lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Tue, 9 Jul 2013 14:16:56 +0200
From:	Florian Lobmaier <Florian.Lobmaier@....com>
To:	Lee Jones <lee.jones@...aro.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
CC:	"sameo@...ux.intel.com" <sameo@...ux.intel.com>
Subject: RE: [PATCH 01/07] mfd patch of ams AS3722 PMIC against linux_3.8.8

Hello,

thanks for the inputs. Please see the updated mfd driver patch attached. Hopefully the format of the patches is correct now. It is stated the old way in Documentation/SubmittingPatches, section 1. May I ask the question on how to send multiple patches correctly (mfd driver, regulator, gpio, etc.)?

Signed-off-by: Florian Lobmaier <florian.lobmaier@....com>

---
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ff553ba..138acb6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -516,6 +516,21 @@ config MFD_LP8788
          TI LP8788 PMU supports regulators, battery charger, RTC,
          ADC, backlight driver and current sinks.

+config MFD_AS3722
+       tristate "Support for ams AS3722 PMIC"
+       select MFD_CORE
+       select REGMAP_I2C
+       select REGMAP_IRQ
+       depends on I2C=y
+       help
+         Core support for the ams AS3722 PMIC. Additional
+         drivers must be enabled in order to use the functionality of the
+         device.
+         Related drivers are:
+               * ams AS3722 PMIC regulators
+               * ams AS3722 GPIO
+               * ams AS3722 RTC
+
 config MFD_MAX77686
        bool "Maxim Semiconductor MAX77686 PMIC Support"
        depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8b977f8..559779c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -148,3 +148,4 @@ obj-$(CONFIG_MFD_LM3533)    += lm3533-core.o lm3533-ctrlbank.o
 obj-$(CONFIG_VEXPRESS_CONFIG)  += vexpress-config.o vexpress-sysreg.o
 obj-$(CONFIG_MFD_RETU)         += retu-mfd.o
 obj-$(CONFIG_MFD_AS3711)       += as3711.o
+obj-$(CONFIG_MFD_AS3722)       += as3722-core.o as3722-regmap.o
diff --git a/drivers/mfd/as3722-core.c b/drivers/mfd/as3722-core.c
new file mode 100644
index 0000000..ddb39c7
--- /dev/null
+++ b/drivers/mfd/as3722-core.c
@@ -0,0 +1,747 @@
+/*
+ * as3722-core.c - core driver for AS3722 PMICs
+ *
+ * Copyright (C) 2013 ams AG
+ *
+ * Author: Florian Lobmaier <florian.lobmaier@....com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/as3722-reg.h>
+#include <linux/mfd/as3722-plat.h>
+
+enum as3722_ids {
+       AS3722_GPIO_ID,
+       AS3722_REGULATOR_ID,
+       AS3722_RTC_ID,
+       AS3722_WATCHDOG_ID,
+       AS3722_PWM_ID,
+};
+
+static const struct resource as3722_rtc_resource[] = {
+       {
+               .name = "as3722-rtc-alarm",
+               .start = AS3722_IRQ_RTC_ALARM,
+               .end = AS3722_IRQ_RTC_ALARM,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static const struct resource as3722_wdt_resource[] = {
+       {
+               .name = "as3722-watchdog-ping",
+               .start = AS3722_IRQ_WATCHDOG,
+               .end = AS3722_IRQ_WATCHDOG,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct mfd_cell as3722_devs[] = {
+       {
+               .name = "as3722-gpio",
+               .id = AS3722_GPIO_ID,
+       },
+       {
+               .name = "as3722-regulator",
+               .id = AS3722_REGULATOR_ID,
+       },
+       {
+               .name = "as3722-rtc",
+               .num_resources = ARRAY_SIZE(as3722_rtc_resource),
+               .resources = as3722_rtc_resource,
+               .id = AS3722_RTC_ID,
+       },
+       {
+               .name = "as3722-wdt",
+               .num_resources = ARRAY_SIZE(as3722_wdt_resource),
+               .resources = as3722_wdt_resource,
+               .id = AS3722_WATCHDOG_ID,
+       },
+       {
+               .name = "as3722-pwm",
+               .id = AS3722_PWM_ID,
+       },
+};
+
+static const struct regmap_irq as3722_irqs[] = {
+       /* INT1 IRQs */
+       [AS3722_IRQ_LID] = {
+               .mask = AS3722_IRQ_MASK_LID,
+       },
+       [AS3722_IRQ_ACOK] = {
+               .mask = AS3722_IRQ_MASK_ACOK,
+       },
+       [AS3722_IRQ_ENABLE1] = {
+               .mask = AS3722_IRQ_MASK_ENABLE1,
+       },
+       [AS3722_IRQ_SD0] = {
+               .mask = AS3722_IRQ_MASK_SD0,
+       },
+       [AS3722_IRQ_ONKEY_LONG] = {
+               .mask = AS3722_IRQ_MASK_ONKEY_LONG,
+       },
+       [AS3722_IRQ_ONKEY] = {
+               .mask = AS3722_IRQ_MASK_ONKEY,
+       },
+       [AS3722_IRQ_OVTMP] = {
+               .mask = AS3722_IRQ_MASK_OVTMP,
+       },
+       [AS3722_IRQ_LOWBAT] = {
+               .mask = AS3722_IRQ_MASK_LOWBAT,
+       },
+       [AS3722_IRQ_RTC_REP] = {
+               .mask = AS3722_IRQ_MASK_RTC_REP,
+               .reg_offset = 1,
+       },
+       [AS3722_IRQ_RTC_ALARM] = {
+               .mask = AS3722_IRQ_MASK_RTC_ALARM,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_WATCHDOG] = {
+               .mask = AS3722_IRQ_MASK_WATCHDOG,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_ADC] = {
+               .mask = AS3722_IRQ_MASK_ADC,
+               .reg_offset = 3,
+       },
+       [AS3722_IRQ_GPIO1] = {
+               .mask = AS3722_IRQ_MASK_GPIO1,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_GPIO2] = {
+               .mask = AS3722_IRQ_MASK_GPIO2,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_GPIO3] = {
+               .mask = AS3722_IRQ_MASK_GPIO3,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_GPIO4] = {
+               .mask = AS3722_IRQ_MASK_GPIO4,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_GPIO5] = {
+               .mask = AS3722_IRQ_MASK_GPIO5,
+               .reg_offset = 2,
+       },
+       [AS3722_IRQ_TEMP_SD0_SHUTDOWN] = {
+               .mask = AS3722_IRQ_MASK_TEMP_SD0_SHUTDOWN,
+               .reg_offset = 3,
+       },
+       [AS3722_IRQ_TEMP_SD1_SHUTDOWN] = {
+               .mask = AS3722_IRQ_MASK_TEMP_SD1_SHUTDOWN,
+               .reg_offset = 3,
+       },
+       [AS3722_IRQ_TEMP_SD6_SHUTDOWN] = {
+               .mask = AS3722_IRQ_MASK_TEMP_SD6_SHUTDOWN,
+               .reg_offset = 3,
+       },
+       [AS3722_IRQ_TEMP_SD0_ALARM] = {
+               .mask = AS3722_IRQ_MASK_TEMP_SD0_ALARM,
+               .reg_offset = 3,
+       },
+       [AS3722_IRQ_TEMP_SD1_ALARM] = {
+               .mask = AS3722_IRQ_MASK_TEMP_SD1_ALARM,
+               .reg_offset = 3,
+       },
+       [AS3722_IRQ_TEMP_SD6_ALARM] = {
+               .mask = AS3722_IRQ_MASK_TEMP_SD6_ALARM,
+               .reg_offset = 3,
+       },
+};
+
+static struct regmap_irq_chip as3722_irq_chip = {
+       .name = "as3722",
+       .irqs = as3722_irqs,
+       .num_irqs = ARRAY_SIZE(as3722_irqs),
+       .num_regs = 4,
+       .status_base = AS3722_INTERRUPTSTATUS1_REG,
+       .mask_base = AS3722_INTERRUPTMASK1_REG,
+       .wake_base = 1,
+};
+
+static void as3722_reg_init(struct as3722 *as3722,
+               struct as3722_reg_init *reg_data)
+{
+       int ret;
+
+       while (reg_data->reg != AS3722_REG_INIT_TERMINATE) {
+               ret = as3722_reg_write(as3722, reg_data->reg, reg_data->val);
+               if (ret) {
+                       dev_err(as3722->dev,
+                                       "reg setup failed: %d\n", ret);
+                       return;
+               }
+               reg_data++;
+       }
+}
+
+int as3722_read_adc(struct as3722 *as3722,
+               enum as3722_adc_channel channel,
+               enum as3722_adc_source source,
+               enum as3722_adc_voltange_range voltage_range)
+{
+       int result = 0;
+       unsigned int try_counter = 0;
+       u32 val;
+
+       mutex_lock(&as3722->adc_mutex);
+       /* select source */
+       as3722_set_bits(as3722,
+                       AS3722_ADC0_CONTROL_REG + channel,
+                       AS3722_ADC_MASK_SOURCE_SELECT,
+                       source);
+       /* select voltage range */
+       as3722_set_bits(as3722,
+                       AS3722_ADC0_CONTROL_REG + channel,
+                       AS3722_ADC_MASK_VOLTAGE_RANGE,
+                       voltage_range << AS3722_ADC_SHIFT_VOLTAGE_RANGE);
+       /* start conversion */
+       as3722_set_bits(as3722,
+                       AS3722_ADC0_CONTROL_REG + channel,
+                       AS3722_ADC_MASK_CONV_START,
+                       AS3722_ADC_BIT_CONV_START);
+
+       /*
+        * check if result ready
+        * as no HW interrupt is available we have to poll
+        * the status bit. The result is available on the next I2C read
+        * at 400kHz I2C speed, so no threaded polling required.
+        */
+       try_counter = 0;
+       do {
+               /* 2*channel for correct channel nr.1 read offset */
+               as3722_reg_read(as3722,
+                               AS3722_ADC0_MSB_RESULT_REG + 2*channel,
+                               &val);
+               /* check if conversion is ready */
+               if ((val & AS3722_ADC_MASK_CONV_NOTREADY)
+                    != AS3722_ADC_BIT_CONV_NOTREADY
+                  )
+                       break;  /* conversion ready */
+               /*
+                * if not, we try  max. 10 times which ensures
+                * that it works up to 4MHz I2C speed and that
+                * we stop if something goes wrong
+                */
+               try_counter++;
+       } while (try_counter < 10);
+
+       /* read result, MSB byte already available from last read */
+       result = ((val & AS3722_ADC_MASK_MSB_VAL) << 8);
+       as3722_reg_read(as3722,
+                       AS3722_ADC0_LSB_RESULT_REG + 2*channel,
+                       &val);
+       result += (val & AS3722_ADC_MASK_LSB_VAL);
+
+       mutex_unlock(&as3722->adc_mutex);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(as3722_read_adc);
+
+static irqreturn_t as3722_onkey_press_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 ONKEY pressed\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_onkey_lpress_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 ONKEY long pressed\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_temp_sd0_shutdown_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 temp SD0 shutdown triggered\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_temp_sd1_shutdown_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 temp SD1 shutdown triggered\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_temp_sd6_shutdown_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 temp SD6 shutdown triggered\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_temp_sd0_alarm_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 temp SD0 alarm triggered\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_temp_sd1_alarm_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 temp SD1 alarm triggered\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_temp_sd6_alarm_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 temp SD6 alarm triggered\n");
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t as3722_ovtmp_alarm_irq(int irq, void *irq_data)
+{
+       struct as3722 *as3722 = irq_data;
+
+       dev_dbg(as3722->dev, "AS3722 ovtmp alarm triggered\n");
+       return IRQ_HANDLED;
+}
+
+static int as3722_init(struct as3722 *as3722,
+               struct as3722_platform_data *pdata, int irq)
+{
+       u32 reg;
+       int ret;
+       int irq_onkey, irq_onkeylong;
+       int irq_temp_sd0_shutdown, irq_temp_sd1_shutdown, irq_temp_sd6_shutdown;
+       int irq_temp_sd0_alarm, irq_temp_sd1_alarm, irq_temp_sd6_alarm;
+       int irq_ovtmp_alarm;
+
+       /* Check that this is actually a AS3722 */
+       ret = regmap_read(as3722->regmap, AS3722_ADDR_ASIC_ID1, &reg);
+       if (ret != 0) {
+               dev_err(as3722->dev,
+                       "Chip ID register read failed\n");
+               return ret;
+       }
+       if (reg != AS3722_DEVICE_ID) {
+               dev_err(as3722->dev,
+                       "Device is not an AS3722, ID is 0x%x\n",
+                       reg);
+               return -ENODEV;
+       }
+
+       ret = regmap_read(as3722->regmap, AS3722_ADDR_ASIC_ID2, &reg);
+       if (ret != 0) {
+               dev_err(as3722->dev,
+                       "ID2 register read failed: %d\n",
+                       ret);
+               return ret;
+       }
+       dev_info(as3722->dev, "AS3722 with revision %x found\n", reg);
+
+       /* init adc mutex */
+       mutex_init(&as3722->adc_mutex);
+
+       /* request irqs for onkey and over temperature */
+       if (as3722->irq_data) {
+               irq_onkey = regmap_irq_get_virq(as3722->irq_data,
+                                               AS3722_IRQ_ONKEY);
+               ret = request_threaded_irq(irq_onkey,
+                                          NULL,
+                                          as3722_onkey_press_irq,
+                                          pdata->irq_type,
+                                          "onkey-press",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request ONKEY IRQ: %d\n",
+                                ret);
+
+               irq_onkeylong = regmap_irq_get_virq(as3722->irq_data,
+                                                   AS3722_IRQ_ONKEY_LONG);
+               ret = request_threaded_irq(irq_onkeylong,
+                                          NULL,
+                                          as3722_onkey_lpress_irq,
+                                          pdata->irq_type,
+                                          "onkey-lpress",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request ONKEY_LONG IRQ: %d\n",
+                                ret);
+
+               irq_temp_sd0_shutdown =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_TEMP_SD0_SHUTDOWN);
+               ret = request_threaded_irq(irq_temp_sd0_shutdown,
+                                          NULL,
+                                          as3722_temp_sd0_shutdown_irq,
+                                          pdata->irq_type,
+                                          "temp sd0 shutdown",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request temp sd0 shutdown IRQ:"
+                                " %d\n",
+                                ret);
+               irq_temp_sd1_shutdown =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_TEMP_SD1_SHUTDOWN);
+               ret = request_threaded_irq(irq_temp_sd1_shutdown,
+                                          NULL,
+                                          as3722_temp_sd1_shutdown_irq,
+                                          pdata->irq_type,
+                                          "temp sd1 shutdown",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request temp sd1 shutdown IRQ:"
+                                " %d\n",
+                                ret);
+               irq_temp_sd6_shutdown =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_TEMP_SD6_SHUTDOWN);
+               ret = request_threaded_irq(irq_temp_sd6_shutdown,
+                                          NULL,
+                                          as3722_temp_sd6_shutdown_irq,
+                                          pdata->irq_type,
+                                          "temp sd6 shutdown",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request temp sd6 shutdown IRQ:"
+                                " %d\n",
+                                ret);
+               irq_temp_sd0_alarm =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_TEMP_SD0_ALARM);
+               ret = request_threaded_irq(irq_temp_sd0_alarm,
+                                          NULL,
+                                          as3722_temp_sd0_alarm_irq,
+                                          pdata->irq_type,
+                                          "temp sd0 alarm",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request temp sd0 alarm IRQ:"
+                                " %d\n",
+                                ret);
+
+               irq_temp_sd1_alarm =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_TEMP_SD1_ALARM);
+               ret = request_threaded_irq(irq_temp_sd1_alarm,
+                                          NULL,
+                                          as3722_temp_sd1_alarm_irq,
+                                          pdata->irq_type,
+                                          "temp sd1 alarm",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request temp sd1 alarm IRQ:"
+                                " %d\n",
+                                ret);
+               irq_temp_sd6_alarm =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_TEMP_SD6_ALARM);
+               ret = request_threaded_irq(irq_temp_sd6_alarm,
+                                          NULL,
+                                          as3722_temp_sd6_alarm_irq,
+                                          pdata->irq_type,
+                                          "temp sd6 alarm",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request temp sd6 alarm IRQ:"
+                                " %d\n",
+                                ret);
+
+               irq_ovtmp_alarm =
+                       regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_OVTMP);
+               ret = request_threaded_irq(irq_ovtmp_alarm,
+                                          NULL,
+                                          as3722_ovtmp_alarm_irq,
+                                          pdata->irq_type,
+                                          "ovtmp alarm",
+                                          as3722);
+               if (ret < 0)
+                       dev_warn(as3722->dev,
+                                "Failed to request ovtmp alarm IRQ:"
+                                " %d\n",
+                                ret);
+       }
+
+       /* do some initial platform register setup */
+       if (pdata->core_init_data)
+               as3722_reg_init(as3722, pdata->core_init_data);
+
+       /* initialise stby reg count variable, used in regulator */
+       as3722->reg_stby_counter = 0;
+
+       /* enable pullups if required */
+       if (pdata->use_internal_int_pullup == 1)
+               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
+                               AS3722_INT_PULLUP_MASK,
+                               AS3722_INT_PULLUP_ON);
+       else
+               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
+                               AS3722_INT_PULLUP_MASK,
+                               AS3722_INT_PULLUP_OFF);
+
+       if (pdata->use_internal_i2c_pullup)
+               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
+                               AS3722_I2C_PULLUP_MASK,
+                               AS3722_I2C_PULLUP_ON);
+       else
+               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
+                               AS3722_I2C_PULLUP_MASK,
+                               AS3722_I2C_PULLUP_OFF);
+
+       /* enable1 pin standby configuration */
+       if (pdata->enable1_deepsleep)
+               as3722_set_bits(as3722, AS3722_CTRL1_REG,
+                               AS3722_ENABLE1_DEEPSLEEP_MASK,
+                               AS3722_ENABLE1_DEEPSLEEP_ON);
+       else
+               as3722_set_bits(as3722, AS3722_CTRL1_REG,
+                               AS3722_ENABLE1_DEEPSLEEP_MASK,
+                               AS3722_ENABLE1_DEEPSLEEP_OFF);
+
+       if (pdata->enable1_invert)
+               as3722_set_bits(as3722, AS3722_CTRL1_REG,
+                               AS3722_ENABLE1_INVERT_MASK,
+                               AS3722_ENABLE1_INVERT_ON);
+       else
+               as3722_set_bits(as3722, AS3722_CTRL1_REG,
+                               AS3722_ENABLE1_INVERT_MASK,
+                               AS3722_ENABLE1_INVERT_OFF);
+
+       as3722_set_bits(as3722, AS3722_RESETTIMER_REG,
+                       AS3722_OFF_DELAY_MASK,
+                       pdata->off_delay << AS3722_OFF_DELAY_SHIFT);
+
+       /* thermal shutdown control */
+       as3722_set_bits(as3722, AS3722_OVERTEMPERATURE_CONTROL_REG,
+                       AS3722_OVTMP_MASK,
+                       pdata->mask_ovtemp << AS3722_OVTMP_SHIFT);
+
+       /* overcurrent/powergood configuration */
+       reg = (pdata->pg_sd6_vmask_time << AS3722_PG_SD6_VMASK_TIME_SHIFT)
+                       & AS3722_PG_SD6_VMASK_TIME_MASK;
+       reg |= (pdata->sd6_lv_deb_time << AS3722_SD6_LV_DEB_SHIFT)
+                       & AS3722_SD6_LV_DEB_MASK;
+       reg |= (pdata->sd1_lv_deb_time << AS3722_SD1_LV_DEB_SHIFT)
+                       & AS3722_SD1_LV_DEB_MASK;
+       reg |= (pdata->sd0_lv_deb_time << AS3722_SD0_LV_DEB_SHIFT)
+                       & AS3722_SD0_LV_DEB_MASK;
+       as3722_reg_write(as3722, AS3722_SD_LV_DEB_REG, reg);
+
+       reg = (pdata->pg_vresfall_mask << 7)
+                       & AS3722_PG_VRESFALL_MASK_MASK;
+       reg |= (pdata->pg_ovcurr_sd0_mask << 6)
+                       & AS3722_PG_OVCURR_SD0_MASK_MASK;
+       reg |= (pdata->pg_pwrgood_sd0_mask << 5)
+                       & AS3722_PG_PWRGOOD_SD0_MASK_MASK;
+       reg |= (pdata->pg_gpio5_mask << 4)
+                       & AS3722_PG_GPIO5_MASK_MASK;
+       reg |= (pdata->pg_gpio4_mask << 3)
+                       & AS3722_PG_GPIO4_MASK_MASK;
+       reg |= (pdata->pg_gpio3_mask << 2)
+                       & AS3722_PG_GPIO3_MASK_MASK;
+       reg |= (pdata->pg_ac_ok_mask << 1)
+                       & AS3722_PG_AC_OK_MASK_MASK;
+       reg |= (pdata->pg_ac_ok_inv)
+                       & AS3722_PG_AC_OK_INV_MASK;
+       as3722_reg_write(as3722, AS3722_OC_PG_CONTROL_REG, reg);
+
+       reg = (pdata->pg_ovcurr_sd6_mask << 7)
+                       & AS3722_PG_OVCURR_SD6_MASK_MASK;
+       reg |= (pdata->pg_pwrgood_sd6_mask << 6)
+                       & AS3722_PG_PWRGOOD_SD6_MASK_MASK;
+       reg |= (pdata->pg_sd6_ovc_alarm << 3)
+                       & AS3722_PG_SD6_OVC_ALARM_MASK;
+       reg |= (pdata->pg_sd0_vmask_time << 1)
+                       & AS3722_PG_SD0_VMASK_TIME_MASK;
+       reg |= (pdata->oc_pg_inv)
+                       & AS3722_OC_PG_INV_MASK;
+       as3722_reg_write(as3722, AS3722_OC_PG_CONTROL2_REG, reg);
+
+       /* enable 32kHz clock output if required */
+       if (pdata->enable_clk32out_pin)
+               as3722_set_bits(as3722, AS3722_RTC_CONTROL_REG,
+                               AS3722_CLK32OUT_ENABLE_MASK,
+                               AS3722_CLK32OUT_ENABLE_ON);
+       else
+               as3722_set_bits(as3722, AS3722_RTC_CONTROL_REG,
+                               AS3722_CLK32OUT_ENABLE_MASK,
+                               AS3722_CLK32OUT_ENABLE_OFF);
+       return 0;
+}
+
+static int as3722_i2c_probe(struct i2c_client *i2c,
+               const struct i2c_device_id *id)
+{
+       struct as3722 *as3722;
+       struct as3722_platform_data *pdata;
+       int irq_flags;
+       int ret;
+
+       pdata = dev_get_platdata(&i2c->dev);
+       if (!pdata) {
+               dev_err(&i2c->dev, "as3722 requires platform data\n");
+               return -EINVAL;
+       }
+
+       as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL);
+       if (!as3722)
+               return -ENOMEM;
+
+       as3722->dev = &i2c->dev;
+       as3722->chip_irq = i2c->irq;
+       i2c_set_clientdata(i2c, as3722);
+
+       as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config);
+       if (IS_ERR(as3722->regmap)) {
+               ret = PTR_ERR(as3722->regmap);
+               dev_err(&i2c->dev, "regmap_init failed with err: %d\n", ret);
+               return ret;
+       }
+
+       irq_flags = pdata->irq_type;
+       irq_flags |= IRQF_ONESHOT;
+       ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq,
+                       irq_flags, pdata->irq_base, &as3722_irq_chip,
+                       &as3722->irq_data);
+       if (ret < 0) {
+               dev_err(as3722->dev,
+                       "irq allocation failed for as3722 failed\n");
+               return ret;
+       }
+
+       ret = as3722_init(as3722, pdata, i2c->irq);
+       if (ret < 0)
+               return ret;
+
+       ret = mfd_add_devices(&i2c->dev,
+                             -1,
+                             as3722_devs,
+                             ARRAY_SIZE(as3722_devs),
+                             NULL,
+                             pdata->irq_base,
+                             regmap_irq_get_domain(as3722->irq_data));
+       if (ret) {
+               dev_err(as3722->dev,
+                       "add mfd devices failed with err: %d\n",
+                       ret);
+               return ret;
+       }
+
+       dev_info(as3722->dev,
+                "AS3722 core driver initialized successfully\n");
+
+       return 0;
+}
+
+static int as3722_i2c_remove(struct i2c_client *i2c)
+{
+       struct as3722 *as3722 = i2c_get_clientdata(i2c);
+       int irq_onkeylong, irq_onkey;
+       int irq_temp_sd0_shutdown, irq_temp_sd1_shutdown, irq_temp_sd6_shutdown;
+       int irq_temp_sd0_alarm, irq_temp_sd1_alarm, irq_temp_sd6_alarm;
+       int irq_ovtmp_alarm;
+
+       irq_onkeylong = regmap_irq_get_virq(as3722->irq_data,
+                                           AS3722_IRQ_ONKEY_LONG);
+       irq_onkey = regmap_irq_get_virq(as3722->irq_data, AS3722_IRQ_ONKEY);
+       irq_temp_sd0_shutdown =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_TEMP_SD0_SHUTDOWN);
+       irq_temp_sd1_shutdown =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_TEMP_SD1_SHUTDOWN);
+       irq_temp_sd6_shutdown =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_TEMP_SD6_SHUTDOWN);
+       irq_temp_sd0_alarm =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_TEMP_SD0_ALARM);
+       irq_temp_sd1_alarm =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_TEMP_SD1_ALARM);
+       irq_temp_sd6_alarm =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_TEMP_SD6_ALARM);
+       irq_ovtmp_alarm =
+               regmap_irq_get_virq(as3722->irq_data,
+                                   AS3722_IRQ_OVTMP);
+
+       free_irq(irq_onkeylong, as3722);
+       free_irq(irq_onkey, as3722);
+       free_irq(irq_temp_sd0_shutdown, as3722);
+       free_irq(irq_temp_sd1_shutdown, as3722);
+       free_irq(irq_temp_sd6_shutdown, as3722);
+       free_irq(irq_temp_sd0_alarm, as3722);
+       free_irq(irq_temp_sd1_alarm, as3722);
+       free_irq(irq_temp_sd6_alarm, as3722);
+       free_irq(irq_ovtmp_alarm, as3722);
+       mfd_remove_devices(as3722->dev);
+       regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
+
+       return 0;
+}
+
+static const struct i2c_device_id as3722_i2c_id[] = {
+       { "as3722", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
+
+static struct i2c_driver as3722_i2c_driver = {
+       .driver = {
+               .name = "as3722",
+               .owner = THIS_MODULE,
+       },
+       .probe = as3722_i2c_probe,
+       .remove = as3722_i2c_remove,
+       .id_table = as3722_i2c_id,
+};
+
+module_i2c_driver(as3722_i2c_driver);
+
+MODULE_DESCRIPTION("I2C, IRQ and ADC support for AS3722 PMICs");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@....com>");
diff --git a/drivers/mfd/as3722-regmap.c b/drivers/mfd/as3722-regmap.c
new file mode 100644
index 0000000..725722e
--- /dev/null
+++ b/drivers/mfd/as3722-regmap.c
@@ -0,0 +1,417 @@
+/*
+ * as3722-regmap.c - regmap for AS3722 PMICs
+ *
+ * Copyright (C) 2013 ams AG
+ *
+ * Author: Florian Lobmaier <florian.lobmaier@....com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/mfd/as3722-reg.h>
+
+/* Default Register Values (for caching)
+ * Please make sure to update (or update cache at startup)
+ * after device is OTP programmed! */
+static struct reg_default as3722_defaults[] = {
+       { 0x0000, 0x0000 }, /* SD0 Voltage */
+       { 0x0001, 0x0000 }, /* SD1 Voltage */
+       { 0x0002, 0x0000 }, /* SD2 Voltage */
+       { 0x0003, 0x0000 }, /* SD3 Voltage */
+       { 0x0004, 0x0000 }, /* SD4 Voltage */
+       { 0x0005, 0x0000 }, /* SD5 Voltage */
+       { 0x0006, 0x0000 }, /* SD6 Voltage */
+       { 0x0008, 0x0003 }, /* GPIO0 Control */
+       { 0x0009, 0x0003 }, /* GPIO1 Control */
+       { 0x000a, 0x0003 }, /* GPIO2 Control */
+       { 0x000b, 0x0003 }, /* GPIO3 Control */
+       { 0x000c, 0x0003 }, /* GPIO4 Control */
+       { 0x000d, 0x0003 }, /* GPIO5 Control */
+       { 0x000e, 0x0003 }, /* GPIO6 Control */
+       { 0x000f, 0x0003 }, /* GPIO7 Control */
+       { 0x0010, 0x0000 }, /* LDO0 Voltage */
+       { 0x0011, 0x0000 }, /* LDO1 Voltage */
+       { 0x0012, 0x0000 }, /* LDO2 Voltage */
+       { 0x0013, 0x0000 }, /* LDO3 Voltage */
+       { 0x0014, 0x0000 }, /* LDO4 Voltage */
+       { 0x0015, 0x0000 }, /* LDO5 Voltage */
+       { 0x0016, 0x0000 }, /* LDO6 Voltage */
+       { 0x0017, 0x0000 }, /* LDO7 Voltage */
+       { 0x0019, 0x0000 }, /* LDO9 Voltage */
+       { 0x001a, 0x0000 }, /* LDO10 Voltage */
+       { 0x001b, 0x0000 }, /* LDO11 Voltage */
+       { 0x001d, 0x0000 }, /* LDO3 Settings */
+       { 0x001e, 0x0000 }, /* GPIO deb1 */
+       { 0x001f, 0x0000 }, /* GPIO deb2 */
+       { 0x0020, 0x0000 }, /* GPIO Signal Out */
+       { 0x0021, 0x0000 }, /* GPIO Signal In */
+       { 0x0022, 0x0000 }, /* Reg_sequ_mod1 */
+       { 0x0023, 0x0000 }, /* Reg_sequ_mod2 */
+       { 0x0024, 0x0000 }, /* Reg_sequ_mod3 */
+       { 0x0027, 0x0000 }, /* SD_phsw_ctrl */
+       { 0x0028, 0x0000 }, /* SD_phsw_status */
+       { 0x0029, 0x0000 }, /* SD0 Control */
+       { 0x002a, 0x0001 }, /* SD1 Control */
+       { 0x002b, 0x0000 }, /* SDmph Control */
+       { 0x002c, 0x0000 }, /* SD23 Control */
+       { 0x002d, 0x0000 }, /* SD4 Control */
+       { 0x002e, 0x0000 }, /* SD5 Control */
+       { 0x002f, 0x0001 }, /* SD6 Control */
+       { 0x0030, 0x0000 }, /* SD_dvm */
+       { 0x0031, 0x0000 }, /* Resetreason */
+       { 0x0032, 0x0000 }, /* Battery Voltage Monitor */
+       { 0x0033, 0x0000 }, /* Startup Control */
+       { 0x0034, 0x0008 }, /* RestTimer */
+       { 0x0035, 0x0000 }, /* ReferenceControl */
+       { 0x0036, 0x0000 }, /* ResetControl */
+       { 0x0037, 0x0001 }, /* OvertemperatureControl */
+       { 0x0038, 0x0000 }, /* WatchdogControl */
+       { 0x0039, 0x0000 }, /* Reg_standby_mod1 */
+       { 0x003a, 0x0000 }, /* Reg_standby_mod2 */
+       { 0x003b, 0x0000 }, /* Reg_standby_mod3 */
+       { 0x003c, 0x0000 }, /* Enable Control 1 */
+       { 0x003d, 0x0000 }, /* Enable Control 2 */
+       { 0x003e, 0x0000 }, /* Enable Control 3 */
+       { 0x003f, 0x0000 }, /* Enable Control 4 */
+       { 0x0040, 0x0000 }, /* Enable Control 5 */
+       { 0x0041, 0x0000 }, /* PWM Control low */
+       { 0x0042, 0x0000 }, /* PWM Control high */
+       { 0x0046, 0x0000 }, /* Watchdog Timer */
+       { 0x0048, 0x0000 }, /* Watchdog Software Signal */
+       { 0x0049, 0x0000 }, /* IO Voltage */
+       { 0x004a, 0x0000 }, /* Battery_voltage_monitor2 */
+       { 0x004d, 0x007f }, /* SDcontrol */
+       { 0x004e, 0x00ff }, /* LDOcontrol0 */
+       { 0x004f, 0x000e }, /* LDOcontrol1 */
+       { 0x0050, 0x0000 }, /* SD0_protect */
+       { 0x0051, 0x0000 }, /* SD6_protect */
+       { 0x0052, 0x0000 }, /* PWM_vcontrol1 */
+       { 0x0053, 0x0000 }, /* PWM_vcontrol2 */
+       { 0x0054, 0x0000 }, /* PWM_vcontrol3 */
+       { 0x0055, 0x0000 }, /* PWM_vcontrol4 */
+       { 0x0057, 0x0040 }, /* BBcharger */
+       { 0x0058, 0x0000 }, /* CTRLsequ1 */
+       { 0x0059, 0x0000 }, /* CTRLsequ2 */
+       { 0x005a, 0x0000 }, /* OVcurrent */
+       { 0x005b, 0x0000 }, /* OVcurrent_deb */
+       { 0x005c, 0x0000 }, /* SDlv_deb */
+       { 0x005d, 0x0000 }, /* OC_pg_ctrl */
+       { 0x005e, 0x0000 }, /* OC_pg_ctrl2 */
+       { 0x005f, 0x0000 }, /* CTRLstatus */
+       { 0x0060, 0x0020 }, /* RTC Control */
+       { 0x0061, 0x0000 }, /* RTCsecond */
+       { 0x0062, 0x0000 }, /* RTCminute */
+       { 0x0063, 0x0000 }, /* RTChour */
+       { 0x0064, 0x0001 }, /* RTCday */
+       { 0x0065, 0x0001 }, /* RTCmonth */
+       { 0x0066, 0x0000 }, /* RTCyear */
+       { 0x0067, 0x0000 }, /* RTCAlarmsecond */
+       { 0x0068, 0x0000 }, /* RTCAlarmminute */
+       { 0x0069, 0x0000 }, /* RTCAlarmhour */
+       { 0x006a, 0x003f }, /* RTCAlarmday */
+       { 0x006b, 0x001f }, /* RTCAlarmmonth */
+       { 0x006c, 0x007f }, /* RTCAlarmyear */
+       { 0x006d, 0x0000 }, /* SRAM */
+       { 0x006f, 0x0000 }, /* RTC_Access */
+       { 0x0073, 0x0000 }, /* RegStatus */
+       { 0x0074, 0x00ff }, /* InterruptMask1 */
+       { 0x0075, 0x00ff }, /* InterruptMask2 */
+       { 0x0076, 0x00ff }, /* InterruptMask3 */
+       { 0x0077, 0x00ff }, /* InterruptMask4 */
+       { 0x0080, 0x0000 }, /* ADC0 Control */
+       { 0x0081, 0x0000 }, /* ADC1 Control */
+       { 0x0086, 0x007f }, /* ADC1 threshold hi MSB */
+       { 0x0087, 0x0007 }, /* ADC1 threshold hi LSB */
+       { 0x0088, 0x0000 }, /* ADC1 threshold lo MSB */
+       { 0x0089, 0x0000 }, /* ADC1 threshold lo LSB */
+       { 0x008a, 0x0000 }, /* ADC Configuration */
+};
+
+/*
+ * Access masks.
+ */
+static bool as3722_readable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AS3722_SD0_VOLTAGE_REG:
+       case AS3722_SD1_VOLTAGE_REG:
+       case AS3722_SD2_VOLTAGE_REG:
+       case AS3722_SD3_VOLTAGE_REG:
+       case AS3722_SD4_VOLTAGE_REG:
+       case AS3722_SD5_VOLTAGE_REG:
+       case AS3722_SD6_VOLTAGE_REG:
+       case AS3722_GPIO0_CONTROL_REG:
+       case AS3722_GPIO1_CONTROL_REG:
+       case AS3722_GPIO2_CONTROL_REG:
+       case AS3722_GPIO3_CONTROL_REG:
+       case AS3722_GPIO4_CONTROL_REG:
+       case AS3722_GPIO5_CONTROL_REG:
+       case AS3722_GPIO6_CONTROL_REG:
+       case AS3722_GPIO7_CONTROL_REG:
+       case AS3722_LDO0_VOLTAGE_REG:
+       case AS3722_LDO1_VOLTAGE_REG:
+       case AS3722_LDO2_VOLTAGE_REG:
+       case AS3722_LDO3_VOLTAGE_REG:
+       case AS3722_LDO4_VOLTAGE_REG:
+       case AS3722_LDO5_VOLTAGE_REG:
+       case AS3722_LDO6_VOLTAGE_REG:
+       case AS3722_LDO7_VOLTAGE_REG:
+       case AS3722_LDO9_VOLTAGE_REG:
+       case AS3722_LDO10_VOLTAGE_REG:
+       case AS3722_LDO11_VOLTAGE_REG:
+       case 0x1d:
+       case 0x1e:
+       case 0x1f:
+       case AS3722_GPIO_SIGNAL_OUT_REG:
+       case AS3722_GPIO_SIGNAL_IN_REG:
+       case 0x22:
+       case 0x23:
+       case 0x24:
+       case 0x27:
+       case 0x28:
+       case AS3722_SD0_CONTROL_REG:
+       case AS3722_SD1_CONTROL_REG:
+       case AS3722_SDmph_CONTROL_REG:
+       case AS3722_SD23_CONTROL_REG:
+       case AS3722_SD4_CONTROL_REG:
+       case AS3722_SD5_CONTROL_REG:
+       case AS3722_SD6_CONTROL_REG:
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case AS3722_WATCHDOG_CONTROL_REG:
+       case 0x39:
+       case 0x3a:
+       case 0x3b:
+       case 0x3c:
+       case 0x3d:
+       case 0x3e:
+       case 0x3f:
+       case 0x40:
+       case 0x41:
+       case 0x42:
+       case AS3722_WATCHDOG_TIMER_REG:
+       case AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG:
+       case AS3722_IOVOLTAGE_REG:
+       case 0x4a:
+       case AS3722_SD_CONTROL_REG:
+       case AS3722_LDOCONTROL0_REG:
+       case AS3722_LDOCONTROL1_REG:
+       case 0x50:
+       case 0x51:
+       case 0x52:
+       case 0x53:
+       case 0x54:
+       case 0x55:
+       case 0x57:
+       case AS3722_CTRL1_REG:
+       case AS3722_CTRL2_REG:
+       case 0x5a:
+       case 0x5b:
+       case 0x5c:
+       case 0x5d:
+       case 0x5e:
+       case 0x5f:
+       case AS3722_RTC_CONTROL_REG:
+       case AS3722_RTC_SECOND_REG:
+       case AS3722_RTC_MINUTE_REG:
+       case AS3722_RTC_HOUR_REG:
+       case AS3722_RTC_DAY_REG:
+       case AS3722_RTC_MONTH_REG:
+       case AS3722_RTC_YEAR_REG:
+       case AS3722_RTC_ALARM_SECOND_REG:
+       case AS3722_RTC_ALARM_MINUTE_REG:
+       case AS3722_RTC_ALARM_HOUR_REG:
+       case AS3722_RTC_ALARM_DAY_REG:
+       case AS3722_RTC_ALARM_MONTH_REG:
+       case AS3722_RTC_ALARM_YEAR_REG:
+       case 0x6d:
+       case 0x6f:
+       case 0x73:
+       case AS3722_INTERRUPTMASK1_REG:
+       case AS3722_INTERRUPTMASK2_REG:
+       case AS3722_INTERRUPTMASK3_REG:
+       case AS3722_INTERRUPTMASK4_REG:
+       case AS3722_INTERRUPTSTATUS1_REG:
+       case AS3722_INTERRUPTSTATUS2_REG:
+       case AS3722_INTERRUPTSTATUS3_REG:
+       case AS3722_INTERRUPTSTATUS4_REG:
+       case 0x7d:
+       case AS3722_ADC0_CONTROL_REG:
+       case AS3722_ADC1_CONTROL_REG:
+       case AS3722_ADC0_MSB_RESULT_REG:
+       case AS3722_ADC0_LSB_RESULT_REG:
+       case AS3722_ADC1_MSB_RESULT_REG:
+       case AS3722_ADC1_LSB_RESULT_REG:
+       case AS3722_ADC1_THRESHOLD_HI_MSB_REG:
+       case AS3722_ADC1_THRESHOLD_HI_LSB_REG:
+       case AS3722_ADC1_THRESHOLD_LO_MSB_REG:
+       case AS3722_ADC1_THRESHOLD_LO_LSB_REG:
+       case AS3722_ADC_CONFIG_REG:
+       case AS3722_ADDR_ASIC_ID1:
+       case AS3722_ADDR_ASIC_ID2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool as3722_writeable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AS3722_SD0_VOLTAGE_REG:
+       case AS3722_SD1_VOLTAGE_REG:
+       case AS3722_SD2_VOLTAGE_REG:
+       case AS3722_SD3_VOLTAGE_REG:
+       case AS3722_SD4_VOLTAGE_REG:
+       case AS3722_SD5_VOLTAGE_REG:
+       case AS3722_SD6_VOLTAGE_REG:
+       case AS3722_GPIO0_CONTROL_REG:
+       case AS3722_GPIO1_CONTROL_REG:
+       case AS3722_GPIO2_CONTROL_REG:
+       case AS3722_GPIO3_CONTROL_REG:
+       case AS3722_GPIO4_CONTROL_REG:
+       case AS3722_GPIO5_CONTROL_REG:
+       case AS3722_GPIO6_CONTROL_REG:
+       case AS3722_GPIO7_CONTROL_REG:
+       case AS3722_LDO0_VOLTAGE_REG:
+       case AS3722_LDO1_VOLTAGE_REG:
+       case AS3722_LDO2_VOLTAGE_REG:
+       case AS3722_LDO3_VOLTAGE_REG:
+       case AS3722_LDO4_VOLTAGE_REG:
+       case AS3722_LDO5_VOLTAGE_REG:
+       case AS3722_LDO6_VOLTAGE_REG:
+       case AS3722_LDO7_VOLTAGE_REG:
+       case AS3722_LDO9_VOLTAGE_REG:
+       case AS3722_LDO10_VOLTAGE_REG:
+       case AS3722_LDO11_VOLTAGE_REG:
+       case 0x1d:
+       case 0x1e:
+       case 0x1f:
+       case AS3722_GPIO_SIGNAL_OUT_REG:
+       case 0x22:
+       case 0x23:
+       case 0x24:
+       case 0x27:
+       case 0x28:
+       case AS3722_SD0_CONTROL_REG:
+       case AS3722_SD1_CONTROL_REG:
+       case AS3722_SDmph_CONTROL_REG:
+       case AS3722_SD23_CONTROL_REG:
+       case AS3722_SD4_CONTROL_REG:
+       case AS3722_SD5_CONTROL_REG:
+       case AS3722_SD6_CONTROL_REG:
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case AS3722_WATCHDOG_CONTROL_REG:
+       case 0x39:
+       case 0x3a:
+       case 0x3b:
+       case 0x3c:
+       case 0x3d:
+       case 0x3e:
+       case 0x3f:
+       case 0x40:
+       case 0x41:
+       case 0x42:
+       case AS3722_WATCHDOG_TIMER_REG:
+       case AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG:
+       case AS3722_IOVOLTAGE_REG:
+       case 0x4a:
+       case AS3722_SD_CONTROL_REG:
+       case AS3722_LDOCONTROL0_REG:
+       case AS3722_LDOCONTROL1_REG:
+       case 0x50:
+       case 0x51:
+       case 0x52:
+       case 0x53:
+       case 0x54:
+       case 0x55:
+       case 0x57:
+       case AS3722_CTRL1_REG:
+       case AS3722_CTRL2_REG:
+       case 0x5a:
+       case 0x5b:
+       case 0x5c:
+       case 0x5d:
+       case 0x5e:
+       case AS3722_RTC_CONTROL_REG:
+       case AS3722_RTC_SECOND_REG:
+       case AS3722_RTC_MINUTE_REG:
+       case AS3722_RTC_HOUR_REG:
+       case AS3722_RTC_DAY_REG:
+       case AS3722_RTC_MONTH_REG:
+       case AS3722_RTC_YEAR_REG:
+       case AS3722_RTC_ALARM_SECOND_REG:
+       case AS3722_RTC_ALARM_MINUTE_REG:
+       case AS3722_RTC_ALARM_HOUR_REG:
+       case AS3722_RTC_ALARM_DAY_REG:
+       case AS3722_RTC_ALARM_MONTH_REG:
+       case AS3722_RTC_ALARM_YEAR_REG:
+       case 0x6d:
+       case 0x6f:
+       case AS3722_INTERRUPTMASK1_REG:
+       case AS3722_INTERRUPTMASK2_REG:
+       case AS3722_INTERRUPTMASK3_REG:
+       case AS3722_INTERRUPTMASK4_REG:
+       case AS3722_INTERRUPTSTATUS1_REG:
+       case AS3722_INTERRUPTSTATUS2_REG:
+       case AS3722_INTERRUPTSTATUS3_REG:
+       case AS3722_INTERRUPTSTATUS4_REG:
+       case 0x7d:
+       case AS3722_ADC0_CONTROL_REG:
+       case AS3722_ADC1_CONTROL_REG:
+       case AS3722_ADC1_THRESHOLD_HI_MSB_REG:
+       case AS3722_ADC1_THRESHOLD_HI_LSB_REG:
+       case AS3722_ADC1_THRESHOLD_LO_MSB_REG:
+       case AS3722_ADC1_THRESHOLD_LO_LSB_REG:
+       case AS3722_ADC_CONFIG_REG:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool as3722_volatile(struct device *dev, unsigned int reg)
+{
+       return false;
+}
+
+const struct regmap_config as3722_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .max_register = AS3722_REGISTER_COUNT,
+       .readable_reg = as3722_readable,
+       .writeable_reg = as3722_writeable,
+       .volatile_reg = as3722_volatile,
+
+       .reg_defaults = as3722_defaults,
+       .num_reg_defaults = ARRAY_SIZE(as3722_defaults),
+};

---

-----Original Message-----
From: Lee Jones [mailto:lee.jones@...aro.org]
Sent: Donnerstag, 23. Mai 2013 16:22
To: Florian Lobmaier
Cc: sameo@...ux.intel.com; linux-kernel@...r.kernel.org
Subject: Re: [PATCH 01/07] mfd patch of ams AS3722 PMIC against linux_3.8.8

On Thu, 23 May 2013, Florian Lobmaier wrote:

> From: Florian Lobmaier <florian.lobmaier@....com>
>
> Added multi-function device driver support for ams AS3722 PMIC
> Includes modules gpio, regulator, rtc, and watchdog
>
> Signed-off-by: Florian Lobmaier <florian.lobmaier@....com>
>
> ---
> diff -uprN -X Documentation/dontdiff ../kernel_3.8.8/linux-kernel/drivers/mfd/as3722-core.c ./drivers/mfd/as3722-core.c
> --- ../kernel_3.8.8/linux-kernel/drivers/mfd/as3722-core.c      1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/mfd/as3722-core.c 2013-05-23 13:12:36.000000000 +0200
> @@ -0,0 +1,514 @@

Eh? Can you use Git to format your patches?

> +/*
> + * as3722-core.c - core driver for AS3722 PMICs
> + *
> + * Copyright (C) 2013 ams AG
> + *
> + * Author: Florian Lobmaier <florian.lobmaier@....com>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> +02111-1307 USA
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/regmap.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/core.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/as3722-reg.h>
> +#include <linux/mfd/as3722-plat.h>
> +
> +#define AS3722_DRIVER_VERSION  "v0.9.2"

Are you sure you want this in the upstream version?

> +enum as3722_ids {
> +       AS3722_GPIO_ID,
> +       AS3722_REGULATOR_ID,
> +       AS3722_RTC_ID,
> +       AS3722_WATCHDOG_ID,
> +};
> +
> +static const struct resource as3722_rtc_resource[] = {
> +       {
> +               .name = "as3722-rtc-alarm",
> +               .start = AS3722_IRQ_RTC_ALARM,
> +               .end = AS3722_IRQ_RTC_ALARM,
> +               .flags = IORESOURCE_IRQ,
> +       },
> +};
> +
> +static const struct resource as3722_wdt_resource[] = {
> +       {
> +               .name = "as3722-watchdog-irq",

Drop the -irq.

> +               .start = AS3722_IRQ_WATCHDOG,
> +               .end = AS3722_IRQ_WATCHDOG,
> +               .flags = IORESOURCE_IRQ,
> +       },
> +};
> +
> +static struct mfd_cell as3722_devs[] = {
> +       {
> +               .name = "as3722-gpio",
> +               .id = AS3722_GPIO_ID,
> +       },
> +       {
> +               .name = "as3722-regulator",
> +               .id = AS3722_REGULATOR_ID,
> +       },
> +       {
> +               .name = "as3722-rtc",
> +               .num_resources = ARRAY_SIZE(as3722_rtc_resource),
> +               .resources = as3722_rtc_resource,
> +               .id = AS3722_RTC_ID,
> +       },
> +       {
> +               .name = "as3722-wdt",
> +               .num_resources = ARRAY_SIZE(as3722_wdt_resource),
> +               .resources = as3722_wdt_resource,
> +               .id = AS3722_WATCHDOG_ID,
> +       },
> +};
> +
> +static const struct regmap_irq as3722_irqs[] = {
> +       /* INT1 IRQs */
> +       [AS3722_IRQ_LID] = {
> +               .mask = AS3722_IRQ_MASK_LID,
> +       },
> +       [AS3722_IRQ_ACOK] = {
> +               .mask = AS3722_IRQ_MASK_ACOK,
> +       },
> +       [AS3722_IRQ_ENABLE1] = {
> +               .mask = AS3722_IRQ_MASK_ENABLE1,
> +       },
> +       [AS3722_IRQ_SD0] = {
> +               .mask = AS3722_IRQ_MASK_SD0,
> +       },
> +       [AS3722_IRQ_ONKEY_LONG] = {
> +               .mask = AS3722_IRQ_MASK_ONKEY_LONG,
> +       },
> +       [AS3722_IRQ_ONKEY] = {
> +               .mask = AS3722_IRQ_MASK_ONKEY,
> +       },
> +       [AS3722_IRQ_OVTMP] = {
> +               .mask = AS3722_IRQ_MASK_OVTMP,
> +       },
> +       [AS3722_IRQ_LOWBAT] = {
> +               .mask = AS3722_IRQ_MASK_LOWBAT,
> +       },
> +       [AS3722_IRQ_RTC_REP] = {
> +               .mask = AS3722_IRQ_MASK_RTC_REP,
> +               .reg_offset = 1,
> +       },
> +       [AS3722_IRQ_RTC_ALARM] = {
> +               .mask = AS3722_IRQ_MASK_RTC_ALARM,
> +               .reg_offset = 2,
> +       },
> +       [AS3722_IRQ_WATCHDOG] = {
> +               .mask = AS3722_IRQ_MASK_WATCHDOG,
> +               .reg_offset = 2,
> +       },
> +       [AS3722_IRQ_ADC] = {
> +               .mask = AS3722_IRQ_MASK_ADC,
> +               .reg_offset = 3,
> +       },
> +       [AS3722_IRQ_GPIO1] = {
> +               .mask = AS3722_IRQ_MASK_GPIO1,
> +               .reg_offset = 2,
> +       },
> +       [AS3722_IRQ_GPIO2] = {
> +               .mask = AS3722_IRQ_MASK_GPIO2,
> +               .reg_offset = 2,
> +       },
> +       [AS3722_IRQ_GPIO3] = {
> +               .mask = AS3722_IRQ_MASK_GPIO3,
> +               .reg_offset = 2,
> +       },
> +       [AS3722_IRQ_GPIO4] = {
> +               .mask = AS3722_IRQ_MASK_GPIO4,
> +               .reg_offset = 2,
> +       },
> +       [AS3722_IRQ_GPIO5] = {
> +               .mask = AS3722_IRQ_MASK_GPIO5,
> +               .reg_offset = 2,
> +       },
> +};
> +
> +static struct regmap_irq_chip as3722_irq_chip = {
> +       .name = "as3722",
> +       .irqs = as3722_irqs,
> +       .num_irqs = ARRAY_SIZE(as3722_irqs),
> +       .num_regs = 4,
> +       .status_base = AS3722_INTERRUPTSTATUS1_REG,
> +       .mask_base = AS3722_INTERRUPTMASK1_REG,
> +       .wake_base = 1,
> +};
> +
> +static void as3722_reg_init(struct as3722 *as3722,
> +               struct as3722_reg_init *reg_data) {
> +       int ret;
> +
> +       while (reg_data->reg != AS3722_REG_INIT_TERMINATE) {
> +               ret = as3722_reg_write(as3722, reg_data->reg, reg_data->val);
> +               if (ret) {
> +                       dev_err(as3722->dev,
> +                                       "reg setup failed: %d\n", ret);
> +                       return;
> +               }
> +               reg_data++;
> +       }
> +}
> +
> +int as3722_read_adc(struct as3722 *as3722,
> +               enum as3722_adc_channel channel,
> +               enum as3722_adc_source source,
> +               enum as3722_adc_voltange_range voltage_range) {
> +       int result = 0;
> +       unsigned int try_counter = 0;
> +       u32 val;
> +
> +       mutex_lock(&as3722->adc_mutex);
> +       /* select source */
> +       as3722_set_bits(as3722,
> +                       AS3722_ADC0_CONTROL_REG + channel,
> +                       AS3722_ADC_MASK_SOURCE_SELECT,
> +                       source);
> +       /* select voltage range */
> +       as3722_set_bits(as3722,
> +                       AS3722_ADC0_CONTROL_REG + channel,
> +                       AS3722_ADC_MASK_VOLTAGE_RANGE,
> +                       voltage_range << AS3722_ADC_SHIFT_VOLTAGE_RANGE);
> +       /* start conversion */
> +       as3722_set_bits(as3722,
> +                       AS3722_ADC0_CONTROL_REG + channel,
> +                       AS3722_ADC_MASK_CONV_START,
> +                       AS3722_ADC_BIT_CONV_START);
> +
> +       /* check if result ready
> +        * as no HW interrupt is available for that we have to poll
> +        * the status bit. Should be available on the next I2C read
> +        * at 400kHz I2C speed, so no threaded polling required.
> +        */

Grammar is a bit all over the place in this comment.

Also, leave the top line blank:

The preferred style for long (multi-line) comments is:

        /*
         * This is the preferred style for multi-line
         * comments in the Linux kernel source code.
         * Please use it consistently.
         *
         * Description:  A column of asterisks on the left side,
         * with beginning and ending almost-blank lines.
         */

> +       try_counter = 0;
> +       do {
> +               as3722_reg_read(as3722,
> +                               AS3722_ADC0_MSB_RESULT_REG +
> + 2*channel,

Why 2*channel? Perhaps a small comment would be useful. Also stick some brackets in there to clear up the logic a little.

> +                               &val);
> +               try_counter++;
> +       } while (
> +               ((val & AS3722_ADC_MASK_CONV_NOTREADY)
> +                       == AS3722_ADC_BIT_CONV_NOTREADY)
> +               && (try_counter < 10)

Yuck! Can you find a better way to do this please?

Perhaps put the logic in the look and break out when you need to.

Why 10?

> +               );
> +
> +       /* read result, MSB byte already available from last read */
> +       result = ((val & AS3722_ADC_MASK_MSB_VAL) << 8);
> +       as3722_reg_read(as3722,
> +                       AS3722_ADC0_LSB_RESULT_REG + 2*channel,
> +                       &val);
> +       result += (val & AS3722_ADC_MASK_LSB_VAL);
> +
> +       mutex_unlock(&as3722->adc_mutex);
> +
> +       return result;
> +}
> +EXPORT_SYMBOL_GPL(as3722_read_adc);
> +
> +static irqreturn_t as3722_onkey_press_irq(int irq, void *irq_data) {
> +       struct as3722 *as3722 = irq_data;
> +
> +       dev_info(as3722->dev, "AS3722 ONKEY pressed\n");

I think this is debug is it not? dev_dbg() instead?

> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t as3722_onkey_lpress_irq(int irq, void *irq_data) {
> +       struct as3722 *as3722 = irq_data;
> +
> +       dev_info(as3722->dev, "AS3722 ONKEY long pressed\n");

As above.

> +       return IRQ_HANDLED;
> +}
> +
> +static int as3722_init(struct as3722 *as3722,
> +               struct as3722_platform_data *pdata, int irq) {
> +       u32 reg;
> +       int ret;
> +
> +       /* Check that this is actually a AS3722 */
> +       ret = regmap_read(as3722->regmap, AS3722_ADDR_ASIC_ID1, &reg);
> +       if (ret != 0) {

if (ret)

> +               dev_err(as3722->dev,
> +                               "Chip ID register read failed\n");

Your tabbing looks a little wild here.

> +               return -EIO;

Better to return ret?

> +       }
> +       if (reg != AS3722_DEVICE_ID) {
> +               dev_err(as3722->dev,
> +                               "Device is not an AS3722, ID is 0x%x\n"
> +                               , reg);

Tabbing again and a floating comma, which should be on the line above.

> +               return -ENODEV;
> +       }
> +
> +       ret = regmap_read(as3722->regmap, AS3722_ADDR_ASIC_ID2, &reg);
> +       if (ret < 0) {

Why is this different to the return error check of the regmap_read() above?

> +               dev_err(as3722->dev,
> +                               "ID2 register read failed: %d\n",
> + ret);

More wild tabbing.

> +               return ret;
> +       }
> +       dev_info(as3722->dev, "AS3722 with revision %x found\n",
> +                       reg);

Why is reg on a new line?

> +
> +       /* init adc mutex */
> +       mutex_init(&as3722->adc_mutex);
> +
> +       /* request irqs for onkey */
> +       if (as3722->irq_data) {
> +               ret = request_threaded_irq(regmap_irq_get_virq(
> +                                               as3722->irq_data,
> +                                               AS3722_IRQ_ONKEY),

This is pretty messy, can you break out the regmap_irq_get_virq() call?

> +                                               NULL, as3722_onkey_press_irq,
> +                                               pdata->irq_type,
> +                                               "onkey-press",
> + as3722);

More random tabbing. It would be better if you could align with the '('.

> +               if (ret < 0)
> +                       dev_warn(as3722->dev,
> +                               "Failed to request ONKEY IRQ: %d\n",
> + ret);

Nearly. :)

> +               ret = request_threaded_irq(regmap_irq_get_virq(
> +                                               as3722->irq_data,
> +
> + AS3722_IRQ_ONKEY_LONG),

Please break this out.

> +                                               NULL, as3722_onkey_lpress_irq,
> +                                               pdata->irq_type,
> +                                               "onkey-lpress", as3722);
> +               if (ret < 0)
> +                       dev_warn(as3722->dev,
> +                               "Failed to request ONKEY_LONG IRQ: %d\n",
> +                               ret);

So close...

> +       }
> +
> +       /* do some initial platform register setup */
> +       if (pdata->core_init_data)
> +               as3722_reg_init(as3722, pdata->core_init_data);
> +
> +       /* initialise stby reg count variable */
> +       as3722->reg_stby_counter = 0;

Where is this used?

> +
> +       /* enable pullups if required */
> +       if (pdata->use_internal_int_pullup == 1)

Is this a bool? If so, why not drop the " == 1"?

> +               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
> +                               AS3722_INT_PULLUP_MASK,
> +                               AS3722_INT_PULLUP_ON);
> +       else
> +               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
> +                               AS3722_INT_PULLUP_MASK,
> +                               AS3722_INT_PULLUP_OFF);

New line here for readability.

> +       if (pdata->use_internal_i2c_pullup == 1)

Is this a bool? If so, why not drop the " == 1"?

> +               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
> +                               AS3722_I2C_PULLUP_MASK,
> +                               AS3722_I2C_PULLUP_ON);
> +       else
> +               as3722_set_bits(as3722, AS3722_IOVOLTAGE_REG,
> +                               AS3722_I2C_PULLUP_MASK,
> +                               AS3722_I2C_PULLUP_OFF);
> +
> +       /* enable1 pin standby configuration */
> +       if (pdata->enable1_deepsleep)
> +               as3722_set_bits(as3722, AS3722_CTRL1_REG,
> +                               AS3722_ENABLE1_DEEPSLEEP_MASK,
> +                               AS3722_ENABLE1_DEEPSLEEP_ON);
> +       else
> +               as3722_set_bits(as3722, AS3722_CTRL1_REG,
> +                               AS3722_ENABLE1_DEEPSLEEP_MASK,
> +                               AS3722_ENABLE1_DEEPSLEEP_OFF);

New line separator here.

> +       if (pdata->enable1_invert)
> +               as3722_set_bits(as3722, AS3722_CTRL1_REG,
> +                               AS3722_ENABLE1_INVERT_MASK,
> +                               AS3722_ENABLE1_INVERT_ON);
> +       else
> +               as3722_set_bits(as3722, AS3722_CTRL1_REG,
> +                               AS3722_ENABLE1_INVERT_MASK,
> +                               AS3722_ENABLE1_INVERT_OFF);

