- 论坛徽章:
- 0
|
位于 /drivers/serial/mfd.c 中
1. 初始化:
- static int __init hsu_pci_init(void)
-
{
-
int ret;
-
-
hsu_global_init(); //初始化
-
-
ret = uart_register_driver(&serial_hsu_reg); //注册UART 驱动
-
if (ret)
-
return ret;
-
-
return pci_register_driver(&hsu_pci_driver); //注册pci驱动
-
}
-
-
static void __exit hsu_pci_exit(void)
-
{
-
pci_unregister_driver(&hsu_pci_driver);
-
uart_unregister_driver(&serial_hsu_reg);
-
-
hsu_debugfs_remove(phsu);
-
-
kfree(phsu);
-
}
-
-
module_init(hsu_pci_init);
-
module_exit(hsu_pci_exit);
-
-
MODULE_LICENSE("GPL v2");
-
MODULE_ALIAS("platform:medfield-hsu");
2. hsu_global_init(), 初始化3个UART 串口。
- static void hsu_global_init(void)
-
{
-
struct hsu_port *hsu;
-
struct uart_hsu_port *uport;
-
struct hsu_dma_chan *dchan;
-
int i, ret;
-
-
hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
-
if (!hsu)
-
return;
-
-
/* Get basic io resource and map it */
-
hsu->paddr = 0xffa28000;
-
hsu->iolen = 0x1000;
-
-
if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
-
pr_warning("HSU: error in request mem region\n");
-
-
hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
-
if (!hsu->reg) {
-
pr_err("HSU: error in ioremap\n");
-
ret = -ENOMEM;
-
goto err_free_region;
-
}
-
-
/* Initialise the 3 UART ports */
-
uport = hsu->port;
-
for (i = 0; i < 3; i++) {
-
uport->port.type = PORT_MFD;
-
uport->port.iotype = UPIO_MEM;
-
uport->port.mapbase = (resource_size_t)hsu->paddr
-
+ HSU_PORT_REG_OFFSET
-
+ i * HSU_PORT_REG_LENGTH;
-
uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
-
+ i * HSU_PORT_REG_LENGTH;
-
-
sprintf(uport->name, "hsu_port%d", i);
-
uport->port.fifosize = 64;
-
uport->port.ops = &serial_hsu_pops;
-
uport->port.line = i;
-
uport->port.flags = UPF_IOREMAP;
-
/* set the scalable maxim support rate to 2746800 bps */
-
uport->port.uartclk = 115200 * 24 * 16;
-
-
uport->running = 0;
-
uport->txc = &hsu->chans[i * 2];
-
uport->rxc = &hsu->chans[i * 2 + 1];
-
-
serial_hsu_ports[i] = uport;
-
uport->index = i;
-
uport++;
-
}
-
-
/* Initialise 6 dma channels */
-
dchan = hsu->chans;
-
for (i = 0; i < 6; i++) {
-
dchan->id = i;
-
dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
dchan->uport = &hsu->port[i/2];
-
dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
-
i * HSU_DMA_CHANS_REG_LENGTH;
-
-
/* Work around for RX */
-
if (dmarx_need_timer() && dchan->dirt == DMA_FROM_DEVICE) {
-
init_timer(&dchan->rx_timer);
-
dchan->rx_timer.function = hsu_dma_rx_timeout;
-
dchan->rx_timer.data = (unsigned long)dchan;
-
}
-
dchan++;
-
}
-
-
phsu = hsu;
-
hsu_debugfs_init(hsu);
-
return;
-
-
err_free_region:
-
release_mem_region(hsu->paddr, hsu->iolen);
-
kfree(hsu);
-
return;
-
}
3. 串口信息配置:
- static struct uart_driver serial_hsu_reg = {
-
.owner = THIS_MODULE,
-
.driver_name = "MFD serial",
-
.dev_name = "ttyMFD",
-
.major = TTY_MAJOR,
-
.minor = 128,
-
.nr = 3,
-
};
4. pci 驱动信息:
- static struct pci_driver hsu_pci_driver = {
-
.name = "HSU serial",
-
.id_table = pci_ids,
-
.probe = serial_hsu_probe,
-
.remove = __devexit_p(serial_hsu_remove),
-
.suspend = serial_hsu_suspend,
-
.resume = serial_hsu_resume,
-
};
5. serial_hsu_probe :
- static int serial_hsu_probe(struct pci_dev *pdev,
-
const struct pci_device_id *ent)
-
{
-
struct uart_hsu_port *uport;
-
int index, ret;
-
-
printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
-
pdev->vendor, pdev->device);
-
-
switch (pdev->device) {
-
case 0x081B:
-
index = 0;
-
break;
-
case 0x081C:
-
index = 1;
-
break;
-
case 0x081D:
-
index = 2;
-
break;
-
case 0x081E:
-
/* internal DMA controller */
-
index = 3;
-
break;
-
default:
-
dev_err(&pdev->dev, "HSU: out of index!");
-
return -ENODEV;
-
}
-
-
ret = pci_enable_device(pdev);
-
if (ret)
-
return ret;
-
-
if (index == 3) {
-
/* DMA controller */
-
ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
-
if (ret) {
-
dev_err(&pdev->dev, "can not get IRQ\n");
-
goto err_disable;
-
}
-
pci_set_drvdata(pdev, phsu);
-
} else {
-
/* UART port 0~2 */
-
uport = &phsu->port[index];
-
uport->port.irq = pdev->irq;
-
uport->port.dev = &pdev->dev;
-
uport->dev = &pdev->dev;
-
-
ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
-
if (ret) {
-
dev_err(&pdev->dev, "can not get IRQ\n");
-
goto err_disable;
-
}
-
uart_add_one_port(&serial_hsu_reg, &uport->port);
-
-
#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-
if (index == 1) {
-
register_console(&serial_hsu_console);
-
uport->port.cons = &serial_hsu_console;
-
}
-
#endif
-
pci_set_drvdata(pdev, uport);
-
}
-
-
return 0;
-
-
err_disable:
-
pci_disable_device(pdev);
-
return ret;
-
}
serial_hsu_suspend() 和 serial_hsu_resume().
- #ifdef CONFIG_PM
-
static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
-
{
-
void *priv = pci_get_drvdata(pdev);
-
struct uart_hsu_port *up;
-
-
/* Make sure this is not the internal dma controller */
-
if (priv && (pdev->device != 0x081E)) {
-
up = priv;
-
uart_suspend_port(&serial_hsu_reg, &up->port);
-
}
-
-
pci_save_state(pdev);
-
pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
return 0;
-
}
-
-
static int serial_hsu_resume(struct pci_dev *pdev)
-
{
-
void *priv = pci_get_drvdata(pdev);
-
struct uart_hsu_port *up;
-
int ret;
-
-
pci_set_power_state(pdev, PCI_D0);
-
pci_restore_state(pdev);
-
-
ret = pci_enable_device(pdev);
-
if (ret)
-
dev_warn(&pdev->dev,
-
"HSU: can't re-enable device, try to continue\n");
-
-
if (priv && (pdev->device != 0x081E)) {
-
up = priv;
-
uart_resume_port(&serial_hsu_reg, &up->port);
-
}
-
return 0;
-
}
-
#else
-
#define serial_hsu_suspend NULL
-
#define serial_hsu_resume NULL
-
#endif
6 . serial_hsu_pops, 实现了 serial hsu 的各种串口操作。
- struct uart_ops serial_hsu_pops = {
-
.tx_empty = serial_hsu_tx_empty,
-
.set_mctrl = serial_hsu_set_mctrl,
-
.get_mctrl = serial_hsu_get_mctrl,
-
.stop_tx = serial_hsu_stop_tx,
-
.start_tx = serial_hsu_start_tx,
-
.stop_rx = serial_hsu_stop_rx,
-
.enable_ms = serial_hsu_enable_ms,
-
.break_ctl = serial_hsu_break_ctl,
-
.startup = serial_hsu_startup,
-
.shutdown = serial_hsu_shutdown,
-
.set_termios = serial_hsu_set_termios,
-
.pm = serial_hsu_pm,
-
.type = serial_hsu_type,
-
.release_port = serial_hsu_release_port,
-
.request_port = serial_hsu_request_port,
-
.config_port = serial_hsu_config_port,
-
.verify_port = serial_hsu_verify_port,
-
};
7. serial_hsu_console 结构体, 实现了console功能,注意里面有个 serail_hsu_reg
- tatic struct console serial_hsu_console = {
-
.name = "ttyMFD",
-
.write = serial_hsu_console_write,
-
.device = uart_console_device,
-
.setup = serial_hsu_console_setup,
-
.flags = CON_PRINTBUFFER,
-
.index = 1,
-
.data = &serial_hsu_reg, //串口 hsu 信息数据
-
};
-
#endif
- static void serial_hsu_console_putchar(struct uart_port *port, int ch)
-
{
-
struct uart_hsu_port *up =
-
container_of(port, struct uart_hsu_port, port);
-
-
wait_for_xmitr(up);
-
serial_out(up, UART_TX, ch);
-
}
-
-
/*
-
* Print a string to the serial port trying not to disturb
-
* any possible real use of the port...
-
*
-
* The console_lock must be held when we get here.
-
*/
-
static void
-
serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
-
{
-
struct uart_hsu_port *up = serial_hsu_ports[co->index];
-
unsigned long flags;
-
unsigned int ier;
-
int locked = 1;
-
-
local_irq_save(flags);
-
if (up->port.sysrq)
-
locked = 0;
-
else if (oops_in_progress) {
-
locked = spin_trylock(&up->port.lock);
-
} else
-
spin_lock(&up->port.lock);
-
-
/* First save the IER then disable the interrupts */
-
ier = serial_in(up, UART_IER);
-
serial_out(up, UART_IER, 0);
-
-
uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
-
-
/*
-
* Finally, wait for transmitter to become empty
-
* and restore the IER
-
*/
-
wait_for_xmitr(up);
-
serial_out(up, UART_IER, ier);
-
-
if (locked)
-
spin_unlock(&up->port.lock);
-
local_irq_restore(flags);
-
}
-
-
static struct console serial_hsu_console;
-
-
static int __init
-
serial_hsu_console_setup(struct console *co, char *options)
-
{
-
struct uart_hsu_port *up;
-
int baud = 115200;
-
int bits = 8;
-
int parity = 'n';
-
int flow = 'n';
-
int ret;
-
-
if (co->index == -1 || co->index >= serial_hsu_reg.nr)
-
co->index = 0;
-
up = serial_hsu_ports[co->index];
-
if (!up)
-
return -ENODEV;
-
-
if (options)
-
uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-
ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
-
-
return ret;
-
}
|
|