aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2010-01-22 13:59:25 +0100
committerLars-Peter Clausen <lars@metafoo.de>2010-01-22 13:59:25 +0100
commit04697d0e4011a0f2942411acff56f9bc9ca6c11a (patch)
treeb5c2e552a77ce54aeb0859f62d3e0ef26d3d5696 /drivers
parente447c3d0b2ddaf8c2e98c9819d1c545ae7274f20 (diff)
parentb29086188b50e3794533074c2831b4b44507e7e9 (diff)
Merge branch 'pcf50633-2.6.32' into om-gta02-2.6.32om-gta02-2.6.32
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/pcf50633-gpio.c228
-rw-r--r--drivers/mfd/Kconfig7
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/pcf50633-core.c12
-rw-r--r--drivers/mfd/pcf50633-gpio.c121
7 files changed, 243 insertions, 134 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 2ad0128c63c..c1a4e822344 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -172,6 +172,13 @@ config GPIO_ADP5520
To compile this driver as a module, choose M here: the module will
be called adp5520-gpio.
+config GPIO_PCF50633
+ tristate "GPIO support for NXP PCF50633"
+ depends on MFD_PCF50633
+ help
+ Say yes here if you want to include support GPIO for pins on
+ the PCF50633 chip.
+
comment "PCI GPIO expanders:"
config GPIO_BT8XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 00a532c9a1e..25d66f19fb2 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o
obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o
+obj-$(CONFIG_GPIO_PCF50633) += pcf50633-gpio.o
diff --git a/drivers/gpio/pcf50633-gpio.c b/drivers/gpio/pcf50633-gpio.c
new file mode 100644
index 00000000000..dc49defed23
--- /dev/null
+++ b/drivers/gpio/pcf50633-gpio.c
@@ -0,0 +1,228 @@
+/* NXP PCF50633 GPIO Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * Copyright 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/platform_device.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/gpio.h>
+
+#define PCF50633_REG_GPIOCTL 0x13
+#define PCF50633_REG_GPIOCFG(x) (0x14 + (x))
+
+enum pcf50633_regulator_id {
+ PCF50633_REGULATOR_AUTO,
+ PCF50633_REGULATOR_DOWN1,
+ PCF50633_REGULATOR_DOWN2,
+ PCF50633_REGULATOR_LDO1,
+ PCF50633_REGULATOR_LDO2,
+ PCF50633_REGULATOR_LDO3,
+ PCF50633_REGULATOR_LDO4,
+ PCF50633_REGULATOR_LDO5,
+ PCF50633_REGULATOR_LDO6,
+ PCF50633_REGULATOR_HCLDO,
+ PCF50633_REGULATOR_MEMLDO,
+};
+
+#define PCF50633_REG_AUTOOUT 0x1a
+#define PCF50633_REG_DOWN1OUT 0x1e
+#define PCF50633_REG_DOWN2OUT 0x22
+#define PCF50633_REG_MEMLDOOUT 0x26
+#define PCF50633_REG_LDO1OUT 0x2d
+#define PCF50633_REG_LDO2OUT 0x2f
+#define PCF50633_REG_LDO3OUT 0x31
+#define PCF50633_REG_LDO4OUT 0x33
+#define PCF50633_REG_LDO5OUT 0x35
+#define PCF50633_REG_LDO6OUT 0x37
+#define PCF50633_REG_HCLDOOUT 0x39
+
+static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
+ [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
+ [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT,
+ [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT,
+ [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT,
+ [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT,
+ [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT,
+ [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT,
+ [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT,
+ [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT,
+ [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT,
+ [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT,
+};
+
+struct pcf50633_gpio {
+ struct pcf50633 *pcf;
+ struct gpio_chip chip;
+};
+
+static inline struct pcf50633 *gpio_chip_to_pcf50633(struct gpio_chip *chip)
+{
+ struct pcf50633 *pcf = dev_to_pcf50633(chip->dev->parent);
+ return pcf;
+}
+
+static void pcf50633_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct pcf50633 *pcf = gpio_chip_to_pcf50633(chip);
+ u8 reg;
+
+ reg = PCF50633_REG_GPIOCFG(gpio);
+
+ pcf50633_reg_set_bit_mask(pcf, reg, 0x07, value ? 0x0 : 0x7);
+}
+
+static int pcf50633_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct pcf50633 *pcf = gpio_chip_to_pcf50633(chip);
+ return pcf50633_reg_read(pcf, PCF50633_REG_GPIOCFG(gpio)) >> 3;
+}
+
+
+static int pcf50633_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ struct pcf50633 *pcf = gpio_chip_to_pcf50633(chip);
+ int ret;
+
+ ret = pcf50633_gpio_set_config(pcf, pcf->pdata->gpio_base + gpio,
+ PCF50633_GPIO_CONFIG_OUTPUT);
+ if (!ret)
+ pcf50633_gpio_set_value(chip, gpio, value);
+
+ return ret;
+}
+
+static int pcf50633_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ return -ENOSYS;
+}
+
+int pcf50633_gpio_set_config(struct pcf50633 *pcf, unsigned gpio,
+ enum pcf50633_gpio_config config)
+{
+ u8 reg;
+ u8 direction;
+ int ret;
+
+ gpio -= pcf->pdata->gpio_base;
+
+ if (gpio < 3) {
+ direction = (config == PCF50633_GPIO_CONFIG_INPUT) ? (1 << gpio) : 0;
+ ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_GPIOCTL, (1 << gpio),
+ direction);
+ if (ret) {
+ return ret;
+ }
+ } else if (gpio > 3 || config == PCF50633_GPIO_CONFIG_INPUT) {
+ return -EINVAL;
+ }
+
+ if (config != PCF50633_GPIO_CONFIG_INPUT) {
+ reg = PCF50633_REG_GPIOCFG(gpio);
+ ret = pcf50633_reg_set_bit_mask(pcf, reg, 0x0f, config);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_set_config);
+
+int pcf50633_gpio_power_supply_set(struct pcf50633 *pcf,
+ int gpio, int regulator, int on)
+{
+ u8 reg, val, mask;
+
+ gpio -= pcf->pdata->gpio_base;
+
+ /* the *ENA register is always one after the *OUT register */
+ reg = pcf50633_regulator_registers[regulator] + 1;
+
+ val = !!on << (gpio - PCF50633_GPIO1);
+ mask = 1 << (gpio - PCF50633_GPIO1);
+
+ return pcf50633_reg_set_bit_mask(pcf, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set);
+
+
+static int __devinit pcf50633_gpio_probe(struct platform_device *pdev)
+{
+ struct pcf50633 *pcf = dev_to_pcf50633(pdev->dev.parent);
+ struct pcf50633_gpio *pcf_gpio;
+
+ pcf_gpio = kzalloc(sizeof(*pcf_gpio), GFP_KERNEL);
+
+ if (!pcf_gpio)
+ return -ENOMEM;
+
+ pcf_gpio->pcf = pcf;
+
+ pcf_gpio->chip.direction_input = pcf50633_gpio_direction_input;
+ pcf_gpio->chip.direction_output = pcf50633_gpio_direction_output;
+ pcf_gpio->chip.get = pcf50633_gpio_get_value;
+ pcf_gpio->chip.set = pcf50633_gpio_set_value;
+
+ pcf_gpio->chip.base = pcf->pdata->gpio_base;
+ pcf_gpio->chip.ngpio = 4;
+ pcf_gpio->chip.label = dev_name(pcf->dev);
+ pcf_gpio->chip.can_sleep = 1;
+ pcf_gpio->chip.owner = THIS_MODULE;
+ pcf_gpio->chip.dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, pcf_gpio);
+
+ return gpiochip_add(&pcf_gpio->chip);
+}
+
+static int __devexit pcf50633_gpio_remove(struct platform_device *pdev)
+{
+ struct pcf50633_gpio *pcf_gpio = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&pcf_gpio->chip);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(pcf_gpio);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_gpio_driver = {
+ .probe = pcf50633_gpio_probe,
+ .remove = __devexit_p(pcf50633_gpio_remove),
+ .driver = {
+ .name = "pcf50633-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init pcf50633_gpio_init(void)
+{
+ return platform_driver_register(&pcf50633_gpio_driver);
+}
+module_init(pcf50633_gpio_init);
+
+void __exit pcf50633_gpio_exit(void)
+{
+ platform_driver_unregister(&pcf50633_gpio_driver);
+}
+module_exit(pcf50633_gpio_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("GPIO driver for the PCF50633");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f5a60b49dfb..0c2126fe16c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -268,13 +268,6 @@ config PCF50633_ADC
Say yes here if you want to include support for ADC in the
NXP PCF50633 chip.
-config PCF50633_GPIO
- tristate "Support for NXP PCF50633 GPIO"
- depends on MFD_PCF50633
- help
- Say yes here if you want to include support GPIO for pins on
- the PCF50633 chip.
-
config AB3100_CORE
tristate "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5272b0451f0..f30cede74c2 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -48,6 +48,5 @@ obj-$(CONFIG_PMIC_DA903X) += da903x.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
-obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index 41ac3a52df1..f41c1a38935 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -454,7 +454,7 @@ static irqreturn_t pcf50633_irq(int irq, void *data)
static void
pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
- struct platform_device **pdev)
+ struct platform_device **pdev)
{
int ret;
@@ -621,7 +621,8 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
&pcf->adc_pdev);
pcf50633_client_dev_register(pcf, "pcf50633-backlight",
&pcf->bl_pdev);
-
+ pcf50633_client_dev_register(pcf, "pcf50633-gpio",
+ &pcf->gpio_pdev);
for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
struct platform_device *pdev;
@@ -647,9 +648,9 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
if (ret)
dev_info(pcf->dev, "Failed to create sysfs entries\n");
-
- if (pdata->probe_done)
- pdata->probe_done(pcf);
+
+ if (pcf->pdata->probe_done)
+ pcf->pdata->probe_done(pcf);
return 0;
@@ -670,6 +671,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
free_irq(pcf->irq, pcf);
destroy_workqueue(pcf->work_queue);
+ platform_device_unregister(pcf->gpio_pdev);
platform_device_unregister(pcf->input_pdev);
platform_device_unregister(pcf->rtc_pdev);
platform_device_unregister(pcf->mbc_pdev);
diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c
deleted file mode 100644
index 9ab19a8f669..00000000000
--- a/drivers/mfd/pcf50633-gpio.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* NXP PCF50633 GPIO Driver
- *
- * (C) 2006-2008 by Openmoko, Inc.
- * Author: Balaji Rao <balajirrao@openmoko.org>
- * All rights reserved.
- *
- * Broken down from monstrous PCF50633 driver mainly by
- * Harald Welte, Andy Green and Werner Almesberger
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/gpio.h>
-
-enum pcf50633_regulator_id {
- PCF50633_REGULATOR_AUTO,
- PCF50633_REGULATOR_DOWN1,
- PCF50633_REGULATOR_DOWN2,
- PCF50633_REGULATOR_LDO1,
- PCF50633_REGULATOR_LDO2,
- PCF50633_REGULATOR_LDO3,
- PCF50633_REGULATOR_LDO4,
- PCF50633_REGULATOR_LDO5,
- PCF50633_REGULATOR_LDO6,
- PCF50633_REGULATOR_HCLDO,
- PCF50633_REGULATOR_MEMLDO,
-};
-
-#define PCF50633_REG_AUTOOUT 0x1a
-#define PCF50633_REG_DOWN1OUT 0x1e
-#define PCF50633_REG_DOWN2OUT 0x22
-#define PCF50633_REG_MEMLDOOUT 0x26
-#define PCF50633_REG_LDO1OUT 0x2d
-#define PCF50633_REG_LDO2OUT 0x2f
-#define PCF50633_REG_LDO3OUT 0x31
-#define PCF50633_REG_LDO4OUT 0x33
-#define PCF50633_REG_LDO5OUT 0x35
-#define PCF50633_REG_LDO6OUT 0x37
-#define PCF50633_REG_HCLDOOUT 0x39
-
-static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
- [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
- [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT,
- [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT,
- [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT,
- [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT,
- [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT,
- [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT,
- [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT,
- [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT,
- [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT,
- [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT,
-};
-
-int pcf50633_gpio_set(struct pcf50633 *pcf, int gpio, u8 val)
-{
- u8 reg;
-
- reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
-
- return pcf50633_reg_set_bit_mask(pcf, reg, 0x07, val);
-}
-EXPORT_SYMBOL_GPL(pcf50633_gpio_set);
-
-u8 pcf50633_gpio_get(struct pcf50633 *pcf, int gpio)
-{
- u8 reg, val;
-
- reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
- val = pcf50633_reg_read(pcf, reg) & 0x07;
-
- return val;
-}
-EXPORT_SYMBOL_GPL(pcf50633_gpio_get);
-
-int pcf50633_gpio_invert_set(struct pcf50633 *pcf, int gpio, int invert)
-{
- u8 val, reg;
-
- reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
- val = !!invert << 3;
-
- return pcf50633_reg_set_bit_mask(pcf, reg, 1 << 3, val);
-}
-EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_set);
-
-int pcf50633_gpio_invert_get(struct pcf50633 *pcf, int gpio)
-{
- u8 reg, val;
-
- reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
- val = pcf50633_reg_read(pcf, reg);
-
- return val & (1 << 3);
-}
-EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_get);
-
-int pcf50633_gpio_power_supply_set(struct pcf50633 *pcf,
- int gpio, int regulator, int on)
-{
- u8 reg, val, mask;
-
- /* the *ENA register is always one after the *OUT register */
- reg = pcf50633_regulator_registers[regulator] + 1;
-
- val = !!on << (gpio - PCF50633_GPIO1);
- mask = 1 << (gpio - PCF50633_GPIO1);
-
- return pcf50633_reg_set_bit_mask(pcf, reg, mask, val);
-}
-EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set);
-
-MODULE_LICENSE("GPL");