免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1789 | 回复: 0
打印 上一主题 下一主题

medfield 平台 串口 console 驱动 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-22 08:51 |只看该作者 |倒序浏览
位于 /drivers/serial/mfd.c 中

1. 初始化:

  1. static int __init hsu_pci_init(void)
  2. {
  3.     int ret;

  4.     hsu_global_init();                              //初始化

  5.     ret = uart_register_driver(&serial_hsu_reg);   //注册UART 驱动
  6.     if (ret)
  7.         return ret;

  8.     return pci_register_driver(&hsu_pci_driver);   //注册pci驱动
  9. }

  10. static void __exit hsu_pci_exit(void)
  11. {
  12.     pci_unregister_driver(&hsu_pci_driver);
  13.     uart_unregister_driver(&serial_hsu_reg);

  14.     hsu_debugfs_remove(phsu);

  15.     kfree(phsu);
  16. }

  17. module_init(hsu_pci_init);
  18. module_exit(hsu_pci_exit);

  19. MODULE_LICENSE("GPL v2");
  20. MODULE_ALIAS("platform:medfield-hsu");
 2. hsu_global_init(), 初始化3个UART 串口。

  1. static void hsu_global_init(void)
  2. {
  3.     struct hsu_port *hsu;
  4.     struct uart_hsu_port *uport;
  5.     struct hsu_dma_chan *dchan;
  6.     int i, ret;

  7.     hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
  8.     if (!hsu)
  9.         return;

  10.     /* Get basic io resource and map it */
  11.     hsu->paddr = 0xffa28000;
  12.     hsu->iolen = 0x1000;

  13.     if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
  14.         pr_warning("HSU: error in request mem region\n");

  15.     hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
  16.     if (!hsu->reg) {
  17.         pr_err("HSU: error in ioremap\n");
  18.         ret = -ENOMEM;
  19.         goto err_free_region;
  20.     }

  21.     /* Initialise the 3 UART ports */
  22.     uport = hsu->port;
  23.     for (i = 0; i < 3; i++) {
  24.         uport->port.type = PORT_MFD;
  25.         uport->port.iotype = UPIO_MEM;
  26.         uport->port.mapbase = (resource_size_t)hsu->paddr
  27.                     + HSU_PORT_REG_OFFSET
  28.                     + i * HSU_PORT_REG_LENGTH;
  29.         uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
  30.                     + i * HSU_PORT_REG_LENGTH;

  31.         sprintf(uport->name, "hsu_port%d", i);
  32.         uport->port.fifosize = 64;
  33.         uport->port.ops = &serial_hsu_pops;
  34.         uport->port.line = i;
  35.         uport->port.flags = UPF_IOREMAP;
  36.         /* set the scalable maxim support rate to 2746800 bps */
  37.         uport->port.uartclk = 115200 * 24 * 16;

  38.         uport->running = 0;
  39.         uport->txc = &hsu->chans[i * 2];
  40.         uport->rxc = &hsu->chans[i * 2 + 1];

  41.         serial_hsu_ports[i] = uport;
  42.         uport->index = i;
  43.         uport++;
  44.    }

  45.     /* Initialise 6 dma channels */
  46.     dchan = hsu->chans;
  47.     for (i = 0; i < 6; i++) {
  48.         dchan->id = i;
  49.         dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
  50.         dchan->uport = &hsu->port[i/2];
  51.         dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
  52.                 i * HSU_DMA_CHANS_REG_LENGTH;

  53.         /* Work around for RX */
  54.         if (dmarx_need_timer() && dchan->dirt == DMA_FROM_DEVICE) {
  55.             init_timer(&dchan->rx_timer);
  56.             dchan->rx_timer.function = hsu_dma_rx_timeout;
  57.             dchan->rx_timer.data = (unsigned long)dchan;
  58.         }
  59.         dchan++;
  60.     }

  61.     phsu = hsu;
  62.     hsu_debugfs_init(hsu);
  63.     return;

  64. err_free_region:
  65.     release_mem_region(hsu->paddr, hsu->iolen);
  66.     kfree(hsu);
  67.     return;
  68. }
