⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410.c.txt

📁 本源码是对三星S3C24xx系列的UART的驱动程序.
💻 TXT
📖 第 1 页 / 共 5 页
字号:
1084 static int probe_index = 0;
1085 
1086 static int s3c24xx_serial_probe(struct platform_device *dev,
1087                                 struct s3c24xx_uart_info *info)
1088 {
1089         struct s3c24xx_uart_port *ourport;
1090         int ret;
1091 
1092         dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
1093 
1094         ourport = &s3c24xx_serial_ports[probe_index];
1095         probe_index++;
1096 
1097         dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);
1098 
1099         ret = s3c24xx_serial_init_port(ourport, info, dev);
1100         if (ret < 0)
1101                 goto probe_err;
1102 
1103         dbg("%s: adding port\n", __FUNCTION__);
1104         uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
1105         platform_set_drvdata(dev, &ourport->port);
1106 
1107         return 0;
1108 
1109  probe_err:
1110         return ret;
1111 }
1112 
1113 static int s3c24xx_serial_remove(struct platform_device *dev)
1114 {
1115         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1116 
1117         if (port)
1118                 uart_remove_one_port(&s3c24xx_uart_drv, port);
1119 
1120         return 0;
1121 }
1122 
1123 /* UART power management code */
1124 
1125 #ifdef CONFIG_PM
1126 
1127 static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
1128 {
1129         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1130 
1131         if (port)
1132                 uart_suspend_port(&s3c24xx_uart_drv, port);
1133 
1134         return 0;
1135 }
1136 
1137 static int s3c24xx_serial_resume(struct platform_device *dev)
1138 {
1139         struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1140         struct s3c24xx_uart_port *ourport = to_ourport(port);
1141 
1142         if (port) {
1143                 clk_enable(ourport->clk);
1144                 s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
1145                 clk_disable(ourport->clk);
1146 
1147                 uart_resume_port(&s3c24xx_uart_drv, port);
1148         }
1149 
1150         return 0;
1151 }
1152 
1153 #else
1154 #define s3c24xx_serial_suspend NULL
1155 #define s3c24xx_serial_resume  NULL
1156 #endif
1157 
1158 static int s3c24xx_serial_init(struct platform_driver *drv,
1159                                struct s3c24xx_uart_info *info)
1160 {
1161         dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
1162         return platform_driver_register(drv);
1163 }
1164 
1165 
1166 /* now comes the code to initialise either the s3c2410 or s3c2440 serial
1167  * port information
1168 */
1169 
1170 /* cpu specific variations on the serial port support */
1171 
1172 #ifdef CONFIG_CPU_S3C2400
1173 
1174 static int s3c2400_serial_getsource(struct uart_port *port,
1175                                     struct s3c24xx_uart_clksrc *clk)
1176 {
1177         clk->divisor = 1;
1178         clk->name = "pclk";
1179 
1180         return 0;
1181 }
1182 
1183 static int s3c2400_serial_setsource(struct uart_port *port,
1184                                     struct s3c24xx_uart_clksrc *clk)
1185 {
1186         return 0;
1187 }
1188 
1189 static int s3c2400_serial_resetport(struct uart_port *port,
1190                                     struct s3c2410_uartcfg *cfg)
1191 {
1192         dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n",
1193             port, port->mapbase, cfg);
1194 
1195         wr_regl(port, S3C2410_UCON,  cfg->ucon);
1196         wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1197 
1198         /* reset both fifos */
1199 
1200         wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1201         wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1202 
1203         return 0;
1204 }
1205 
1206 static struct s3c24xx_uart_info s3c2400_uart_inf = {
1207         .name           = "Samsung S3C2400 UART",
1208         .type           = PORT_S3C2400,
1209         .fifosize       = 16,
1210         .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
1211         .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
1212         .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
1213         .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
1214         .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
1215         .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
1216         .get_clksrc     = s3c2400_serial_getsource,
1217         .set_clksrc     = s3c2400_serial_setsource,
1218         .reset_port     = s3c2400_serial_resetport,
1219 };
1220 
1221 static int s3c2400_serial_probe(struct platform_device *dev)
1222 {
1223         return s3c24xx_serial_probe(dev, &s3c2400_uart_inf);
1224 }
1225 
1226 static struct platform_driver s3c2400_serial_drv = {
1227         .probe          = s3c2400_serial_probe,
1228         .remove         = s3c24xx_serial_remove,
1229         .suspend        = s3c24xx_serial_suspend,
1230         .resume         = s3c24xx_serial_resume,
1231         .driver         = {
1232                 .name   = "s3c2400-uart",
1233                 .owner  = THIS_MODULE,
1234         },
1235 };
1236 
1237 static inline int s3c2400_serial_init(void)
1238 {
1239         return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf);
1240 }
1241 
1242 static inline void s3c2400_serial_exit(void)
1243 {
1244         platform_driver_unregister(&s3c2400_serial_drv);
1245 }
1246 
1247 #define s3c2400_uart_inf_at &s3c2400_uart_inf
1248 #else
1249 
1250 static inline int s3c2400_serial_init(void)
1251 {
1252         return 0;
1253 }
1254 
1255 static inline void s3c2400_serial_exit(void)
1256 {
1257 }
1258 
1259 #define s3c2400_uart_inf_at NULL
1260 
1261 #endif /* CONFIG_CPU_S3C2400 */
1262 
1263 /* S3C2410 support */
1264 
1265 #ifdef CONFIG_CPU_S3C2410
1266 
1267 static int s3c2410_serial_setsource(struct uart_port *port,
1268                                     struct s3c24xx_uart_clksrc *clk)
1269 {
1270         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1271 
1272         if (strcmp(clk->name, "uclk") == 0)
1273                 ucon |= S3C2410_UCON_UCLK;
1274         else
1275                 ucon &= ~S3C2410_UCON_UCLK;
1276 
1277         wr_regl(port, S3C2410_UCON, ucon);
1278         return 0;
1279 }
1280 
1281 static int s3c2410_serial_getsource(struct uart_port *port,
1282                                     struct s3c24xx_uart_clksrc *clk)
1283 {
1284         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1285 
1286         clk->divisor = 1;
1287         clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
1288 
1289         return 0;
1290 }
1291 
1292 static int s3c2410_serial_resetport(struct uart_port *port,
1293                                     struct s3c2410_uartcfg *cfg)
1294 {
1295         dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",
1296             port, port->mapbase, cfg);
1297 
1298         wr_regl(port, S3C2410_UCON,  cfg->ucon);
1299         wr_regl(port, S3C2410_ULCON, cfg->ulcon);
1300 
1301         /* reset both fifos */
1302 
1303         wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
1304         wr_regl(port, S3C2410_UFCON, cfg->ufcon);
1305 
1306         return 0;
1307 }
1308 
1309 static struct s3c24xx_uart_info s3c2410_uart_inf = {
1310         .name           = "Samsung S3C2410 UART",
1311         .type           = PORT_S3C2410,
1312         .fifosize       = 16,
1313         .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
1314         .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
1315         .rx_fifofull    = S3C2410_UFSTAT_RXFULL,
1316         .tx_fifofull    = S3C2410_UFSTAT_TXFULL,
1317         .tx_fifomask    = S3C2410_UFSTAT_TXMASK,
1318         .tx_fifoshift   = S3C2410_UFSTAT_TXSHIFT,
1319         .get_clksrc     = s3c2410_serial_getsource,
1320         .set_clksrc     = s3c2410_serial_setsource,
1321         .reset_port     = s3c2410_serial_resetport,
1322 };
1323 
1324 /* device management */
1325 
1326 static int s3c2410_serial_probe(struct platform_device *dev)
1327 {
1328         return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
1329 }
1330 
1331 static struct platform_driver s3c2410_serial_drv = {
1332         .probe          = s3c2410_serial_probe,
1333         .remove         = s3c24xx_serial_remove,
1334         .suspend        = s3c24xx_serial_suspend,
1335         .resume         = s3c24xx_serial_resume,
1336         .driver         = {
1337                 .name   = "s3c2410-uart",
1338                 .owner  = THIS_MODULE,
1339         },
1340 };
1341 
1342 static inline int s3c2410_serial_init(void)
1343 {
1344         return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
1345 }
1346 
1347 static inline void s3c2410_serial_exit(void)
1348 {
1349         platform_driver_unregister(&s3c2410_serial_drv);
1350 }
1351 
1352 #define s3c2410_uart_inf_at &s3c2410_uart_inf
1353 #else
1354 
1355 static inline int s3c2410_serial_init(void)
1356 {
1357         return 0;
1358 }
1359 
1360 static inline void s3c2410_serial_exit(void)
1361 {
1362 }
1363 
1364 #define s3c2410_uart_inf_at NULL
1365 
1366 #endif /* CONFIG_CPU_S3C2410 */
1367 
1368 #ifdef CONFIG_CPU_S3C2440
1369 
1370 static int s3c2440_serial_setsource(struct uart_port *port,
1371                                      struct s3c24xx_uart_clksrc *clk)
1372 {
1373         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1374 
1375         // todo - proper fclk<>nonfclk switch //
1376 
1377         ucon &= ~S3C2440_UCON_CLKMASK;
1378 
1379         if (strcmp(clk->name, "uclk") == 0)
1380                 ucon |= S3C2440_UCON_UCLK;
1381         else if (strcmp(clk->name, "pclk") == 0)
1382                 ucon |= S3C2440_UCON_PCLK;
1383         else if (strcmp(clk->name, "fclk") == 0)
1384                 ucon |= S3C2440_UCON_FCLK;
1385         else {
1386                 printk(KERN_ERR "unknown clock source %s\n", clk->name);
1387                 return -EINVAL;
1388         }
1389 
1390         wr_regl(port, S3C2410_UCON, ucon);
1391         return 0;
1392 }
1393 
1394 
1395 static int s3c2440_serial_getsource(struct uart_port *port,
1396                                     struct s3c24xx_uart_clksrc *clk)
1397 {
1398         unsigned long ucon = rd_regl(port, S3C2410_UCON);
1399         unsigned long ucon0, ucon1, ucon2;
1400 
1401         switch (ucon & S3C2440_UCON_CLKMASK) {
1402         case S3C2440_UCON_UCLK:
1403                 clk->divisor = 1;
1404                 clk->name = "uclk";
1405                 break;
1406 
1407         case S3C2440_UCON_PCLK:
1408         case S3C2440_UCON_PCLK2:
1409                 clk->divisor = 1;
1410                 clk->name = "pclk";
1411                 break;
1412 
1413         case S3C2440_UCON_FCLK:
1414                 /* the fun of calculating the uart divisors on
1415                  * the s3c2440 */
1416 
1417                 ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
1418                 ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
1419                 ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
1420 
1421                 printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
1422 
1423                 ucon0 &= S3C2440_UCON0_DIVMASK;
1424                 ucon1 &= S3C2440_UCON1_DIVMASK;
1425                 ucon2 &= S3C2440_UCON2_DIVMASK;
1426 
1427                 if (ucon0 != 0) {
1428                         clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
1429                         clk->divisor += 6;
1430                 } else if (ucon1 != 0) {
1431                         clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
1432                         clk->divisor += 21;
1433                 } else if (ucon2 != 0) {
1434                         clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
1435                         clk->divisor += 36;
1436                 } else {
1437                         /* manual calims 44, seems to be 9 */
1438                         clk->divisor = 9;
1439                 }
1440 
1441                 clk->name = "fclk";
1442                 break;
1443         }
1444 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -