diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 09:22:47 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 09:22:47 -0700 |
commit | 3b72e4415438538c0967fd1aee930f688ccdf6dd (patch) | |
tree | b3c234f933c4781d028e499b0e12f85f6366591a | |
parent | 396b122f6af3d329df3b4d688f6e66de3e2a399a (diff) | |
parent | 64c12e9b7edb0bfce9c5d7db43091b67894d8339 (diff) |
Merge branch 'for-next' of git://git.o-hand.com/linux-mfd
* 'for-next' of git://git.o-hand.com/linux-mfd:
mfd: further unbork the ucb1400 ac97_bus dependencies
mfd: ucb1400 needs GPIO
mfd: ucb1400 sound driver uses/depends on AC97_BUS:
mfd: Don't use NO_IRQ in WM8350
mfd: update TMIO drivers to use the clock API
mfd: twl4030-core irq simplification
mfd: add base support for Dialog DA9030/DA9034 PMICs
mfd: TWL4030 core driver
mfd: support tmiofb cell on tc6393xb
mfd: add OHCI cell to tc6393xb
mfd: Fix htc-egpio compile warning
mfd: do tcb6393xb state restore on resume only if requested
mfd: provide and use setup hook for tc6393xb
mfd: update sm501 debugging/low information messages
mfd: reduce stack usage in mfd-core.c
-rw-r--r-- | arch/arm/mach-pxa/include/mach/tosa.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-pxa/tosa.c | 37 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 16 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 2 | ||||
-rw-r--r-- | drivers/mfd/da903x.c | 563 | ||||
-rw-r--r-- | drivers/mfd/htc-egpio.c | 2 | ||||
-rw-r--r-- | drivers/mfd/mfd-core.c | 15 | ||||
-rw-r--r-- | drivers/mfd/sm501.c | 6 | ||||
-rw-r--r-- | drivers/mfd/t7l66xb.c | 40 | ||||
-rw-r--r-- | drivers/mfd/tc6387xb.c | 47 | ||||
-rw-r--r-- | drivers/mfd/tc6393xb.c | 296 | ||||
-rw-r--r-- | drivers/mfd/twl4030-core.c | 1193 | ||||
-rw-r--r-- | drivers/mfd/wm8350-core.c | 2 | ||||
-rw-r--r-- | include/linux/i2c/twl4030.h | 339 | ||||
-rw-r--r-- | include/linux/mfd/da903x.h | 201 | ||||
-rw-r--r-- | include/linux/mfd/t7l66xb.h | 2 | ||||
-rw-r--r-- | include/linux/mfd/tc6387xb.h | 3 | ||||
-rw-r--r-- | include/linux/mfd/tc6393xb.h | 17 |
19 files changed, 2687 insertions, 98 deletions
diff --git a/arch/arm/mach-pxa/include/mach/tosa.h b/arch/arm/mach-pxa/include/mach/tosa.h index a72803f0461..8bce6d8615b 100644 --- a/arch/arm/mach-pxa/include/mach/tosa.h +++ b/arch/arm/mach-pxa/include/mach/tosa.h @@ -59,8 +59,6 @@ * TC6393XB GPIOs */ #define TOSA_TC6393XB_GPIO_BASE (NR_BUILTIN_GPIO + 2 * 12) -#define TOSA_TC6393XB_GPIO(i) (TOSA_TC6393XB_GPIO_BASE + (i)) -#define TOSA_TC6393XB_GPIO_BIT(gpio) (1 << (gpio - TOSA_TC6393XB_GPIO_BASE)) #define TOSA_GPIO_TG_ON (TOSA_TC6393XB_GPIO_BASE + 0) #define TOSA_GPIO_L_MUTE (TOSA_TC6393XB_GPIO_BASE + 1) diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 130e37e4ebd..a6c4694359c 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -706,16 +706,39 @@ static struct tmio_nand_data tosa_tc6393xb_nand_config = { .badblock_pattern = &tosa_tc6393xb_nand_bbt, }; -static struct tc6393xb_platform_data tosa_tc6393xb_setup = { +static int tosa_tc6393xb_setup(struct platform_device *dev) +{ + int rc; + + rc = gpio_request(TOSA_GPIO_CARD_VCC_ON, "CARD_VCC_ON"); + if (rc) + goto err_req; + + rc = gpio_direction_output(TOSA_GPIO_CARD_VCC_ON, 1); + if (rc) + goto err_dir; + + return rc; + +err_dir: + gpio_free(TOSA_GPIO_CARD_VCC_ON); +err_req: + return rc; +} + +static void tosa_tc6393xb_teardown(struct platform_device *dev) +{ + gpio_free(TOSA_GPIO_CARD_VCC_ON); +} + +static struct tc6393xb_platform_data tosa_tc6393xb_data = { .scr_pll2cr = 0x0cc1, .scr_gper = 0x3300, - .scr_gpo_dsr = - TOSA_TC6393XB_GPIO_BIT(TOSA_GPIO_CARD_VCC_ON), - .scr_gpo_doecr = - TOSA_TC6393XB_GPIO_BIT(TOSA_GPIO_CARD_VCC_ON), .irq_base = IRQ_BOARD_START, .gpio_base = TOSA_TC6393XB_GPIO_BASE, + .setup = tosa_tc6393xb_setup, + .teardown = tosa_tc6393xb_teardown, .enable = tosa_tc6393xb_enable, .disable = tosa_tc6393xb_disable, @@ -723,6 +746,8 @@ static struct tc6393xb_platform_data tosa_tc6393xb_setup = { .resume = tosa_tc6393xb_resume, .nand_data = &tosa_tc6393xb_nand_config, + + .resume_restore = 1, }; @@ -730,7 +755,7 @@ static struct platform_device tc6393xb_device = { .name = "tc6393xb", .id = -1, .dev = { - .platform_data = &tosa_tc6393xb_setup, + .platform_data = &tosa_tc6393xb_data, }, .num_resources = ARRAY_SIZE(tc6393xb_resources), .resource = tc6393xb_resources, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6e1e8c624f9..8317fdef169 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -219,7 +219,7 @@ config TOUCHSCREEN_ATMEL_TSADCC config TOUCHSCREEN_UCB1400 tristate "Philips UCB1400 touchscreen" - select AC97_BUS + depends on AC97_BUS depends on UCB1400_CORE help This enables support for the Philips UCB1400 touchscreen interface. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 5eff8ad834d..5a79d2d4cda 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -52,6 +52,8 @@ config HTC_PASIC3 config UCB1400_CORE tristate "Philips UCB1400 Core driver" + depends on AC97_BUS + depends on GPIOLIB help This enables support for the Philips UCB1400 core functions. The UCB1400 is an AC97 audio codec. @@ -59,6 +61,20 @@ config UCB1400_CORE To compile this driver as a module, choose M here: the module will be called ucb1400_core. +config TWL4030_CORE + bool "Texas Instruments TWL4030/TPS659x0 Support" + depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3) + help + Say yes here if you have TWL4030 family chip on your board. + This core driver provides register access and IRQ handling + facilities, and registers devices for the various functions + so that function-specific drivers can bind to them. + + These multi-function chips are found on many OMAP2 and OMAP3 + boards, providing power management, RTC, GPIO, keypad, a + high speed USB OTG transceiver, an audio codec (on most + versions) and many other features. + config MFD_TMIO bool default n diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 759b1fe1c89..68e237b830a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -17,6 +17,8 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o obj-$(CONFIG_MFD_WM8350) += wm8350.o obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o +obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o + obj-$(CONFIG_MFD_CORE) += mfd-core.o obj-$(CONFIG_MCP) += mcp-core.o diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c new file mode 100644 index 00000000000..b57326ae464 --- /dev/null +++ b/drivers/mfd/da903x.c @@ -0,0 +1,563 @@ +/* + * Base driver for Dialog Semiconductor DA9030/DA9034 + * + * Copyright (C) 2008 Compulab, Ltd. + * Mike Rapoport <mike@compulab.co.il> + * + * Copyright (C) 2006-2008 Marvell International Ltd. + * Eric Miao <eric.miao@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/mfd/da903x.h> + +#define DA9030_CHIP_ID 0x00 +#define DA9030_EVENT_A 0x01 +#define DA9030_EVENT_B 0x02 +#define DA9030_EVENT_C 0x03 +#define DA9030_STATUS 0x04 +#define DA9030_IRQ_MASK_A 0x05 +#define DA9030_IRQ_MASK_B 0x06 +#define DA9030_IRQ_MASK_C 0x07 +#define DA9030_SYS_CTRL_A 0x08 +#define DA9030_SYS_CTRL_B 0x09 +#define DA9030_FAULT_LOG 0x0a + +#define DA9034_CHIP_ID 0x00 +#define DA9034_EVENT_A 0x01 +#define DA9034_EVENT_B 0x02 +#define DA9034_EVENT_C 0x03 +#define DA9034_EVENT_D 0x04 +#define DA9034_STATUS_A 0x05 +#define DA9034_STATUS_B 0x06 +#define DA9034_IRQ_MASK_A 0x07 +#define DA9034_IRQ_MASK_B 0x08 +#define DA9034_IRQ_MASK_C 0x09 +#define DA9034_IRQ_MASK_D 0x0a +#define DA9034_SYS_CTRL_A 0x0b +#define DA9034_SYS_CTRL_B 0x0c +#define DA9034_FAULT_LOG 0x0d + +struct da903x_chip; + +struct da903x_chip_ops { + int (*init_chip)(struct da903x_chip *); + int (*unmask_events)(struct da903x_chip *, unsigned int events); + int (*mask_events)(struct da903x_chip *, unsigned int events); + int (*read_events)(struct da903x_chip *, unsigned int *events); + int (*read_status)(struct da903x_chip *, unsigned int *status); +}; + +struct da903x_chip { + struct i2c_client *client; + struct device *dev; + struct da903x_chip_ops *ops; + + int type; + uint32_t events_mask; + + struct mutex lock; + struct work_struct irq_work; + + struct blocking_notifier_head notifier_list; +}; + +static inline int __da903x_read(struct i2c_client *client, + int reg, uint8_t *val) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "failed reading at 0x%02x\n", reg); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + +static inline int __da903x_reads(struct i2c_client *client, int reg, + int len, uint8_t *val) +{ + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, reg, len, val); + if (ret < 0) { + dev_err(&client->dev, "failed reading from 0x%02x\n", reg); + return ret; + } + return 0; +} + +static inline int __da903x_write(struct i2c_client *client, + int reg, uint8_t val) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret < 0) { + dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n", + val, reg); + return ret; + } + return 0; +} + +static inline int __da903x_writes(struct i2c_client *client, int reg, + int len, uint8_t *val) +{ + int ret; + + ret = i2c_smbus_write_i2c_block_data(client, reg, len, val); + if (ret < 0) { + dev_err(&client->dev, "failed writings to 0x%02x\n", reg); + return ret; + } + return 0; +} + +int da903x_register_notifier(struct device *dev, struct notifier_block *nb, + unsigned int events) +{ + struct da903x_chip *chip = dev_get_drvdata(dev); + + chip->ops->unmask_events(chip, events); + return blocking_notifier_chain_register(&chip->notifier_list, nb); +} +EXPORT_SYMBOL_GPL(da903x_register_notifier); + +int da903x_unregister_notifier(struct device *dev, struct notifier_block *nb, + unsigned int events) +{ + struct da903x_chip *chip = dev_get_drvdata(dev); + + chip->ops->mask_events(chip, events); + return blocking_notifier_chain_unregister(&chip->notifier_list, nb); +} +EXPORT_SYMBOL_GPL(da903x_unregister_notifier); + +int da903x_write(struct device *dev, int reg, uint8_t val) +{ + return __da903x_write(to_i2c_client(dev), reg, val); +} +EXPORT_SYMBOL_GPL(da903x_write); + +int da903x_read(struct device *dev, int reg, uint8_t *val) +{ + return __da903x_read(to_i2c_client(dev), reg, val); +} +EXPORT_SYMBOL_GPL(da903x_read); + +int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask) +{ + struct da903x_chip *chip = dev_get_drvdata(dev); + uint8_t reg_val; + int ret = 0; + + mutex_lock(&chip->lock); + + ret = __da903x_read(chip->client, reg, ®_val); + if (ret) + goto out; + + if ((reg_val & bit_mask) == 0) { + reg_val |= bit_mask; + ret = __da903x_write(chip->client, reg, reg_val); + } +out: + mutex_unlock(&chip->lock); + return ret; +} +EXPORT_SYMBOL_GPL(da903x_set_bits); + +int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask) +{ + struct da903x_chip *chip = dev_get_drvdata(dev); + uint8_t reg_val; + int ret = 0; + + mutex_lock(&chip->lock); + + ret = __da903x_read(chip->client, reg, ®_val); + if (ret) + goto out; + + if (reg_val & bit_mask) { + reg_val &= ~bit_mask; + ret = __da903x_write(chip->client, reg, reg_val); + } +out: + mutex_unlock(&chip->lock); + return ret; +} +EXPORT_SYMBOL_GPL(da903x_clr_bits); + +int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask) +{ + struct da903x_chip *chip = dev_get_drvdata(dev); + uint8_t reg_val; + int ret = 0; + + mutex_lock(&chip->lock); + + ret = __da903x_read(chip->client, reg, ®_val); + if (ret) + goto out; + + if ((reg_val & mask) != val) { + reg_val = (reg_val & ~mask) | val; + ret = __da903x_write(chip->client, reg, reg_val); + } +out: + mutex_unlock(&chip->lock); + return ret; +} +EXPORT_SYMBOL_GPL(da903x_update); + +int da903x_query_status(struct device *dev, unsigned int sbits) +{ + struct da903x_chip *chip = dev_get_drvdata(dev); + unsigned int status = 0; + + chip->ops->read_status(chip, &status); + return ((status & sbits) == sbits); +} +EXPORT_SYMBOL(da903x_query_status); + +static int __devinit da9030_init_chip(struct da903x_chip *chip) +{ + uint8_t chip_id; + int err; + + err = __da903x_read(chip->client, DA9030_CHIP_ID, &chip_id); + if (err) + return err; + + err = __da903x_write(chip->client, DA9030_SYS_CTRL_A, 0xE8); + if (err) + return err; + + dev_info(chip->dev, "DA9030 (CHIP ID: 0x%02x) detected\n", chip_id); + return 0; +} + +static int da9030_unmask_events(struct da903x_chip *chip, unsigned int events) +{ + uint8_t v[3]; + + chip->events_mask &= ~events; + + v[0] = (chip->events_mask & 0xff); + v[1] = (chip->events_mask >> 8) & 0xff; + v[2] = (chip->events_mask >> 16) & 0xff; + + return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v); +} + +static int da9030_mask_events(struct da903x_chip *chip, unsigned int events) +{ + uint8_t v[3]; + + chip->events_mask &= ~events; + + v[0] = (chip->events_mask & 0xff); + v[1] = (chip->events_mask >> 8) & 0xff; + v[2] = (chip->events_mask >> 16) & 0xff; + + return __da903x_writes(chip->client, DA9030_IRQ_MASK_A, 3, v); +} + +static int da9030_read_events(struct da903x_chip *chip, unsigned int *events) +{ + uint8_t v[3] = {0, 0, 0}; + int ret; + + ret = __da903x_reads(chip->client, DA9030_EVENT_A, 3, v); + if (ret < 0) + return ret; + + *events = (v[2] << 16) | (v[1] << 8) | v[0]; + return 0; +} + +static int da9030_read_status(struct da903x_chip *chip, unsigned int *status) +{ + return __da903x_read(chip->client, DA9030_STATUS, (uint8_t *)status); +} + +static int da9034_init_chip(struct da903x_chip *chip) +{ + uint8_t chip_id; + int err; + + err = __da903x_read(chip->client, DA9034_CHIP_ID, &chip_id); + if (err) + return err; + + err = __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0xE8); + if (err) + return err; + + /* avoid SRAM power off during sleep*/ + __da903x_write(chip->client, 0x10, 0x07); + __da903x_write(chip->client, 0x11, 0xff); + __da903x_write(chip->client, 0x12, 0xff); + + /* Enable the ONKEY power down functionality */ + __da903x_write(chip->client, DA9034_SYS_CTRL_B, 0x20); + __da903x_write(chip->client, DA9034_SYS_CTRL_A, 0x60); + + /* workaround to make LEDs work */ + __da903x_write(chip->client, 0x90, 0x01); + __da903x_write(chip->client, 0xB0, 0x08); + + /* make ADTV1 and SDTV1 effective */ + __da903x_write(chip->client, 0x20, 0x00); + + dev_info(chip->dev, "DA9034 (CHIP ID: 0x%02x) detected\n", chip_id); + return 0; +} + +static int da9034_unmask_events(struct da903x_chip *chip, unsigned int events) +{ + uint8_t v[4]; + + chip->events_mask &= ~events; + + v[0] = (chip->events_mask & 0xff); + v[1] = (chip->events_mask >> 8) & 0xff; + v[2] = (chip->events_mask >> 16) & 0xff; + v[3] = (chip->events_mask >> 24) & 0xff; + + return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v); +} + +static int da9034_mask_events(struct da903x_chip *chip, unsigned int events) +{ + uint8_t v[4]; + + chip->events_mask |= events; + + v[0] = (chip->events_mask & 0xff); + v[1] = (chip->events_mask >> 8) & 0xff; + v[2] = (chip->events_mask >> 16) & 0xff; + v[3] = (chip->events_mask >> 24) & 0xff; + + return __da903x_writes(chip->client, DA9034_IRQ_MASK_A, 4, v); +} + +static int da9034_read_events(struct da903x_chip *chip, unsigned int *events) +{ + uint8_t v[4] = {0, 0, 0, 0}; + int ret; + + ret = __da903x_reads(chip->client, DA9034_EVENT_A, 4, v); + if (ret < 0) + return ret; + + *events = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0]; + return 0; +} + +static int da9034_read_status(struct da903x_chip *chip, unsigned int *status) +{ + uint8_t v[2] = {0, 0}; + int ret = 0; + + ret = __da903x_reads(chip->client, DA9034_STATUS_A, 2, v); + if (ret) + return ret; + + *status = (v[1] << 8) | v[0]; + return 0; +} + +static void da903x_irq_work(struct work_struct *work) +{ + struct da903x_chip *chip = + container_of(work, struct da903x_chip, irq_work); + unsigned int events = 0; + + while (1) { + if (chip->ops->read_events(chip, &events)) + break; + + events &= ~chip->events_mask; + if (events == 0) + break; + + blocking_notifier_call_chain( + &chip->notifier_list, events, NULL); + } + enable_irq(chip->client->irq); +} + +static int da903x_irq_handler(int irq, void *data) +{ + struct da903x_chip *chip = data; + + disable_irq_nosync(irq); + (void)schedule_work(&chip->irq_work); + + return IRQ_HANDLED; +} + +static struct da903x_chip_ops da903x_ops[] = { + [0] = { + .init_chip = da9030_init_chip, + .unmask_events = da9030_unmask_events, + .mask_events = da9030_mask_events, + .read_events = da9030_read_events, + .read_status = da9030_read_status, + }, + [1] = { + .init_chip = da9034_init_chip, + .unmask_events = da9034_unmask_events, + .mask_events = da9034_mask_events, + .read_events = da9034_read_events, + .read_status = da9034_read_status, + } +}; + +static const struct i2c_device_id da903x_id_table[] = { + { "da9030", 0 }, + { "da9034", 1 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, da903x_id_table); + +static int __devexit __remove_subdev(struct device *dev, void *unused) +{ + platform_device_unregister(to_platform_device(dev)); + return 0; +} + +static int __devexit da903x_remove_subdevs(struct da903x_chip *chip) +{ + return device_for_each_child(chip->dev, NULL, __remove_subdev); +} + +static int __devinit da903x_add_subdevs(struct da903x_chip *chip, + struct da903x_platform_data *pdata) +{ + struct da903x_subdev_info *subdev; + struct platform_device *pdev; + int i, ret = 0; + + for (i = 0; i < pdata->num_subdevs; i++) { + subdev = &pdata->subdevs[i]; + + pdev = platform_device_alloc(subdev->name, subdev->id); + + pdev->dev.parent = chip->dev; + pdev->dev.platform_data = subdev->platform_data; + + ret = platform_device_add(pdev); + if (ret) + goto failed; + } + return 0; + +failed: + da903x_remove_subdevs(chip); + return ret; +} + +static int __devinit da903x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct da903x_platform_data *pdata = client->dev.platform_data; + struct da903x_chip *chip; + unsigned int tmp; + int ret; + + chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->client = client; + chip->dev = &client->dev; + chip->ops = &da903x_ops[id->driver_data]; + + mutex_init(&chip->lock); + INIT_WORK(&chip->irq_work, da903x_irq_work); + BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list); + + i2c_set_clientdata(client, chip); + + ret = chip->ops->init_chip(chip); + if (ret) + goto out_free_chip; + + /* mask and clear all IRQs */ + chip->events_mask = 0xffffffff; + chip->ops->mask_events(chip, chip->events_mask); + chip->ops->read_events(chip, &tmp); + + ret = request_irq(client->irq, da903x_irq_handler, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "da903x", chip); + if (ret) { + dev_err(&client->dev, "failed to request irq %d\n", + client->irq); + goto out_free_chip; + } + + ret = da903x_add_subdevs(chip, pdata); + if (ret) + goto out_free_irq; + + return 0; + +out_free_irq: + free_irq(client->irq, chip); +out_free_chip: + i2c_set_clientdata(client, NULL); + kfree(chip); + return ret; +} + +static int __devexit da903x_remove(struct i2c_client *client) +{ + struct da903x_chip *chip = i2c_get_clientdata(client); + + da903x_remove_subdevs(chip); + kfree(chip); + return 0; +} + +static struct i2c_driver da903x_driver = { + .driver = { + .name = "da903x", + .owner = THIS_MODULE, + }, + .probe = da903x_probe, + .remove = __devexit_p(da903x_remove), + .id_table = da903x_id_table, +}; + +static int __init da903x_init(void) +{ + return i2c_add_driver(&da903x_driver); +} +module_init(da903x_init); + +static void __exit da903x_exit(void) +{ + i2c_del_driver(&da903x_driver); +} +module_exit(da903x_exit); + +MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034"); +MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>" + "Mike Rapoport <mike@compulab.co.il>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index 6be43172dc6..50dff6e0088 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -289,7 +289,7 @@ static int __init egpio_probe(struct platform_device *pdev) ei->base_addr = ioremap_nocache(res->start, res->end - res->start); if (!ei->base_addr) goto fail; - pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr); + pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr); if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) goto fail; diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 9c9c126ed33..6c0d1bec4b7 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -20,7 +20,7 @@ static int mfd_add_device(struct device *parent, int id, struct resource *mem_base, int irq_base) { - struct resource res[cell->num_resources]; + struct resource *res; struct platform_device *pdev; int ret = -ENOMEM; int r; @@ -29,14 +29,17 @@ static int mfd_add_device(struct device *parent, int id, if (!pdev) goto fail_alloc; + res = kzalloc(sizeof(*res) * cell->num_resources, GFP_KERNEL); + if (!res) + goto fail_device; + pdev->dev.parent = parent; ret = platform_device_add_data(pdev, cell->platform_data, cell->data_size); if (ret) - goto fail_device; + goto fail_res; - memset(res, 0, sizeof(res)); for (r = 0; r < cell->num_resources; r++) { res[r].name = cell->resources[r].name; res[r].flags = cell->resources[r].flags; @@ -64,11 +67,15 @@ static int mfd_add_device(struct device *parent, int id, ret = platform_device_add(pdev); if (ret) - goto fail_device; + goto fail_res; + + kfree(res); return 0; /* platform_device_del(pdev); */ +fail_res: + kfree(res); fail_device: platform_device_put(pdev); fail_alloc: diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 7aebad4c06f..220e4371266 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -623,8 +623,8 @@ unsigned long sm501_set_clock(struct device *dev, sm501_sync_regs(sm); - dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", - gate, clock, mode); + dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", + gate, clock, mode); sm501_mdelay(sm, 16); mutex_unlock(&sm->clock_lock); @@ -742,7 +742,7 @@ static int sm501_register_device(struct sm501_devdata *sm, int ret; for (ptr = 0; ptr < pdev->num_resources; ptr++) { - printk("%s[%d] flags %08lx: %08llx..%08llx\n", + printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n", pdev->name, ptr, pdev->resource[ptr].flags, (unsigned long long)pdev->resource[ptr].start, diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 49a0fffc02a..9f7024c0f8e 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -24,8 +24,10 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/clk.h> #include <linux/platform_device.h> #include <linux/mfd/core.h> #include <linux/mfd/tmio.h> @@ -56,6 +58,8 @@ struct t7l66xb { spinlock_t lock; struct resource rscr; + struct clk *clk48m; + struct clk *clk32k; int irq; int irq_base; }; @@ -65,13 +69,11 @@ struct t7l66xb { static int t7l66xb_mmc_enable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; struct t7l66xb *t7l66xb = platform_get_drvdata(dev); unsigned long flags; u8 dev_ctl; - if (pdata->enable_clk32k) - pdata->enable_clk32k(dev); + clk_enable(t7l66xb->clk32k); spin_lock_irqsave(&t7l66xb->lock, flags); @@ -87,7 +89,6 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc) static int t7l66xb_mmc_disable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; struct t7l66xb *t7l66xb = platform_get_drvdata(dev); unsigned long flags; u8 dev_ctl; @@ -100,8 +101,7 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc) spin_unlock_irqrestore(&t7l66xb->lock, flags); - if (pdata->disable_clk32k) - pdata->disable_clk32k(dev); + clk_disable(t7l66xb->clk32k); return 0; } @@ -258,18 +258,22 @@ static void t7l66xb_detach_irq(struct platform_device *dev) #ifdef CONFIG_PM static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) { + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); struct t7l66xb_platform_data *pdata = dev->dev.platform_data; if (pdata && pdata->suspend) pdata->suspend(dev); + clk_disable(t7l66xb->clk48m); return 0; } static int t7l66xb_resume(struct platform_device *dev) { + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + clk_enable(t7l66xb->clk48m); if (pdata && pdata->resume) pdata->resume(dev); @@ -309,6 +313,19 @@ static int t7l66xb_probe(struct platform_device *dev) t7l66xb->irq_base = pdata->irq_base; + t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K"); + if (IS_ERR(t7l66xb->clk32k)) { + ret = PTR_ERR(t7l66xb->clk32k); + goto err_clk32k_get; + } + + t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M"); + if (IS_ERR(t7l66xb->clk48m)) { + ret = PTR_ERR(t7l66xb->clk48m); + clk_put(t7l66xb->clk32k); + goto err_clk48m_get; + } + rscr = &t7l66xb->rscr; rscr->name = "t7l66xb-core"; rscr->start = iomem->start; @@ -325,6 +342,8 @@ static int t7l66xb_probe(struct platform_device *dev) goto err_ioremap; } + clk_enable(t7l66xb->clk48m); + if (pdata && pdata->enable) pdata->enable(dev); @@ -359,9 +378,13 @@ static int t7l66xb_probe(struct platform_device *dev) iounmap(t7l66xb->scr); err_ioremap: release_resource(&t7l66xb->rscr); -err_noirq: err_request_scr: kfree(t7l66xb); + clk_put(t7l66xb->clk48m); +err_clk48m_get: + clk_put(t7l66xb->clk32k); +err_clk32k_get: +err_noirq: return ret; } @@ -372,7 +395,8 @@ static int t7l66xb_remove(struct platform_device *dev) int ret; ret = pdata->disable(dev); - + clk_disable(t7l66xb->clk48m); + clk_put(t7l66xb->clk48m); t7l66xb_detach_irq(dev); iounmap(t7l66xb->scr); release_resource(&t7l66xb->rscr); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index a22b21ac6cf..43222c12fec 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/err.h> #include <linux/mfd/core.h> #include <linux/mfd/tmio.h> @@ -24,18 +25,22 @@ enum { #ifdef CONFIG_PM static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) { - struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); + struct clk *clk32k = platform_get_drvdata(dev); + struct tc6387xb_platform_data *pdata = dev->dev.platform_data; if (pdata && pdata->suspend) pdata->suspend(dev); + clk_disable(clk32k); return 0; } static int tc6387xb_resume(struct platform_device *dev) { - struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev); + struct clk *clk32k = platform_get_drvdata(dev); + struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + clk_enable(clk32k); if (pdata && pdata->resume) pdata->resume(dev); @@ -51,10 +56,9 @@ static int tc6387xb_resume(struct platform_device *dev) static int tc6387xb_mmc_enable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); - struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; + struct clk *clk32k = platform_get_drvdata(dev); - if (tc6387xb->enable_clk32k) - tc6387xb->enable_clk32k(dev); + clk_enable(clk32k); return 0; } @@ -62,10 +66,9 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc) static int tc6387xb_mmc_disable(struct platform_device *mmc) { struct platform_device *dev = to_platform_device(mmc->dev.parent); - struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data; + struct clk *clk32k = platform_get_drvdata(dev); - if (tc6387xb->disable_clk32k) - tc6387xb->disable_clk32k(dev); + c |