3.  串口信息配置:

  1. static struct uart_driver serial_hsu_reg = {
  2.     .owner = THIS_MODULE,
  3.     .driver_name = "MFD serial",
  4.     .dev_name = "ttyMFD",
  5.     .major = TTY_MAJOR,
  6.     .minor = 128,
  7.     .nr = 3,
  8. };
4. pci 驱动信息:

  1. static struct pci_driver hsu_pci_driver = {
  2.     .name =        "HSU serial",
  3.     .id_table =    pci_ids,
  4.     .probe =    serial_hsu_probe,
  5.     .remove =    __devexit_p(serial_hsu_remove),
  6.     .suspend =    serial_hsu_suspend,
  7.     .resume    =    serial_hsu_resume,
  8. };
5.  serial_hsu_probe :

  1. static int serial_hsu_probe(struct pci_dev *pdev,
  2.                 const struct pci_device_id *ent)
  3. {
  4.     struct uart_hsu_port *uport;
  5.     int index, ret;

  6.     printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
  7.         pdev->vendor, pdev->device);

  8.     switch (pdev->device) {
  9.     case 0x081B:
  10.         index = 0;
  11.         break;
  12.     case 0x081C:
  13.         index = 1;
  14.         break;
  15.     case 0x081D:
  16.         index = 2;
  17.         break;
  18.     case 0x081E:
  19.         /* internal DMA controller */
  20.         index = 3;
  21.         break;
  22.     default:
  23.         dev_err(&pdev->dev, "HSU: out of index!");
  24.         return -ENODEV;
  25.     }

  26.     ret = pci_enable_device(pdev);
  27.     if (ret)
  28.         return ret;

  29.     if (index == 3) {
  30.         /* DMA controller */
  31.         ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
  32.         if (ret) {
  33.             dev_err(&pdev->dev, "can not get IRQ\n");
  34.             goto err_disable;
  35.         }
  36.         pci_set_drvdata(pdev, phsu);
  37.     } else {
  38.         /* UART port 0~2 */
  39.         uport = &phsu->port[index];
  40.         uport->port.irq = pdev->irq;
  41.         uport->port.dev = &pdev->dev;
  42.         uport->dev = &pdev->dev;

  43.         ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
  44.         if (ret) {
  45.             dev_err(&pdev->dev, "can not get IRQ\n");
  46.             goto err_disable;
  47.         }
  48.         uart_add_one_port(&serial_hsu_reg, &uport->port);

  49. #ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
  50.         if (index == 1) {
  51.             register_console(&serial_hsu_console);
  52.             uport->port.cons = &serial_hsu_console;
  53.         }
  54. #endif
  55.         pci_set_drvdata(pdev, uport);
  56.     }

  57.     return 0;

  58. err_disable:
  59.     pci_disable_device(pdev);
  60.     return ret;
  61. }
serial_hsu_suspend() 和 serial_hsu_resume().
 
  1. #ifdef CONFIG_PM
  2. static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
  3. {
  4.     void *priv = pci_get_drvdata(pdev);
  5.     struct uart_hsu_port *up;

  6.     /* Make sure this is not the internal dma controller */
  7.     if (priv && (pdev->device != 0x081E)) {
  8.         up = priv;
  9.         uart_suspend_port(&serial_hsu_reg, &up->port);
  10.     }

  11.     pci_save_state(pdev);
  12.     pci_set_power_state(pdev, pci_choose_state(pdev, state));
  13.         return 0;
  14. }

  15. static int serial_hsu_resume(struct pci_dev *pdev)
  16. {
  17.     void *priv = pci_get_drvdata(pdev);
  18.     struct uart_hsu_port *up;
  19.     int ret;

  20.     pci_set_power_state(pdev, PCI_D0);
  21.     pci_restore_state(pdev);

  22.     ret = pci_enable_device(pdev);
  23.     if (ret)
  24.         dev_warn(&pdev->dev,
  25.             "HSU: can't re-enable device, try to continue\n");

  26.     if (priv && (pdev->device != 0x081E)) {
  27.         up = priv;
  28.         uart_resume_port(&serial_hsu_reg, &up->port);
  29.     }
  30.     return 0;
  31. }
  32. #else
  33. #define serial_hsu_suspend    NULL
  34. #define serial_hsu_resume    NULL
  35. #endif