What about doing this instead:

        state = pdata->enable1_invert ? AS3722_ENABLE1_INVERT_ON :
                                        AS3722_ENABLE1_INVERT_OFF;

        as3722_set_bits(as3722, AS3722_CTRL1_REG,
                        AS3722_ENABLE1_INVERT_MASK,
                        state);


> +       as3722_set_bits(as3722, AS3722_RESETTIMER_REG,
> +                       AS3722_OFF_DELAY_MASK,
> +                       pdata->off_delay << AS3722_OFF_DELAY_SHIFT);
> +
> +       /* overcurrent/powergood configuration */
> +       reg = (pdata->pg_sd6_vmask_time << AS3722_PG_SD6_VMASK_TIME_SHIFT)
> +                       & AS3722_PG_SD6_VMASK_TIME_MASK;
> +       reg |= (pdata->sd6_lv_deb_time << AS3722_SD6_LV_DEB_SHIFT)
> +                       & AS3722_SD6_LV_DEB_MASK;
> +       reg |= (pdata->sd1_lv_deb_time << AS3722_SD1_LV_DEB_SHIFT)
> +                       & AS3722_SD1_LV_DEB_MASK;
> +       reg |= (pdata->sd0_lv_deb_time << AS3722_SD0_LV_DEB_SHIFT)
> +                       & AS3722_SD0_LV_DEB_MASK;
> +       as3722_reg_write(as3722, AS3722_SD_LV_DEB_REG, reg);
> +
> +       reg = (pdata->pg_vresfall_mask << 7)
> +                       & AS3722_PG_VRESFALL_MASK_MASK;
> +       reg |= (pdata->pg_ovcurr_sd0_mask << 6)
> +                       & AS3722_PG_OVCURR_SD0_MASK_MASK;
> +       reg |= (pdata->pg_pwrgood_sd0_mask << 5)
> +                       & AS3722_PG_PWRGOOD_SD0_MASK_MASK;
> +       reg |= (pdata->pg_gpio5_mask << 4)
> +                       & AS3722_PG_GPIO5_MASK_MASK;
> +       reg |= (pdata->pg_gpio4_mask << 3)
> +                       & AS3722_PG_GPIO4_MASK_MASK;
> +       reg |= (pdata->pg_gpio3_mask << 2)
> +                       & AS3722_PG_GPIO3_MASK_MASK;
> +       reg |= (pdata->pg_ac_ok_mask << 1)
> +                       & AS3722_PG_AC_OK_MASK_MASK;
> +       reg |= (pdata->pg_ac_ok_inv)
> +                       & AS3722_PG_AC_OK_INV_MASK;
> +       as3722_reg_write(as3722, AS3722_OC_PG_CONTROL_REG, reg);
> +
> +       reg = (pdata->pg_ovcurr_sd6_mask << 7)
> +                       & AS3722_PG_OVCURR_SD6_MASK_MASK;
> +       reg |= (pdata->pg_pwrgood_sd6_mask << 6)
> +                       & AS3722_PG_PWRGOOD_SD6_MASK_MASK;
> +       reg |= (pdata->pg_sd6_ovc_alarm << 3)
> +                       & AS3722_PG_SD6_OVC_ALARM_MASK;
> +       reg |= (pdata->pg_sd0_vmask_time << 1)
> +                       & AS3722_PG_SD0_VMASK_TIME_MASK;
> +       reg |= (pdata->oc_pg_inv)
> +                       & AS3722_OC_PG_INV_MASK;
> +       as3722_reg_write(as3722, AS3722_OC_PG_CONTROL2_REG, reg);
> +
> +       /* enable 32kHz clock output if required */
> +       if (pdata->enable_clk32out_pin == 1)

