diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-03-25 23:56:30 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-03-25 23:57:10 +0100 |
commit | 7256ecc2b7b91b4212ccc5511cb12254bdf806d0 (patch) | |
tree | 1a39b3de03cfc92c5b5dedfb01174d17b49df18a | |
parent | 18bbff9f679cd470db66402fdb9c577b34324183 (diff) | |
parent | 6ed3e2acc7995625625592abe8cd3383c34a471b (diff) |
Merge branch 'sa11x0-mcp' into sa11x0
Conflicts:
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/shannon.c
-rw-r--r-- | arch/arm/mach-sa1100/assabet.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/cerf.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/collie.c | 11 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/generic.c | 13 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/generic.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/include/mach/mcp.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/lart.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/shannon.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/simpad.c | 8 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 5 | ||||
-rw-r--r-- | drivers/mfd/mcp-core.c | 49 | ||||
-rw-r--r-- | drivers/mfd/mcp-sa11x0.c | 198 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-assabet.c | 46 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-core.c | 433 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-ts.c | 39 | ||||
-rw-r--r-- | include/linux/mfd/mcp.h | 14 | ||||
-rw-r--r-- | include/linux/mfd/ucb1x00.h | 38 |
17 files changed, 518 insertions, 357 deletions
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index c3f5064df4b..e708a93a7dd 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -15,6 +15,7 @@ #include <linux/errno.h> #include <linux/ioport.h> #include <linux/serial_core.h> +#include <linux/mfd/ucb1x00.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/delay.h> @@ -71,6 +72,12 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val) EXPORT_SYMBOL(ASSABET_BCR_frob); +static void assabet_ucb1x00_reset(enum ucb1x00_reset state) +{ + if (state == UCB_RST_PROBE) + ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); +} + /* * Assabet flash support code. @@ -167,9 +174,15 @@ static struct irda_platform_data assabet_irda_data = { .set_speed = assabet_irda_set_speed, }; +static struct ucb1x00_plat_data assabet_ucb1x00_data = { + .reset = assabet_ucb1x00_reset, + .gpio_base = -1, +}; + static struct mcp_plat_data assabet_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, + .codec_pdata = &assabet_ucb1x00_data, }; static void assabet_lcd_set_visual(u32 visual) @@ -309,6 +322,8 @@ static void __init assabet_init(void) PPDR |= PPC_TXD3 | PPC_TXD1; PPSR |= PPC_TXD3 | PPC_TXD1; + sa11x0_ppc_configure_mcp(); + if (machine_has_neponset()) { /* * Angel sets this, but other bootloaders may not. diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index c2f9ba3a957..8015604cfc2 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -121,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = { static void __init cerf_init(void) { + sa11x0_ppc_configure_mcp(); platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1); sa11x0_register_mcp(&cerf_mcp_data); diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 841041e1181..d4339d63947 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -22,6 +22,7 @@ #include <linux/tty.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/mfd/ucb1x00.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/timer.h> @@ -83,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = { .num_devs = 1, }; +static struct ucb1x00_plat_data collie_ucb1x00_data = { + .gpio_base = COLLIE_TC35143_GPIO_BASE, +}; + static struct mcp_plat_data collie_mcp_data = { .mccr0 = MCCR0_ADM | MCCR0_ExtClk, .sclk_rate = 9216000, - .gpio_base = COLLIE_TC35143_GPIO_BASE, + .codec_pdata = &collie_ucb1x00_data, }; /* @@ -341,6 +346,10 @@ static void __init collie_init(void) collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN); collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN); + + sa11x0_ppc_configure_mcp(); + + platform_scoop_config = &collie_pcmcia_config; ret = platform_add_devices(devices, ARRAY_SIZE(devices)); diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 0296d69622a..97e9bdf7f29 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -195,7 +195,8 @@ static struct platform_device sa11x0uart3_device = { static struct resource sa11x0mcp_resources[] = { [0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K), - [1] = DEFINE_RES_IRQ(IRQ_Ser4MCP), + [1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4), + [2] = DEFINE_RES_IRQ(IRQ_Ser4MCP), }; static u64 sa11x0mcp_dma_mask = 0xffffffffUL; @@ -211,6 +212,16 @@ static struct platform_device sa11x0mcp_device = { .resource = sa11x0mcp_resources, }; +void __init sa11x0_ppc_configure_mcp(void) +{ + /* Setup the PPC unit for the MCP */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); +} + void sa11x0_register_mcp(struct mcp_plat_data *data) { sa11x0_register_device(&sa11x0mcp_device, data); diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 5c68be858e0..9eb3b3cd5a6 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -36,6 +36,7 @@ struct irda_platform_data; void sa11x0_register_irda(struct irda_platform_data *irda); struct mcp_plat_data; +void sa11x0_ppc_configure_mcp(void); void sa11x0_register_mcp(struct mcp_plat_data *data); struct sa1100fb_mach_info; diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h index ed1a331508a..4b2860ae382 100644 --- a/arch/arm/mach-sa1100/include/mach/mcp.h +++ b/arch/arm/mach-sa1100/include/mach/mcp.h @@ -16,7 +16,7 @@ struct mcp_plat_data { u32 mccr0; u32 mccr1; unsigned int sclk_rate; - int gpio_base; + void *codec_pdata; }; #endif diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index 463a322a425..570f75fb73a 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -107,6 +107,7 @@ static void __init lart_init(void) if (inf) sa11x0_register_lcd(inf); + sa11x0_ppc_configure_mcp(); sa11x0_register_mcp(&lart_mcp_data); } diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 77b2b9b522a..08bb1228961 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -72,6 +72,7 @@ static struct sa1100fb_mach_info shannon_lcd_info = { static void __init shannon_init(void) { + sa11x0_ppc_configure_mcp(); sa11x0_register_lcd(&shannon_lcd_info); sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1); sa11x0_register_mcp(&shannon_mcp_data); diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index cdb9d197c09..3da4c1f11cf 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -10,6 +10,7 @@ #include <linux/string.h> #include <linux/pm.h> #include <linux/platform_device.h> +#include <linux/mfd/ucb1x00.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/io.h> @@ -180,10 +181,14 @@ static struct resource simpad_flash_resources [] = { DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M), }; +static struct ucb1x00_plat_data simpad_ucb1x00_data = { + .gpio_base = SIMPAD_UCB1X00_GPIO_BASE, +}; + static struct mcp_plat_data simpad_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, - .gpio_base = SIMPAD_UCB1X00_GPIO_BASE, + .codec_pdata = &simpad_ucb1x00_data, }; @@ -369,6 +374,7 @@ static int __init simpad_init(void) pm_power_off = simpad_power_off; + sa11x0_ppc_configure_mcp(); sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources, ARRAY_SIZE(simpad_flash_resources)); sa11x0_register_mcp(&simpad_mcp_data); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index cd13e9f2f5e..28a301b2857 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -847,8 +847,9 @@ config MCP_SA11X0 # Chip drivers config MCP_UCB1200 - tristate "Support for UCB1200 / UCB1300" - depends on MCP + bool "Support for UCB1200 / UCB1300" + depends on MCP_SA11X0 + select MCP config MCP_UCB1200_TS tristate "Touchscreen interface support" diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 86cc3f7841c..6acf2e03f2b 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -19,7 +19,6 @@ #include <linux/string.h> #include <linux/mfd/mcp.h> -#include <mach/dma.h> #include <asm/system.h> @@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev) return 0; } -static int mcp_bus_suspend(struct device *dev, pm_message_t state) -{ - struct mcp *mcp = to_mcp(dev); - int ret = 0; - - if (dev->driver) { - struct mcp_driver *drv = to_mcp_driver(dev->driver); - - ret = drv->suspend(mcp, state); - } - return ret; -} - -static int mcp_bus_resume(struct device *dev) -{ - struct mcp *mcp = to_mcp(dev); - int ret = 0; - - if (dev->driver) { - struct mcp_driver *drv = to_mcp_driver(dev->driver); - - ret = drv->resume(mcp); - } - return ret; -} - static struct bus_type mcp_bus_type = { .name = "mcp", .match = mcp_bus_match, .probe = mcp_bus_probe, .remove = mcp_bus_remove, - .suspend = mcp_bus_suspend, - .resume = mcp_bus_resume, }; /** @@ -208,6 +179,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL); if (mcp) { spin_lock_init(&mcp->lock); + device_initialize(&mcp->attached_device); mcp->attached_device.parent = parent; mcp->attached_device.bus = &mcp_bus_type; mcp->attached_device.dma_mask = parent->dma_mask; @@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) } EXPORT_SYMBOL(mcp_host_alloc); -int mcp_host_register(struct mcp *mcp) +int mcp_host_add(struct mcp *mcp, void *pdata) { + mcp->attached_device.platform_data = pdata; dev_set_name(&mcp->attached_device, "mcp0"); - return device_register(&mcp->attached_device); + return device_add(&mcp->attached_device); +} +EXPORT_SYMBOL(mcp_host_add); + +void mcp_host_del(struct mcp *mcp) +{ + device_del(&mcp->attached_device); } -EXPORT_SYMBOL(mcp_host_register); +EXPORT_SYMBOL(mcp_host_del); -void mcp_host_unregister(struct mcp *mcp) +void mcp_host_free(struct mcp *mcp) { - device_unregister(&mcp->attached_device); + put_device(&mcp->attached_device); } -EXPORT_SYMBOL(mcp_host_unregister); +EXPORT_SYMBOL(mcp_host_free); int mcp_driver_register(struct mcp_driver *mcpdrv) { diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 02c53a0766c..1c0ceacaa1f 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -13,51 +13,61 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/mfd/mcp.h> -#include <mach/dma.h> #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/system.h> #include <mach/mcp.h> -#include <mach/assabet.h> - +#define DRIVER_NAME "sa11x0-mcp" struct mcp_sa11x0 { - u32 mccr0; - u32 mccr1; + void __iomem *base0; + void __iomem *base1; + u32 mccr0; + u32 mccr1; }; +/* Register offsets */ +#define MCCR0(m) ((m)->base0 + 0x00) +#define MCDR0(m) ((m)->base0 + 0x08) +#define MCDR1(m) ((m)->base0 + 0x0c) +#define MCDR2(m) ((m)->base0 + 0x10) +#define MCSR(m) ((m)->base0 + 0x18) +#define MCCR1(m) ((m)->base1 + 0x00) + #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) static void mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *m = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x00007f00; - mccr0 |= divisor << 8; - Ser4MCCR0 = mccr0; + m->mccr0 &= ~0x00007f00; + m->mccr0 |= divisor << 8; + writel_relaxed(m->mccr0, MCCR0(m)); } static void mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *m = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x0000007f; - mccr0 |= divisor; - Ser4MCCR0 = mccr0; + m->mccr0 &= ~0x0000007f; + m->mccr0 |= divisor; + writel_relaxed(m->mccr0, MCCR0(m)); } /* @@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) static void mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) { + struct mcp_sa11x0 *m = priv(mcp); int ret = -ETIME; int i; - Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); + writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m)); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CWC) { + if (readl_relaxed(MCSR(m)) & MCSR_CWC) { ret = 0; break; } @@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) static unsigned int mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) { + struct mcp_sa11x0 *m = priv(mcp); int ret = -ETIME; int i; - Ser4MCDR2 = reg << 17 | MCDR2_Rd; + writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m)); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CRC) { - ret = Ser4MCDR2 & 0xffff; + if (readl_relaxed(MCSR(m)) & MCSR_CRC) { + ret = readl_relaxed(MCDR2(m)) & 0xffff; break; } } @@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) static void mcp_sa11x0_enable(struct mcp *mcp) { - Ser4MCSR = -1; - Ser4MCCR0 |= MCCR0_MCE; + struct mcp_sa11x0 *m = priv(mcp); + + writel(-1, MCSR(m)); + m->mccr0 |= MCCR0_MCE; + writel_relaxed(m->mccr0, MCCR0(m)); } static void mcp_sa11x0_disable(struct mcp *mcp) { - Ser4MCCR0 &= ~MCCR0_MCE; + struct mcp_sa11x0 *m = priv(mcp); + + m->mccr0 &= ~MCCR0_MCE; + writel_relaxed(m->mccr0, MCCR0(m)); } /* @@ -137,55 +155,64 @@ static struct mcp_ops mcp_sa11x0 = { .disable = mcp_sa11x0_disable, }; -static int mcp_sa11x0_probe(struct platform_device *pdev) +static int mcp_sa11x0_probe(struct platform_device *dev) { - struct mcp_plat_data *data = pdev->dev.platform_data; + struct mcp_plat_data *data = dev->dev.platform_data; + struct resource *mem0, *mem1; + struct mcp_sa11x0 *m; struct mcp *mcp; int ret; if (!data) return -ENODEV; - if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) - return -EBUSY; + mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); + mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); + if (!mem0 || !mem1) + return -ENXIO; + + if (!request_mem_region(mem0->start, resource_size(mem0), + DRIVER_NAME)) { + ret = -EBUSY; + goto err_mem0; + } - mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); + if (!request_mem_region(mem1->start, resource_size(mem1), + DRIVER_NAME)) { + ret = -EBUSY; + goto err_mem1; + } + + mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0)); if (!mcp) { ret = -ENOMEM; - goto release; + goto err_alloc; } mcp->owner = THIS_MODULE; mcp->ops = &mcp_sa11x0; mcp->sclk_rate = data->sclk_rate; - mcp->dma_audio_rd = DMA_Ser4MCP0Rd; - mcp->dma_audio_wr = DMA_Ser4MCP0Wr; - mcp->dma_telco_rd = DMA_Ser4MCP1Rd; - mcp->dma_telco_wr = DMA_Ser4MCP1Wr; - mcp->gpio_base = data->gpio_base; - platform_set_drvdata(pdev, mcp); + m = priv(mcp); + m->mccr0 = data->mccr0 | 0x7f7f; + m->mccr1 = data->mccr1; - if (machine_is_assabet()) { - ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); + m->base0 = ioremap(mem0->start, resource_size(mem0)); + m->base1 = ioremap(mem1->start, resource_size(mem1)); + if (!m->base0 || !m->base1) { + ret = -ENOMEM; + goto err_ioremap; } - /* - * Setup the PPC unit correctly. - */ - PPDR &= ~PPC_RXD4; - PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; - PSDR |= PPC_RXD4; - PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); - PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + platform_set_drvdata(dev, mcp); /* * Initialise device. Note that we initially * set the sampling rate to minimum. */ - Ser4MCSR = -1; - Ser4MCCR1 = data->mccr1; - Ser4MCCR0 = data->mccr0 | 0x7f7f; + writel_relaxed(-1, MCSR(m)); + writel_relaxed(m->mccr1, MCCR1(m)); + writel_relaxed(m->mccr0, MCCR0(m)); /* * Calculate the read/write timeout (us) from the bit clock @@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / mcp->sclk_rate; - ret = mcp_host_register(mcp); + ret = mcp_host_add(mcp, data->codec_pdata); if (ret == 0) - goto out; + return 0; - release: - release_mem_region(0x80060000, 0x60); - platform_set_drvdata(pdev, NULL); + platform_set_drvdata(dev, NULL); - out: + err_ioremap: + iounmap(m->base1); + iounmap(m->base0); + mcp_host_free(mcp); + err_alloc: + release_mem_region(mem1->start, resource_size(mem1)); + err_mem1: + release_mem_region(mem0->start, resource_size(mem0)); + err_mem0: return ret; } static int mcp_sa11x0_remove(struct platform_device *dev) { struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *m = priv(mcp); + struct resource *mem0, *mem1; + + if (m->mccr0 & MCCR0_MCE) + dev_warn(&dev->dev, + "device left active (missing disable call?)\n"); + + mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); + mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); platform_set_drvdata(dev, NULL); - mcp_host_unregister(mcp); - release_mem_region(0x80060000, 0x60); + mcp_host_del(mcp); + iounmap(m->base1); + iounmap(m->base0); + mcp_host_free(mcp); + release_mem_region(mem1->start, resource_size(mem1)); + release_mem_region(mem0->start, resource_size(mem0)); return 0; } -static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int mcp_sa11x0_suspend(struct device *dev) { - struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev)); + + if (m->mccr0 & MCCR0_MCE) + dev_warn(dev, "device left active (missing disable call?)\n"); - priv(mcp)->mccr0 = Ser4MCCR0; - priv(mcp)->mccr1 = Ser4MCCR1; - Ser4MCCR0 &= ~MCCR0_MCE; + writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m)); return 0; } -static int mcp_sa11x0_resume(struct platform_device *dev) +static int mcp_sa11x0_resume(struct device *dev) { - struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev)); - Ser4MCCR1 = priv(mcp)->mccr1; - Ser4MCCR0 = priv(mcp)->mccr0; + writel_relaxed(m->mccr1, MCCR1(m)); + writel_relaxed(m->mccr0, MCCR0(m)); return 0; } - -/* - * The driver for the SA11x0 MCP port. - */ -MODULE_ALIAS("platform:sa11x0-mcp"); +#endif + +static const struct dev_pm_ops mcp_sa11x0_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = mcp_sa11x0_suspend, + .freeze = mcp_sa11x0_suspend, + .poweroff = mcp_sa11x0_suspend, + .resume_noirq = mcp_sa11x0_resume, + .thaw_noirq = mcp_sa11x0_resume, + .restore_noirq = mcp_sa11x0_resume, +#endif +}; static struct platform_driver mcp_sa11x0_driver = { .probe = mcp_sa11x0_probe, .remove = mcp_sa11x0_remove, - .suspend = mcp_sa11x0_suspend, - .resume = mcp_sa11x0_resume, .driver = { - .name = "sa11x0-mcp", + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &mcp_sa11x0_pm_ops, }, }; @@ -259,6 +314,7 @@ static struct platform_driver mcp_sa11x0_driver = { */ module_platform_driver(mcp_sa11x0_driver); +MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c index cea9da60850..b63c0756a66 100644 --- a/drivers/mfd/ucb1x00-assabet.c +++ b/drivers/mfd/ucb1x00-assabet.c @@ -11,14 +11,15 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/device.h> +#include <linux/err.h> #include <linux/fs.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/platform_device.h> #include <linux/proc_fs.h> -#include <linux/device.h> #include <linux/mfd/ucb1x00.h> -#include <mach/dma.h> - - #define UCB1X00_ATTR(name,input)\ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); static int ucb1x00_assabet_add(struct ucb1x00_dev *dev) { - device_create_file(&dev->ucb->dev, &dev_attr_vbatt); - device_create_file(&dev->ucb->dev, &dev_attr_vcharger); - device_create_file(&dev->ucb->dev, &dev_attr_batt_temp); + struct ucb1x00 *ucb = dev->ucb; + struct platform_device *pdev; + struct gpio_keys_platform_data keys; + static struct gpio_keys_button buttons[6]; + unsigned i; + + memset(buttons, 0, sizeof(buttons)); + memset(&keys, 0, sizeof(keys)); + + for (i = 0; i < ARRAY_SIZE(buttons); i++) { + buttons[i].code = BTN_0 + i; + buttons[i].gpio = ucb->gpio.base + i; + buttons[i].type = EV_KEY; + buttons[i].can_disable = true; + } + + keys.buttons = buttons; + keys.nbuttons = ARRAY_SIZE(buttons); + keys.poll_interval = 50; + keys.name = "ucb1x00"; + + pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1, + &keys, sizeof(keys)); + + device_create_file(&ucb->dev, &dev_attr_vbatt); + device_create_file(&ucb->dev, &dev_attr_vcharger); + device_create_file(&ucb->dev, &dev_attr_batt_temp); + + dev->priv = pdev; return 0; } static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev) { + struct platform_device *pdev = dev->priv; + + if (!IS_ERR(pdev)) + platform_device_unregister(pdev); + device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp); device_remove_file(&dev->ucb->dev, &dev_attr_vcharger); device_remove_file(&dev->ucb->dev, &dev_attr_vbatt); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index febc90cdef7..70f02daeb22 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -23,14 +23,12 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/device.h> #include <linux/mutex.h> #include <linux/mfd/ucb1x00.h> +#include <linux/pm.h> #include <linux/gpio.h> -#include <linux/semaphore.h> - -#include <mach/dma.h> -#include <mach/hardware.h> static DEFINE_MUTEX(ucb1x00_mutex); static LIST_HEAD(ucb1x00_drivers); @@ -102,7 +100,7 @@ void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear) * ucb1x00_enable must have been called to enable the comms * before using this function. * - * This function does not take any semaphores or spinlocks. + * This function does not take any mutexes or spinlocks. */ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) { @@ -120,14 +118,22 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) else ucb->io_out &= ~(1 << offset); + ucb1x00_enable(ucb); ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); + ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); } static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) { struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); - return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset); + unsigned val; + + ucb1x00_enable(ucb); + val = ucb1x00_reg_read(ucb, UCB_IO_DATA); + ucb1x00_disable(ucb); + + return val & (1 << offset); } static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -137,7 +143,9 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ucb->io_lock, flags); ucb->io_dir &= ~(1 << offset); + ucb1x00_enable(ucb); ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); + ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); return 0; @@ -157,6 +165,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset else ucb->io_out &= ~mask; + ucb1x00_enable(ucb); if (old != ucb->io_out) ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); @@ -164,11 +173,19 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset ucb->io_dir |= mask; ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); } + ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); return 0; } +static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + + return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO; +} + /* * UCB1300 data sheet says we must: * 1. enable ADC => 5us (including reference startup time) @@ -186,7 +203,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset * Any code wishing to use the ADC converter must call this * function prior to using it. * - * This function takes the ADC semaphore to prevent two or more + * This function takes the ADC mutex to prevent two or more * concurrent uses, and therefore may sleep. As a result, it * can only be called from process context, not interrupt * context. @@ -196,7 +213,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset */ void ucb1x00_adc_enable(struct ucb1x00 *ucb) { - down(&ucb->adc_sem); + mutex_lock(&ucb->adc_mutex); ucb->adc_cr |= UCB_ADC_ENA; @@ -218,7 +235,7 @@ void ucb1x00_adc_enable(struct ucb1x00 *ucb) * complete (2 frames max without sync). * * If called for a synchronised ADC conversion, it may sleep - * with the ADC semaphore held. + * with the ADC mutex held. */ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) { @@ -246,7 +263,7 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) * ucb1x00_adc_disable - disable the ADC converter * @ucb: UCB1x00 structure describing chip * - * Disable the ADC converter and release the ADC semaphore. + * Disable the ADC converter and release the ADC mutex. */ void ucb1x00_adc_disable(struct ucb1x00 *ucb) { @@ -254,7 +271,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb) ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); ucb1x00_disable(ucb); - up(&ucb->adc_sem); + mutex_unlock(&ucb->adc_mutex); } /* @@ -265,10 +282,9 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb) * SIBCLK to talk to the chip. We leave the clock running until * we have finished processing all interrupts from the chip. */ -static irqreturn_t ucb1x00_irq(int irqnr, void *devid) +static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc) { - struct ucb1x00 *ucb = devid; - struct ucb1x00_irq *irq; + struct ucb1x00 *ucb = irq_desc_get_handler_data(desc); unsigned int isr, i; ucb1x00_enable(ucb); @@ -276,157 +292,104 @@ static irqreturn_t ucb1x00_irq(int irqnr, void *devid) ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); - for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++) - if (isr & 1 && irq->fn) - irq->fn(i, irq->devid); + for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++) + if (isr & 1) + generic_handle_irq(ucb->irq_base + i); ucb1x00_disable(ucb); - - return IRQ_HANDLED; } -/** - * ucb1x00_hook_irq - hook a UCB1x00 interrupt - * @ucb: UCB1x00 structure describing chip - * @idx: interrupt index - * @fn: function to call when interrupt is triggered - * @devid: device id to pass to interrupt handler - * - * Hook the specified interrupt. You can only register one handler - * for each interrupt source. The interrupt source is not enabled - * by this function; use ucb1x00_enable_irq instead. - * - * Interrupt handlers will be called with other interrupts enabled. - * - * Returns zero on success, or one of the following errors: - * -EINVAL if the interrupt index is invalid - * -EBUSY if the interrupt has already been hooked - */ -int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid) +static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask) { - struct ucb1x00_irq *irq; - int ret = -EINVAL; - - if (idx < 16) { - irq = ucb->irq_handler + idx; - ret = -EBUSY; - - spin_lock_irq(&ucb->lock); - if (irq->fn == NULL) { - irq->devid = devid; - irq->fn = fn; - ret = 0; - } - spin_unlock_irq(&ucb->lock); - } - return ret; + ucb1x00_enable(ucb); + if (ucb->irq_ris_enbl & mask) + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & + ucb->irq_mask); + if (ucb->irq_fal_enbl & mask) + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & + ucb->irq_mask); + ucb1x00_disable(ucb); |