6 . serial_hsu_pops, 实现了 serial hsu 的各种串口操作。

  1. struct uart_ops serial_hsu_pops = {
  2.     .tx_empty    = serial_hsu_tx_empty,
  3.     .set_mctrl    = serial_hsu_set_mctrl,
  4.     .get_mctrl    = serial_hsu_get_mctrl,
  5.     .stop_tx    = serial_hsu_stop_tx,
  6.     .start_tx    = serial_hsu_start_tx,
  7.     .stop_rx    = serial_hsu_stop_rx,
  8.     .enable_ms    = serial_hsu_enable_ms,
  9.     .break_ctl    = serial_hsu_break_ctl,
  10.     .startup    = serial_hsu_startup,
  11.     .shutdown    = serial_hsu_shutdown,
  12.     .set_termios    = serial_hsu_set_termios,
  13.     .pm        = serial_hsu_pm,
  14.     .type        = serial_hsu_type,
  15.     .release_port    = serial_hsu_release_port,
  16.     .request_port    = serial_hsu_request_port,
  17.     .config_port    = serial_hsu_config_port,
  18.     .verify_port    = serial_hsu_verify_port,
  19. };
7. serial_hsu_console 结构体, 实现了console功能,注意里面有个 serail_hsu_reg

  1. tatic struct console serial_hsu_console = {
  2.     .name        = "ttyMFD",
  3.     .write        = serial_hsu_console_write,
  4.     .device        = uart_console_device,
  5.     .setup        = serial_hsu_console_setup,
  6.     .flags        = CON_PRINTBUFFER,
  7.     .index        = 1,
  8.     .data        = &serial_hsu_reg,       //串口 hsu 信息数据
  9. };
  10. #endif

  1. static void serial_hsu_console_putchar(struct uart_port *port, int ch)
  2. {
  3.     struct uart_hsu_port *up =
  4.         container_of(port, struct uart_hsu_port, port);

  5.     wait_for_xmitr(up);
  6.     serial_out(up, UART_TX, ch);
  7. }

  8. /*
  9.  * Print a string to the serial port trying not to disturb
  10.  * any possible real use of the port...
  11.  *
  12.  *    The console_lock must be held when we get here.
  13.  */
  14. static void
  15. serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
  16. {
  17.     struct uart_hsu_port *up = serial_hsu_ports[co->index];
  18.     unsigned long flags;
  19.     unsigned int ier;
  20.     int locked = 1;

  21.     local_irq_save(flags);
  22.     if (up->port.sysrq)
  23.         locked = 0;
  24.     else if (oops_in_progress) {
  25.         locked = spin_trylock(&up->port.lock);
  26.     } else
  27.         spin_lock(&up->port.lock);

  28.     /* First save the IER then disable the interrupts */
  29.     ier = serial_in(up, UART_IER);
  30.     serial_out(up, UART_IER, 0);

  31.     uart_console_write(&up->port, s, count, serial_hsu_console_putchar);

  32.     /*
  33.      * Finally, wait for transmitter to become empty
  34.      * and restore the IER
  35.      */
  36.     wait_for_xmitr(up);
  37.     serial_out(up, UART_IER, ier);

  38.     if (locked)
  39.         spin_unlock(&up->port.lock);
  40.     local_irq_restore(flags);
  41. }

  42. static struct console serial_hsu_console;

  43. static int __init
  44. serial_hsu_console_setup(struct console *co, char *options)
  45. {
  46.     struct uart_hsu_port *up;
  47.     int baud = 115200;
  48.     int bits = 8;
  49.     int parity = 'n';
  50.     int flow = 'n';
  51.     int ret;

  52.     if (co->index == -1 || co->index >= serial_hsu_reg.nr)
  53.         co->index = 0;
  54.     up = serial_hsu_ports[co->index];
  55.     if (!up)
  56.         return -ENODEV;

  57.     if (options)
  58.         uart_parse_options(options, &baud, &parity, &bits, &flow);

  59.     ret = uart_set_options(&up->port, co, baud, parity, bits, flow);

  60.     return ret;
  61. }









您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP