diff options
author | Magnus Damm <magnus.damm@gmail.com> | 2008-04-28 05:14:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:32 -0400 |
commit | 61711f8fd8180e458cfb6846bcf4fc636a95f3db (patch) | |
tree | d5c0a40de101622accdacfdbb18a183239596ca7 /drivers/mfd | |
parent | 5d9f3f6b7c4c9fe1706006f24f964e7c0fa49fb7 (diff) |
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.
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>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/sm501.c | 84 |
1 files changed, 68 insertions, 16 deletions
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 13bac53db69a..6e655b4c6682 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/sm501.h> | 23 | #include <linux/sm501.h> |
24 | #include <linux/sm501-regs.h> | 24 | #include <linux/sm501-regs.h> |
25 | #include <linux/serial_8250.h> | ||
25 | 26 | ||
26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
27 | 28 | ||
@@ -723,13 +724,14 @@ static void sm501_device_release(struct device *dev) | |||
723 | */ | 724 | */ |
724 | 725 | ||
725 | static struct platform_device * | 726 | static struct platform_device * |
726 | sm501_create_subdev(struct sm501_devdata *sm, | 727 | sm501_create_subdev(struct sm501_devdata *sm, char *name, |
727 | char *name, unsigned int res_count) | 728 | unsigned int res_count, unsigned int platform_data_size) |
728 | { | 729 | { |
729 | struct sm501_device *smdev; | 730 | struct sm501_device *smdev; |
730 | 731 | ||
731 | smdev = kzalloc(sizeof(struct sm501_device) + | 732 | smdev = kzalloc(sizeof(struct sm501_device) + |
732 | sizeof(struct resource) * res_count, GFP_KERNEL); | 733 | (sizeof(struct resource) * res_count) + |
734 | platform_data_size, GFP_KERNEL); | ||
733 | if (!smdev) | 735 | if (!smdev) |
734 | return NULL; | 736 | return NULL; |
735 | 737 | ||
@@ -737,11 +739,15 @@ sm501_create_subdev(struct sm501_devdata *sm, | |||
737 | 739 | ||
738 | smdev->pdev.name = name; | 740 | smdev->pdev.name = name; |
739 | smdev->pdev.id = sm->pdev_id; | 741 | smdev->pdev.id = sm->pdev_id; |
740 | smdev->pdev.resource = (struct resource *)(smdev+1); | ||
741 | smdev->pdev.num_resources = res_count; | ||
742 | |||
743 | smdev->pdev.dev.parent = sm->dev; | 742 | smdev->pdev.dev.parent = sm->dev; |
744 | 743 | ||
744 | if (res_count) { | ||
745 | smdev->pdev.resource = (struct resource *)(smdev+1); | ||
746 | smdev->pdev.num_resources = res_count; | ||
747 | } | ||
748 | if (platform_data_size) | ||
749 | smdev->pdev.dev.platform_data = (void *)(smdev+1); | ||
750 | |||
745 | return &smdev->pdev; | 751 | return &smdev->pdev; |
746 | } | 752 | } |
747 | 753 | ||
@@ -829,7 +835,7 @@ static int sm501_register_usbhost(struct sm501_devdata *sm, | |||
829 | { | 835 | { |
830 | struct platform_device *pdev; | 836 | struct platform_device *pdev; |
831 | 837 | ||
832 | pdev = sm501_create_subdev(sm, "sm501-usb", 3); | 838 | pdev = sm501_create_subdev(sm, "sm501-usb", 3, 0); |
833 | if (!pdev) | 839 | if (!pdev) |
834 | return -ENOMEM; | 840 | return -ENOMEM; |
835 | 841 | ||
@@ -840,12 +846,55 @@ static int sm501_register_usbhost(struct sm501_devdata *sm, | |||
840 | return sm501_register_device(sm, pdev); | 846 | return sm501_register_device(sm, pdev); |
841 | } | 847 | } |
842 | 848 | ||
849 | static void sm501_setup_uart_data(struct sm501_devdata *sm, | ||
850 | struct plat_serial8250_port *uart_data, | ||
851 | unsigned int offset) | ||
852 | { | ||
853 | uart_data->membase = sm->regs + offset; | ||
854 | uart_data->mapbase = sm->io_res->start + offset; | ||
855 | uart_data->iotype = UPIO_MEM; | ||
856 | uart_data->irq = sm->irq; | ||
857 | uart_data->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; | ||
858 | uart_data->regshift = 2; | ||
859 | uart_data->uartclk = (9600 * 16); | ||
860 | } | ||
861 | |||
862 | static int sm501_register_uart(struct sm501_devdata *sm, int devices) | ||
863 | { | ||
864 | struct platform_device *pdev; | ||
865 | struct plat_serial8250_port *uart_data; | ||
866 | |||
867 | pdev = sm501_create_subdev(sm, "serial8250", 0, | ||
868 | sizeof(struct plat_serial8250_port) * 3); | ||
869 | if (!pdev) | ||
870 | return -ENOMEM; | ||
871 | |||
872 | uart_data = pdev->dev.platform_data; | ||
873 | |||
874 | if (devices & SM501_USE_UART0) { | ||
875 | sm501_setup_uart_data(sm, uart_data++, 0x30000); | ||
876 | sm501_unit_power(sm->dev, SM501_GATE_UART0, 1); | ||
877 | sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 12, 0); | ||
878 | sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x01e0, 0); | ||
879 | } | ||
880 | if (devices & SM501_USE_UART1) { | ||
881 | sm501_setup_uart_data(sm, uart_data++, 0x30020); | ||
882 | sm501_unit_power(sm->dev, SM501_GATE_UART1, 1); | ||
883 | sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 13, 0); | ||
884 | sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x1e00, 0); | ||
885 | } | ||
886 | |||
887 | pdev->id = PLAT8250_DEV_SM501; | ||
888 | |||
889 | return sm501_register_device(sm, pdev); | ||
890 | } | ||
891 | |||
843 | static int sm501_register_display(struct sm501_devdata *sm, | 892 | static int sm501_register_display(struct sm501_devdata *sm, |
844 | resource_size_t *mem_avail) | 893 | resource_size_t *mem_avail) |
845 | { | 894 | { |
846 | struct platform_device *pdev; | 895 | struct platform_device *pdev; |
847 | 896 | ||
848 | pdev = sm501_create_subdev(sm, "sm501-fb", 4); | 897 | pdev = sm501_create_subdev(sm, "sm501-fb", 4, 0); |
849 | if (!pdev) | 898 | if (!pdev) |
850 | return -ENOMEM; | 899 | return -ENOMEM; |
851 | 900 | ||
@@ -963,6 +1012,7 @@ static unsigned int sm501_mem_local[] = { | |||
963 | 1012 | ||
964 | static int sm501_init_dev(struct sm501_devdata *sm) | 1013 | static int sm501_init_dev(struct sm501_devdata *sm) |
965 | { | 1014 | { |
1015 | struct sm501_initdata *idata; | ||
966 | resource_size_t mem_avail; | 1016 | resource_size_t mem_avail; |
967 | unsigned long dramctrl; | 1017 | unsigned long dramctrl; |
968 | unsigned long devid; | 1018 | unsigned long devid; |
@@ -980,6 +1030,9 @@ static int sm501_init_dev(struct sm501_devdata *sm) | |||
980 | return -EINVAL; | 1030 | return -EINVAL; |
981 | } | 1031 | } |
982 | 1032 | ||
1033 | /* disable irqs */ | ||
1034 | writel(0, sm->regs + SM501_IRQ_MASK); | ||
1035 | |||
983 | dramctrl = readl(sm->regs + SM501_DRAM_CONTROL); | 1036 | dramctrl = readl(sm->regs + SM501_DRAM_CONTROL); |
984 | mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; | 1037 | mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; |
985 | 1038 | ||
@@ -998,15 +1051,14 @@ static int sm501_init_dev(struct sm501_devdata *sm) | |||
998 | 1051 | ||
999 | /* check to see if we have some device initialisation */ | 1052 | /* check to see if we have some device initialisation */ |
1000 | 1053 | ||
1001 | if (sm->platdata) { | 1054 | idata = sm->platdata ? sm->platdata->init : NULL; |
1002 | struct sm501_platdata *pdata = sm->platdata; | 1055 | if (idata) { |
1056 | sm501_init_regs(sm, idata); | ||
1003 | 1057 | ||
1004 | if (pdata->init) { | 1058 | if (idata->devices & SM501_USE_USB_HOST) |
1005 | sm501_init_regs(sm, sm->platdata->init); | 1059 | sm501_register_usbhost(sm, &mem_avail); |
1006 | 1060 | if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1)) | |
1007 | if (pdata->init->devices & SM501_USE_USB_HOST) | 1061 | sm501_register_uart(sm, idata->devices); |
1008 | sm501_register_usbhost(sm, &mem_avail); | ||
1009 | } | ||
1010 | } | 1062 | } |
1011 | 1063 | ||
1012 | ret = sm501_check_clocks(sm); | 1064 | ret = sm501_check_clocks(sm); |