📄 s3c2410.c.txt
字号:
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 + -