Is this a bool?

> +               as3722_set_bits(as3722, AS3722_RTC_CONTROL_REG,
> +                               AS3722_CLK32OUT_ENABLE_MASK,
> +                               AS3722_CLK32OUT_ENABLE_ON);
> +       else
> +               as3722_set_bits(as3722, AS3722_RTC_CONTROL_REG,
> +                               AS3722_CLK32OUT_ENABLE_MASK,
> +                               AS3722_CLK32OUT_ENABLE_OFF);

How about using the code I provided above for all of these?

> +       return 0;
> +}
> +
> +static int as3722_i2c_probe(struct i2c_client *i2c,
> +               const struct i2c_device_id *id) {
> +       struct as3722 *as3722;
> +       struct as3722_platform_data *pdata;
> +       int irq_flags;
> +       int ret;
> +
> +       pdata = dev_get_platdata(&i2c->dev);
> +       if (!pdata) {
> +               dev_err(&i2c->dev, "as3722 requires platform data\n");
> +               return -EINVAL;
> +       }
> +
> +       as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL);
> +       if (as3722 == NULL) {

How about: if (!as3722) {

> +               dev_err(&i2c->dev, "mem alloc for as3722 failed\n");

Do we really need to know if we've run out of memory? I'm sure it would be obvious. Just return -ENOMEM.

> +               return -ENOMEM;
> +       }
> +
> +       as3722->dev = &i2c->dev;
> +       as3722->chip_irq = i2c->irq;
> +       i2c_set_clientdata(i2c, as3722);
> +
> +       as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config);
> +       if (IS_ERR(as3722->regmap)) {
> +               ret = PTR_ERR(as3722->regmap);
> +               dev_err(&i2c->dev, "regmap_init failed with err: %d\n", ret);
> +               return ret;
> +       }
> +
> +       irq_flags = pdata->irq_type;
> +       irq_flags |= IRQF_ONESHOT;
> +       ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq,
> +                       irq_flags, pdata->irq_base, &as3722_irq_chip,
> +                       &as3722->irq_data);
> +       if (ret < 0) {
> +               dev_err(as3722->dev,
> +                               "irq allocation failed for as3722
> + failed\n");

Random tabbing.

Ah, I see, it's exactly 3 tabs.

I think it's better to align with something instead.

> +               return ret;
> +       }
> +
> +       ret = as3722_init(as3722, pdata, i2c->irq);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = mfd_add_devices(&i2c->dev, -1, as3722_devs,
> +                       ARRAY_SIZE(as3722_devs), NULL,
> +                       pdata->irq_base,
> +                       regmap_irq_get_domain(as3722->irq_data));

I'm just thinking aloud here, but what happens if
regmap_irq_get_domain() returns an error?

> +       if (ret) {
> +               dev_err(as3722->dev, "add mfd devices failed with err: %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       dev_info(as3722->dev,
> +                       "AS3722 core driver %s initialized successfully\n",
> +                       AS3722_DRIVER_VERSION);
> +
> +       return 0;
> +}
> +
> +static int as3722_i2c_remove(struct i2c_client *i2c) {
> +       struct as3722 *as3722 = i2c_get_clientdata(i2c);
> +
> +       free_irq(regmap_irq_get_virq(as3722->irq_data, AS3722_IRQ_ONKEY_LONG),
> +                       as3722);
> +       free_irq(regmap_irq_get_virq(as3722->irq_data, AS3722_IRQ_ONKEY),
> +                       as3722);

Wow, that's messy. Any chance you can break these out?

Even better, if you use devm_* you won't have to free them at all.

> +       mfd_remove_devices(as3722->dev);
> +       regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
> +
> +       return 0;
> +}
> +
> +static const struct i2c_device_id as3722_i2c_id[] = {
> +       {"as3722", 0},

Consider spaces before and after the '{}'s.

> +       {}
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
> +
> +static struct i2c_driver as3722_i2c_driver = {
> +       .driver = {
> +               .name = "as3722",
> +               .owner = THIS_MODULE,
> +       },
> +       .probe = as3722_i2c_probe,
> +       .remove = as3722_i2c_remove,
> +       .id_table = as3722_i2c_id,
> +};

From here:  -----------------------------------

> +static int __init as3722_i2c_init(void) {
> +       return i2c_add_driver(&as3722_i2c_driver);
> +}
> +
> +subsys_initcall(as3722_i2c_init);
> +
> +static void __exit as3722_i2c_exit(void) {
> +       i2c_del_driver(&as3722_i2c_driver);
> +}
> +
> +module_exit(as3722_i2c_exit);

To here:  -------------------------------------

Swap this out for: module_i2c_driver(as3722_i2c_driver);

> +MODULE_DESCRIPTION("I2C, IRQ and ADC support for AS3722 PMICs");
> +MODULE_LICENSE("GPL"); MODULE_AUTHOR("Florian Lobmaier
> +<florian.lobmaier@....com>");

> diff -uprN -X Documentation/dontdiff ../kernel_3.8.8/linux-kernel/drivers/mfd/as3722-regmap.c ./drivers/mfd/as3722-regmap.c
> --- ../kernel_3.8.8/linux-kernel/drivers/mfd/as3722-regmap.c    1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/mfd/as3722-regmap.c       2013-05-23 13:12:36.000000000 +0200
> @@ -0,0 +1,417 @@

Arghhhh, what is this? Please use Git.

> +/*
> + * as3722-regmap.c - regmap for AS3722 PMICs

This should really be seperate patch.

> + * Copyright (C) 2013 ams AG
> + *
> + * Author: Florian Lobmaier <florian.lobmaier@....com>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> + 02111-1307 USA
> + *
> + */
> +
> +#include <linux/mfd/as3722-reg.h>
> +
> +/* Default Register Values (for caching)
> + * Please make sure to update (or update cache at startup)
> + * after device is OTP programmed! */ static struct reg_default
> +as3722_defaults[] = {
> +       { 0x0000, 0x0000 }, /* SD0 Voltage */
> +       { 0x0001, 0x0000 }, /* SD1 Voltage */
> +       { 0x0002, 0x0000 }, /* SD2 Voltage */
> +       { 0x0003, 0x0000 }, /* SD3 Voltage */
> +       { 0x0004, 0x0000 }, /* SD4 Voltage */
> +       { 0x0005, 0x0000 }, /* SD5 Voltage */
> +       { 0x0006, 0x0000 }, /* SD6 Voltage */
> +       { 0x0008, 0x0003 }, /* GPIO0 Control */
> +       { 0x0009, 0x0003 }, /* GPIO1 Control */
> +       { 0x000a, 0x0003 }, /* GPIO2 Control */
> +       { 0x000b, 0x0003 }, /* GPIO3 Control */
> +       { 0x000c, 0x0003 }, /* GPIO4 Control */
> +       { 0x000d, 0x0003 }, /* GPIO5 Control */
> +       { 0x000e, 0x0003 }, /* GPIO6 Control */
> +       { 0x000f, 0x0003 }, /* GPIO7 Control */
> +       { 0x0010, 0x0000 }, /* LDO0 Voltage */
> +       { 0x0011, 0x0000 }, /* LDO1 Voltage */
> +       { 0x0012, 0x0000 }, /* LDO2 Voltage */
> +       { 0x0013, 0x0000 }, /* LDO3 Voltage */
> +       { 0x0014, 0x0000 }, /* LDO4 Voltage */
> +       { 0x0015, 0x0000 }, /* LDO5 Voltage */
> +       { 0x0016, 0x0000 }, /* LDO6 Voltage */
> +       { 0x0017, 0x0000 }, /* LDO7 Voltage */
> +       { 0x0019, 0x0000 }, /* LDO9 Voltage */
> +       { 0x001a, 0x0000 }, /* LDO10 Voltage */
> +       { 0x001b, 0x0000 }, /* LDO11 Voltage */
> +       { 0x001d, 0x0000 }, /* LDO3 Settings */
> +       { 0x001e, 0x0000 }, /* GPIO deb1 */
> +       { 0x001f, 0x0000 }, /* GPIO deb2 */
> +       { 0x0020, 0x0000 }, /* GPIO Signal Out */
> +       { 0x0021, 0x0000 }, /* GPIO Signal In */
> +       { 0x0022, 0x0000 }, /* Reg_sequ_mod1 */
> +       { 0x0023, 0x0000 }, /* Reg_sequ_mod2 */
> +       { 0x0024, 0x0000 }, /* Reg_sequ_mod3 */
> +       { 0x0027, 0x0000 }, /* SD_phsw_ctrl */
> +       { 0x0028, 0x0000 }, /* SD_phsw_status */
> +       { 0x0029, 0x0000 }, /* SD0 Control */
> +       { 0x002a, 0x0001 }, /* SD1 Control */
> +       { 0x002b, 0x0000 }, /* SDmph Control */
> +       { 0x002c, 0x0000 }, /* SD23 Control */
> +       { 0x002d, 0x0000 }, /* SD4 Control */
> +       { 0x002e, 0x0000 }, /* SD5 Control */
> +       { 0x002f, 0x0001 }, /* SD6 Control */
> +       { 0x0030, 0x0000 }, /* SD_dvm */
> +       { 0x0031, 0x0000 }, /* Resetreason */
> +       { 0x0032, 0x0000 }, /* Battery Voltage Monitor */
> +       { 0x0033, 0x0000 }, /* Startup Control */
> +       { 0x0034, 0x0008 }, /* RestTimer */
> +       { 0x0035, 0x0000 }, /* ReferenceControl */
> +       { 0x0036, 0x0000 }, /* ResetControl */
> +       { 0x0037, 0x0001 }, /* OvertemperatureControl */
> +       { 0x0038, 0x0000 }, /* WatchdogControl */
> +       { 0x0039, 0x0000 }, /* Reg_standby_mod1 */
> +       { 0x003a, 0x0000 }, /* Reg_standby_mod2 */
> +       { 0x003b, 0x0000 }, /* Reg_standby_mod3 */
> +       { 0x003c, 0x0000 }, /* Enable Control 1 */
> +       { 0x003d, 0x0000 }, /* Enable Control 2 */
> +       { 0x003e, 0x0000 }, /* Enable Control 3 */
> +       { 0x003f, 0x0000 }, /* Enable Control 4 */
> +       { 0x0040, 0x0000 }, /* Enable Control 5 */
> +       { 0x0041, 0x0000 }, /* PWM Control low */
> +       { 0x0042, 0x0000 }, /* PWM Control high */
> +       { 0x0046, 0x0000 }, /* Watchdog Timer */
> +       { 0x0048, 0x0000 }, /* Watchdog Software Signal */
> +       { 0x0049, 0x0000 }, /* IO Voltage */
> +       { 0x004a, 0x0000 }, /* Battery_voltage_monitor2 */
> +       { 0x004d, 0x007f }, /* SDcontrol */
> +       { 0x004e, 0x00ff }, /* LDOcontrol0 */
> +       { 0x004f, 0x000e }, /* LDOcontrol1 */
> +       { 0x0050, 0x0000 }, /* SD0_protect */
> +       { 0x0051, 0x0000 }, /* SD6_protect */
> +       { 0x0052, 0x0000 }, /* PWM_vcontrol1 */
> +       { 0x0053, 0x0000 }, /* PWM_vcontrol2 */
> +       { 0x0054, 0x0000 }, /* PWM_vcontrol3 */
> +       { 0x0055, 0x0000 }, /* PWM_vcontrol4 */
> +       { 0x0057, 0x0040 }, /* BBcharger */
> +       { 0x0058, 0x0000 }, /* CTRLsequ1 */
> +       { 0x0059, 0x0000 }, /* CTRLsequ2 */
> +       { 0x005a, 0x0000 }, /* OVcurrent */
> +       { 0x005b, 0x0000 }, /* OVcurrent_deb */
> +       { 0x005c, 0x0000 }, /* SDlv_deb */
> +       { 0x005d, 0x0000 }, /* OC_pg_ctrl */
> +       { 0x005e, 0x0000 }, /* OC_pg_ctrl2 */
> +       { 0x005f, 0x0000 }, /* CTRLstatus */
> +       { 0x0060, 0x0020 }, /* RTC Control */
> +       { 0x0061, 0x0000 }, /* RTCsecond */
> +       { 0x0062, 0x0000 }, /* RTCminute */
> +       { 0x0063, 0x0000 }, /* RTChour */
> +       { 0x0064, 0x0001 }, /* RTCday */
> +       { 0x0065, 0x0001 }, /* RTCmonth */
> +       { 0x0066, 0x0000 }, /* RTCyear */
> +       { 0x0067, 0x0000 }, /* RTCAlarmsecond */
> +       { 0x0068, 0x0000 }, /* RTCAlarmminute */
> +       { 0x0069, 0x0000 }, /* RTCAlarmhour */
> +       { 0x006a, 0x003f }, /* RTCAlarmday */
> +       { 0x006b, 0x001f }, /* RTCAlarmmonth */
> +       { 0x006c, 0x007f }, /* RTCAlarmyear */
> +       { 0x006d, 0x0000 }, /* SRAM */
> +       { 0x006f, 0x0000 }, /* RTC_Access */
> +       { 0x0073, 0x0000 }, /* RegStatus */
> +       { 0x0074, 0x00ff }, /* InterruptMask1 */
> +       { 0x0075, 0x00ff }, /* InterruptMask2 */
> +       { 0x0076, 0x00ff }, /* InterruptMask3 */
> +       { 0x0077, 0x00ff }, /* InterruptMask4 */
> +       { 0x0080, 0x0000 }, /* ADC0 Control */
> +       { 0x0081, 0x0000 }, /* ADC1 Control */
> +       { 0x0086, 0x007f }, /* ADC1 threshold hi MSB */
> +       { 0x0087, 0x0007 }, /* ADC1 threshold hi LSB */
> +       { 0x0088, 0x0000 }, /* ADC1 threshold lo MSB */
> +       { 0x0089, 0x0000 }, /* ADC1 threshold lo LSB */
> +       { 0x008a, 0x0000 }, /* ADC Configuration */ };
> +
> +/*
> + * Access masks.
> + */
> +static bool as3722_readable(struct device *dev, unsigned int reg) {
> +       switch (reg) {
> +       case AS3722_SD0_VOLTAGE_REG:
> +       case AS3722_SD1_VOLTAGE_REG:
> +       case AS3722_SD2_VOLTAGE_REG:
> +       case AS3722_SD3_VOLTAGE_REG:
> +       case AS3722_SD4_VOLTAGE_REG:
> +       case AS3722_SD5_VOLTAGE_REG:
> +       case AS3722_SD6_VOLTAGE_REG:
> +       case AS3722_GPIO0_CONTROL_REG:
> +       case AS3722_GPIO1_CONTROL_REG:
> +       case AS3722_GPIO2_CONTROL_REG:
> +       case AS3722_GPIO3_CONTROL_REG:
> +       case AS3722_GPIO4_CONTROL_REG:
> +       case AS3722_GPIO5_CONTROL_REG:
> +       case AS3722_GPIO6_CONTROL_REG:
> +       case AS3722_GPIO7_CONTROL_REG:
> +       case AS3722_LDO0_VOLTAGE_REG:
> +       case AS3722_LDO1_VOLTAGE_REG:
> +       case AS3722_LDO2_VOLTAGE_REG:
> +       case AS3722_LDO3_VOLTAGE_REG:
> +       case AS3722_LDO4_VOLTAGE_REG:
> +       case AS3722_LDO5_VOLTAGE_REG:
> +       case AS3722_LDO6_VOLTAGE_REG:
> +       case AS3722_LDO7_VOLTAGE_REG:
> +       case AS3722_LDO9_VOLTAGE_REG:
> +       case AS3722_LDO10_VOLTAGE_REG:
> +       case AS3722_LDO11_VOLTAGE_REG:
> +       case 0x1d:
> +       case 0x1e:
> +       case 0x1f:
> +       case AS3722_GPIO_SIGNAL_OUT_REG:
> +       case AS3722_GPIO_SIGNAL_IN_REG:
> +       case 0x22:
> +       case 0x23:
> +       case 0x24:
> +       case 0x27:
> +       case 0x28:
> +       case AS3722_SD0_CONTROL_REG:
> +       case AS3722_SD1_CONTROL_REG:
> +       case AS3722_SDmph_CONTROL_REG:
> +       case AS3722_SD23_CONTROL_REG:
> +       case AS3722_SD4_CONTROL_REG:
> +       case AS3722_SD5_CONTROL_REG:
> +       case AS3722_SD6_CONTROL_REG:
> +       case 0x30:
> +       case 0x31:
> +       case 0x32:
> +       case 0x33:
> +       case 0x34:
> +       case 0x35:
> +       case 0x36:
> +       case 0x37:
> +       case AS3722_WATCHDOG_CONTROL_REG:
> +       case 0x39:
> +       case 0x3a:
> +       case 0x3b:
> +       case 0x3c:
> +       case 0x3d:
> +       case 0x3e:
> +       case 0x3f:
> +       case 0x40:
> +       case 0x41:
> +       case 0x42:
> +       case AS3722_WATCHDOG_TIMER_REG:
> +       case AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG:
> +       case AS3722_IOVOLTAGE_REG:
> +       case 0x4a:
> +       case AS3722_SD_CONTROL_REG:
> +       case AS3722_LDOCONTROL0_REG:
> +       case AS3722_LDOCONTROL1_REG:
> +       case 0x50:
> +       case 0x51:
> +       case 0x52:
> +       case 0x53:
> +       case 0x54:
> +       case 0x55:
> +       case 0x57:
> +       case AS3722_CTRL1_REG:
> +       case AS3722_CTRL2_REG:
> +       case 0x5a:
> +       case 0x5b:
> +       case 0x5c:
> +       case 0x5d:
> +       case 0x5e:
> +       case 0x5f:
> +       case AS3722_RTC_CONTROL_REG:
> +       case AS3722_RTC_SECOND_REG:
> +       case AS3722_RTC_MINUTE_REG:
> +       case AS3722_RTC_HOUR_REG:
> +       case AS3722_RTC_DAY_REG:
> +       case AS3722_RTC_MONTH_REG:
> +       case AS3722_RTC_YEAR_REG:
> +       case AS3722_RTC_ALARM_SECOND_REG:
> +       case AS3722_RTC_ALARM_MINUTE_REG:
> +       case AS3722_RTC_ALARM_HOUR_REG:
> +       case AS3722_RTC_ALARM_DAY_REG:
> +       case AS3722_RTC_ALARM_MONTH_REG:
> +       case AS3722_RTC_ALARM_YEAR_REG:
> +       case 0x6d:
> +       case 0x6f:
> +       case 0x73:
> +       case AS3722_INTERRUPTMASK1_REG:
> +       case AS3722_INTERRUPTMASK2_REG:
> +       case AS3722_INTERRUPTMASK3_REG:
> +       case AS3722_INTERRUPTMASK4_REG:
> +       case AS3722_INTERRUPTSTATUS1_REG:
> +       case AS3722_INTERRUPTSTATUS2_REG:
> +       case AS3722_INTERRUPTSTATUS3_REG:
> +       case AS3722_INTERRUPTSTATUS4_REG:
> +       case 0x7d:
> +       case AS3722_ADC0_CONTROL_REG:
> +       case AS3722_ADC1_CONTROL_REG:
> +       case AS3722_ADC0_MSB_RESULT_REG:
> +       case AS3722_ADC0_LSB_RESULT_REG:
> +       case AS3722_ADC1_MSB_RESULT_REG:
> +       case AS3722_ADC1_LSB_RESULT_REG:
> +       case AS3722_ADC1_THRESHOLD_HI_MSB_REG:
> +       case AS3722_ADC1_THRESHOLD_HI_LSB_REG:
> +       case AS3722_ADC1_THRESHOLD_LO_MSB_REG:
> +       case AS3722_ADC1_THRESHOLD_LO_LSB_REG:
> +       case AS3722_ADC_CONFIG_REG:
> +       case AS3722_ADDR_ASIC_ID1:
> +       case AS3722_ADDR_ASIC_ID2:
> +               return true;
> +       default:
> +               return false;
> +       }
> +}
> +static bool as3722_writeable(struct device *dev, unsigned int reg) {
> +       switch (reg) {
> +       case AS3722_SD0_VOLTAGE_REG:
> +       case AS3722_SD1_VOLTAGE_REG:
> +       case AS3722_SD2_VOLTAGE_REG:
> +       case AS3722_SD3_VOLTAGE_REG:
> +       case AS3722_SD4_VOLTAGE_REG:
> +       case AS3722_SD5_VOLTAGE_REG:
> +       case AS3722_SD6_VOLTAGE_REG:
> +       case AS3722_GPIO0_CONTROL_REG:
> +       case AS3722_GPIO1_CONTROL_REG:
> +       case AS3722_GPIO2_CONTROL_REG:
> +       case AS3722_GPIO3_CONTROL_REG:
> +       case AS3722_GPIO4_CONTROL_REG:
> +       case AS3722_GPIO5_CONTROL_REG:
> +       case AS3722_GPIO6_CONTROL_REG:
> +       case AS3722_GPIO7_CONTROL_REG:
> +       case AS3722_LDO0_VOLTAGE_REG:
> +       case AS3722_LDO1_VOLTAGE_REG:
> +       case AS3722_LDO2_VOLTAGE_REG:
> +       case AS3722_LDO3_VOLTAGE_REG:
> +       case AS3722_LDO4_VOLTAGE_REG:
> +       case AS3722_LDO5_VOLTAGE_REG:
> +       case AS3722_LDO6_VOLTAGE_REG:
> +       case AS3722_LDO7_VOLTAGE_REG:
> +       case AS3722_LDO9_VOLTAGE_REG:
> +       case AS3722_LDO10_VOLTAGE_REG:
> +       case AS3722_LDO11_VOLTAGE_REG:
> +       case 0x1d:
> +       case 0x1e:
> +       case 0x1f:
> +       case AS3722_GPIO_SIGNAL_OUT_REG:
> +       case 0x22:
> +       case 0x23:
> +       case 0x24:
> +       case 0x27:
> +       case 0x28:
> +       case AS3722_SD0_CONTROL_REG:
> +       case AS3722_SD1_CONTROL_REG:
> +       case AS3722_SDmph_CONTROL_REG:
> +       case AS3722_SD23_CONTROL_REG:
> +       case AS3722_SD4_CONTROL_REG:
> +       case AS3722_SD5_CONTROL_REG:
> +       case AS3722_SD6_CONTROL_REG:
> +       case 0x30:
> +       case 0x31:
> +       case 0x32:
> +       case 0x33:
> +       case 0x34:
> +       case 0x35:
> +       case 0x36:
> +       case 0x37:
> +       case AS3722_WATCHDOG_CONTROL_REG:
> +       case 0x39:
> +       case 0x3a:
> +       case 0x3b:
> +       case 0x3c:
> +       case 0x3d:
> +       case 0x3e:
> +       case 0x3f:
> +       case 0x40:
> +       case 0x41:
> +       case 0x42:
> +       case AS3722_WATCHDOG_TIMER_REG:
> +       case AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG:
> +       case AS3722_IOVOLTAGE_REG:
> +       case 0x4a:
> +       case AS3722_SD_CONTROL_REG:
> +       case AS3722_LDOCONTROL0_REG:
> +       case AS3722_LDOCONTROL1_REG:
> +       case 0x50:
> +       case 0x51:
> +       case 0x52:
> +       case 0x53:
> +       case 0x54:
> +       case 0x55:
> +       case 0x57:
> +       case AS3722_CTRL1_REG:
> +       case AS3722_CTRL2_REG:
> +       case 0x5a:
> +       case 0x5b:
> +       case 0x5c:
> +       case 0x5d:
> +       case 0x5e:
> +       case AS3722_RTC_CONTROL_REG:
> +       case AS3722_RTC_SECOND_REG:
> +       case AS3722_RTC_MINUTE_REG:
> +       case AS3722_RTC_HOUR_REG:
> +       case AS3722_RTC_DAY_REG:
> +       case AS3722_RTC_MONTH_REG:
> +       case AS3722_RTC_YEAR_REG:
> +       case AS3722_RTC_ALARM_SECOND_REG:
> +       case AS3722_RTC_ALARM_MINUTE_REG:
> +       case AS3722_RTC_ALARM_HOUR_REG:
> +       case AS3722_RTC_ALARM_DAY_REG:
> +       case AS3722_RTC_ALARM_MONTH_REG:
> +       case AS3722_RTC_ALARM_YEAR_REG:
> +       case 0x6d:
> +       case 0x6f:
> +       case AS3722_INTERRUPTMASK1_REG:
> +       case AS3722_INTERRUPTMASK2_REG:
> +       case AS3722_INTERRUPTMASK3_REG:
> +       case AS3722_INTERRUPTMASK4_REG:
> +       case AS3722_INTERRUPTSTATUS1_REG:
> +       case AS3722_INTERRUPTSTATUS2_REG:
> +       case AS3722_INTERRUPTSTATUS3_REG:
> +       case AS3722_INTERRUPTSTATUS4_REG:
> +       case 0x7d:
> +       case AS3722_ADC0_CONTROL_REG:
> +       case AS3722_ADC1_CONTROL_REG:
> +       case AS3722_ADC1_THRESHOLD_HI_MSB_REG:
> +       case AS3722_ADC1_THRESHOLD_HI_LSB_REG:
> +       case AS3722_ADC1_THRESHOLD_LO_MSB_REG:
> +       case AS3722_ADC1_THRESHOLD_LO_LSB_REG:
> +       case AS3722_ADC_CONFIG_REG:
> +               return true;
> +       default:
> +               return false;
> +       }
> +}

Really? Isn't there a better, more dynamic way of doing this?

> +static bool as3722_volatile(struct device *dev, unsigned int reg) {
> +       return false;
> +}
> +
> +const struct regmap_config as3722_regmap_config = {
> +       .reg_bits = 8,
> +       .val_bits = 8,
> +
> +       .cache_type = REGCACHE_RBTREE,
> +
> +       .max_register = AS3722_REGISTER_COUNT,
> +       .readable_reg = as3722_readable,
> +       .writeable_reg = as3722_writeable,
> +       .volatile_reg = as3722_volatile,
> +
> +       .reg_defaults = as3722_defaults,
> +       .num_reg_defaults = ARRAY_SIZE(as3722_defaults), };
> diff -uprN -X Documentation/dontdiff ../kernel_3.8.8/linux-kernel/drivers/mfd/Kconfig ./drivers/mfd/Kconfig
> --- ../kernel_3.8.8/linux-kernel/drivers/mfd/Kconfig    2013-05-15 14:55:54.000000000 +0200
> +++ ./drivers/mfd/Kconfig       2013-05-23 13:12:36.000000000 +0200
> @@ -516,6 +516,21 @@ config MFD_LP8788

Argh, carnage.

>           TI LP8788 PMU supports regulators, battery charger, RTC,
>           ADC, backlight driver and current sinks.
>
> +config MFD_AS3722
> +       tristate "Support for ams AS3722 PMIC"
> +       select MFD_CORE
> +       select REGMAP_I2C
> +        select REGMAP_IRQ
> +       depends on I2C=y
> +       help
> +         Core support for the ams AS3722 PMIC. Additional
> +         drivers must be enabled in order to use the functionality of the
> +         device.
> +         Related drivers are:
> +               * ams AS3722 PMIC regulators
> +               * ams AS3722 GPIO
> +               * ams AS3722 RTC

Lots of random spacings and line endings above.

>  config MFD_MAX77686
>         bool "Maxim Semiconductor MAX77686 PMIC Support"
>         depends on I2C=y && GENERIC_HARDIRQS diff -uprN -X
> Documentation/dontdiff ../kernel_3.8.8/linux-kernel/drivers/mfd/Makefile ./drivers/mfd/Makefile
> --- ../kernel_3.8.8/linux-kernel/drivers/mfd/Makefile   2013-05-15 14:55:54.000000000 +0200
> +++ ./drivers/mfd/Makefile      2013-05-23 13:12:36.000000000 +0200
> @@ -148,3 +148,4 @@ obj-$(CONFIG_MFD_LM3533)    += lm3533-core.
>  obj-$(CONFIG_VEXPRESS_CONFIG)  += vexpress-config.o vexpress-sysreg.o
>  obj-$(CONFIG_MFD_RETU)         += retu-mfd.o
>  obj-$(CONFIG_MFD_AS3711)       += as3711.o
> +obj-$(CONFIG_MFD_AS3722)       += as3722-core.o as3722-regmap.o

--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