Skip to content

Commit

Permalink
sm501: add uart support
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Magnus Damm authored and Linus Torvalds committed Apr 28, 2008
1 parent 5d9f3f6 commit 61711f8
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 16 deletions.
84 changes: 68 additions & 16 deletions drivers/mfd/sm501.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <linux/sm501.h>
#include <linux/sm501-regs.h>
#include <linux/serial_8250.h>

#include <asm/io.h>

Expand Down Expand Up @@ -723,25 +724,30 @@ static void sm501_device_release(struct device *dev)
*/

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;

smdev->pdev.dev.release = sm501_device_release;

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;
}

Expand Down Expand Up @@ -829,7 +835,7 @@ static int sm501_register_usbhost(struct sm501_devdata *sm,
{
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;

Expand All @@ -840,12 +846,55 @@ static int sm501_register_usbhost(struct sm501_devdata *sm,
return 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;

Expand Down Expand Up @@ -963,6 +1012,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;
Expand All @@ -980,6 +1030,9 @@ static int sm501_init_dev(struct sm501_devdata *sm)
return -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];

Expand All @@ -998,15 +1051,14 @@ static int sm501_init_dev(struct sm501_devdata *sm)

/* check to see if we have some device initialisation */

if (sm->platdata) {
struct sm501_platdata *pdata = sm->platdata;
idata = sm->platdata ? sm->platdata->init : NULL;
if (idata) {
sm501_init_regs(sm, idata);

if (pdata->init) {
sm501_init_regs(sm, sm->platdata->init);

if (pdata->init->devices & SM501_USE_USB_HOST)
sm501_register_usbhost(sm, &mem_avail);
}
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);
Expand Down
1 change: 1 addition & 0 deletions include/linux/serial_8250.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ enum {
PLAT8250_DEV_HUB6,
PLAT8250_DEV_MCA,
PLAT8250_DEV_AU1X00,
PLAT8250_DEV_SM501,
};

/*
Expand Down

0 comments on commit 61711f8

Please sign in to comment.