sm501: Add uart support
PATCH 1/1 sm501: Add uart support
This patch extends the sm501 mfd with 8250 uart support. We're currently doing this in the board specific r2d-1 code already, but it would be nice to do move things into the mfd since it's more chip specific than board specific.
---
drivers/mfd/sm501.c | 86 ++++++++++++++++++++++++++++++++++--------- include/linux/serial_8250.h | 1 2 files changed, 70 insertions(+), 17 deletions(-)
drivers/mfd/sm501.c +69 -17
@@ -22,6 +22,7 @@#include <linux/sm501.h> #include <linux/sm501-regs.h> +#include <linux/serial_8250.h> #include <asm/io.h>
@@ -651,13 +652,14 @@ static void sm501_device_release(struct*/ static struct platform_device * -sm501_create_subdev (struct sm501_devdata *sm, -char *name,unsigned int res_count) +sm501_create_subdev (struct sm501_devdata *sm,char *name, +unsigned int res_count,unsigned int platform_data_size) {struct sm501_device *smdev; smdev =kzalloc (sizeof (struct sm501_device ) + -sizeof (struct resource ) * res_count,GFP_KERNEL ); + (sizeof (struct resource ) * res_count) + + platform_data_size,GFP_KERNEL );if (!smdev)return NULL ;
@@ -665,11 +667,15 @@ sm501_create_subdev(struct sm501_devdata smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; - smdev->pdev.resource = (struct resource *)(smdev+1 ); - smdev->pdev.num_resources = res_count; - smdev->pdev.dev.parent = sm->dev; +if (res_count) { + smdev->pdev.resource = (struct resource *)(smdev+1 ); + smdev->pdev.num_resources = res_count; + } +if (platform_data_size) + smdev->pdev.dev.platform_data = (void *)(smdev+1 ); +return &smdev->pdev; }
@@ -757,7 +763,7 @@ static int sm501_register_usbhost(struct {struct platform_device *pdev; - pdev =sm501_create_subdev (sm,"sm501-usb" ,3 ); + pdev =sm501_create_subdev (sm,"sm501-usb" ,3 ,0 );if (!pdev)return -ENOMEM ;
@@ -768,12 +774,55 @@ static int sm501_register_usbhost(structreturn sm501_register_device (sm, pdev); } +static void sm501_setup_uart_data (struct sm501_devdata *sm, +struct plat_serial8250_port *uart_data, +unsigned int offset) +{ + uart_data->membase = sm->regs + offset; + uart_data->mapbase = sm->io_res->start + offset; + uart_data->iotype =UPIO_MEM ; + uart_data->irq = sm->irq; + uart_data->flags =UPF_BOOT_AUTOCONF |UPF_SKIP_TEST |UPF_SHARE_IRQ ; + uart_data->regshift =2 ; + uart_data->uartclk = (9600 *16 ); +} + +static int sm501_register_uart (struct sm501_devdata *sm,int devices) +{ +struct platform_device *pdev; +struct plat_serial8250_port *uart_data; + + pdev =sm501_create_subdev (sm,"serial8250" ,0 , +sizeof (struct plat_serial8250_port ) *3 ); +if (!pdev) +return -ENOMEM ; + + uart_data = pdev->dev.platform_data; + +if (devices &SM501_USE_UART0 ) { +sm501_setup_uart_data (sm, uart_data++,0x30000 ); +sm501_unit_power (sm->dev,SM501_GATE_UART0 ,1 ); +sm501_modify_reg (sm->dev,SM501_IRQ_MASK ,1 <<12 ,0 ); +sm501_modify_reg (sm->dev,SM501_GPIO63_32_CONTROL ,0x01e0 ,0 ); + } +if (devices &SM501_USE_UART1 ) { +sm501_setup_uart_data (sm, uart_data++,0x30020 ); +sm501_unit_power (sm->dev,SM501_GATE_UART1 ,1 ); +sm501_modify_reg (sm->dev,SM501_IRQ_MASK ,1 <<13 ,0 ); +sm501_modify_reg (sm->dev,SM501_GPIO63_32_CONTROL ,0x1e00 ,0 ); + } + + pdev->id =PLAT8250_DEV_SM501 ; + +return sm501_register_device (sm, pdev); +} +static int sm501_register_display (struct sm501_devdata *sm,resource_size_t *mem_avail) {struct platform_device *pdev; - pdev =sm501_create_subdev (sm,"sm501-fb" ,4 ); + pdev =sm501_create_subdev (sm,"sm501-fb" ,4 ,0 );if (!pdev)return -ENOMEM ;
@@ -891,6 +940,7 @@ static unsigned int sm501_mem_local[] =static int sm501_init_dev (struct sm501_devdata *sm) { +struct sm501_initdata *idata;resource_size_t mem_avail;unsigned long dramctrl;unsigned long devid;
@@ -908,6 +958,9 @@ static int sm501_init_dev(struct sm501_dreturn -EINVAL ; } +/* disable irqs */ +writel (0 , sm->regs +SM501_IRQ_MASK ); + dramctrl =readl (sm->regs +SM501_DRAM_CONTROL ); mem_avail = sm501_mem_local[(dramctrl >>13 ) &0x7 ];
@@ -924,15 +977,14 @@ static int sm501_init_dev(struct sm501_d/* check to see if we have some device initialisation */ -if (sm->platdata) { -struct sm501_platdata *pdata = sm->platdata; - -if (pdata->init) { -sm501_init_regs (sm, sm->platdata->init); - -if (pdata->init->devices &SM501_USE_USB_HOST ) -sm501_register_usbhost (sm, &mem_avail); - } + idata = sm->platdata ? sm->platdata->init :NULL ; +if (idata) { +sm501_init_regs (sm, idata); + +if (idata->devices &SM501_USE_USB_HOST ) +sm501_register_usbhost (sm, &mem_avail); +if (idata->devices & (SM501_USE_UART0 |SM501_USE_UART1 )) +sm501_register_uart (sm, idata->devices); } ret =sm501_check_clocks (sm);
include/linux/serial_8250.h +1 -0
@@ -46,6 +46,7 @@ enum {PLAT8250_DEV_HUB6 ,PLAT8250_DEV_MCA ,PLAT8250_DEV_AU1X00 , + PLAT8250_DEV_SM501, };/*
Quoted 3 lines · Magnus Damm
This patch extends the sm501 mfd with 8250 uart support. We're currently doing this in the board specific r2d-1 code already, but it would be nice to do move things into the mfd since it's more chip specific than board specific.
Looks fine, will add to my set of SM501 changes to keep track of things ready for the next kernel release window.
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/) 'a smiley only costs 4 bytes'
drivers/mfd/sm501.c static void sm501_device_release(struct
Quoted 8 lines · On Fri, 08 Feb 2008 18:57:42 +0900 Magnus Damm <[email protected]> wrote:
drivers/mfd/sm501.c +3
-1smdev =kzalloc (sizeof (struct sm501_device ) + -sizeof (struct resource ) * res_count,GFP_KERNEL ); + (sizeof (struct resource ) * res_count) + + platform_data_size,GFP_KERNEL ); + smdev->pdev.resource = (struct resource *)(smdev+1 );
So this driver plays party tricks with memory allocation and the C type system.
We could at least add
struct resource resources[0];
to the end of struct sm501_device' to avoid the type abuse. Or we could even get radical and splurge four bytes on a struct resource *'. But please, not this.
Oh well. A pre-existing problem.