now using git send-email and splitted mfd patch into multiple patches (4).
Suggestions from 23.05.2013 added.
Signed-off-by: Florian Lobmaier <[email protected]>
---
drivers/mfd/Kconfig | 15 +
drivers/mfd/Makefile | 1 +
drivers/mfd/as3722-core.c | 747 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 763 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/as3722-core.c
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index aecd6dd..a02777c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -27,6 +27,21 @@ config MFD_AS3711
help
Support for the AS3711 PMIC from AMS
+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 PMIC_ADP5520
bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
depends on I2C=y
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 3c90051..358e46e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -159,3 +159,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 <[email protected]>
+ *
+ * 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, ®);
+ 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, ®);
+ 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 <[email protected]>");
--
1.7.2.5
Signed-off-by: Florian Lobmaier <[email protected]>
---
include/linux/mfd/as3722-plat.h | 238 +++++++++++++++++++++++++++++++++++++++
1 files changed, 238 insertions(+), 0 deletions(-)
create mode 100644 include/linux/mfd/as3722-plat.h
diff --git a/include/linux/mfd/as3722-plat.h b/include/linux/mfd/as3722-plat.h
new file mode 100644
index 0000000..0fc3fb7
--- /dev/null
+++ b/include/linux/mfd/as3722-plat.h
@@ -0,0 +1,238 @@
+/*
+ * as3722.h definitions
+ *
+ * Copyright (C) 2013 ams
+ *
+ * Author: Florian Lobmaier <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __LINUX_MFD_AS3722_PLAT_H
+#define __LINUX_MFD_AS3722_PLAT_H
+
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/power_supply.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+#include <linux/regulator/machine.h>
+#include <linux/pwm.h>
+#include <linux/mfd/as3722-reg.h>
+
+struct as3722_reg_init {
+ u32 reg;
+ u32 val;
+};
+
+extern const struct regmap_config as3722_regmap_config;
+
+struct as3722_rtc {
+ struct rtc_device *rtc;
+ int alarm_enabled; /* used for suspend/resume */
+};
+
+struct as3722 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *irq_data;
+ struct regulator_dev *rdevs[AS3722_NUM_REGULATORS];
+ struct as3722_rtc rtc;
+ struct pwm_chip as3722_pwm;
+
+ struct mutex adc_mutex;
+
+ int chip_irq;
+ int reg_stby_counter;
+};
+
+enum {
+ AS3722_GPIO_CFG_NO_INVERT = 0,
+ AS3722_GPIO_CFG_INVERT = 1,
+};
+
+enum {
+ AS3722_GPIO_CFG_OUTPUT_DISABLED = 0,
+ AS3722_GPIO_CFG_OUTPUT_ENABLED = 1,
+};
+
+struct as3722_gpio_config {
+ int gpio;
+ int mode;
+ int invert;
+ int iosf;
+ int output_state;
+};
+
+enum as3722_off_delay {
+ AS3722_OFF_DELAY_NONE = 0,
+ AS3722_OFF_DELAY_8ms = 1,
+ AS3722_OFF_DELAY_16ms = 2,
+ AS3722_OFF_DELAY_32ms = 3,
+};
+
+enum as3722_bit {
+ AS3722_BIT_OFF = 0,
+ AS3722_BIT_ON = 1,
+};
+
+enum as3722_vmask_time {
+ AS3722_NO_MASKING = 0,
+ AS3722_VMASK_4us = 1,
+ AS3722_VMASK_8us = 2,
+};
+
+enum as3722_lv_deb_time {
+ AS3722_NO_DEBOUNCING = 0,
+ AS3722_DEB_1us = 1,
+ AS3722_DEB_4us = 2,
+ AS3722_DEB_20us = 3,
+};
+
+enum as3722_ovc_alarm {
+ AS3722_OVC_ALARM_DISABLED = 0,
+ AS3722_OVC_ALARM_1_6A = 1,
+ AS3722_OVC_ALARM_1_8A = 2,
+ AS3722_OVC_ALARM_2_0A = 3,
+ AS3722_OVC_ALARM_2_2A = 4,
+ AS3722_OVC_ALARM_2_4A = 5,
+ AS3722_OVC_ALARM_2_6A = 6,
+ AS3722_OVC_ALARM_2_8A = 7,
+};
+
+struct as3722_platform_data {
+ struct regulator_init_data *reg_init[AS3722_NUM_REGULATORS];
+
+ /* register initialisation */
+ struct as3722_reg_init *core_init_data;
+ int gpio_base;
+ int irq_base;
+ int irq_type;
+
+ int use_internal_int_pullup;
+ int use_internal_i2c_pullup;
+ int enable_clk32out_pin;
+
+ int num_gpio_cfgs;
+ struct as3722_gpio_config *gpio_cfgs;
+
+ /* enable1 pin standby control */
+ enum as3722_off_delay off_delay;
+ int enable1_deepsleep;
+ int enable1_invert;
+
+ /* thermal shutdown control */
+ enum as3722_bit mask_ovtemp;
+
+ /* overcurrent / powergood settings */
+ enum as3722_vmask_time pg_sd6_vmask_time;
+ enum as3722_lv_deb_time sd6_lv_deb_time;
+ enum as3722_lv_deb_time sd1_lv_deb_time;
+ enum as3722_lv_deb_time sd0_lv_deb_time;
+ enum as3722_bit pg_vresfall_mask;
+ enum as3722_bit pg_ovcurr_sd0_mask;
+ enum as3722_bit pg_pwrgood_sd0_mask;
+ enum as3722_bit pg_gpio5_mask;
+ enum as3722_bit pg_gpio4_mask;
+ enum as3722_bit pg_gpio3_mask;
+ enum as3722_bit pg_ac_ok_mask;
+ enum as3722_bit pg_ac_ok_inv;
+ enum as3722_bit pg_ovcurr_sd6_mask;
+ enum as3722_bit pg_pwrgood_sd6_mask;
+ enum as3722_ovc_alarm pg_sd6_ovc_alarm;
+ enum as3722_vmask_time pg_sd0_vmask_time;
+ enum as3722_bit oc_pg_inv;
+};
+
+static inline int as3722_reg_read(struct as3722 *as3722, u32 reg, u32 *dest)
+{
+ return regmap_read(as3722->regmap, reg, dest);
+}
+
+static inline int as3722_reg_write(struct as3722 *as3722, u32 reg, u32 value)
+{
+ return regmap_write(as3722->regmap, reg, value);
+}
+
+static inline int as3722_block_read(struct as3722 *as3722, u32 reg,
+ int count, u8 *buf)
+{
+ return regmap_bulk_read(as3722->regmap, reg, buf, count);
+}
+
+static inline int as3722_block_write(struct as3722 *as3722, u32 reg,
+ int count, u8 *data)
+{
+ return regmap_bulk_write(as3722->regmap, reg, data, count);
+}
+
+static inline int as3722_set_bits(struct as3722 *as3722, u32 reg,
+ u32 mask, u8 val)
+{
+ return regmap_update_bits(as3722->regmap, reg, mask, val);
+}
+
+/* ADC */
+enum as3722_adc_source {
+ AS3722_ADC_SD0 = 0,
+ AS3722_ADC_SD1 = 1,
+ AS3722_ADC_SD6 = 2,
+ AS3722_ADC_TEMP_SENSOR = 3,
+ AS3722_ADC_VSUP = 4,
+ AS3722_ADC_GPIO1 = 5,
+ AS3722_ADC_GPIO2 = 6,
+ AS3722_ADC_GPIO3 = 7,
+ AS3722_ADC_GPIO4 = 8,
+ AS3722_ADC_GPIO6 = 9,
+ AS3722_ADC_GPIO7 = 10,
+ AS3722_ADC_VBAT = 11,
+ AS3722_ADC_PWM_CLK2 = 12,
+ AS3722_ADC_PWM_DAT2 = 13,
+ AS3722_ADC_TEMP1_SD0 = 16,
+ AS3722_ADC_TEMP2_SD0 = 17,
+ AS3722_ADC_TEMP3_SD0 = 18,
+ AS3722_ADC_TEMP4_SD0 = 19,
+ AS3722_ADC_TEMP_SD1 = 20,
+ AS3722_ADC_TEMP1_SD6 = 21,
+ AS3722_ADC_TEMP2_SD6 = 22,
+};
+
+enum as3722_adc_channel {
+ AS3722_ADC0 = 0,
+ AS3722_ADC1 = 1,
+};
+
+enum as3722_adc_voltange_range {
+ AS3722_ADC_HIGH_VOLTAGE_RANGE = 0,
+ AS3722_ADC_LOW_VOLTAGE_RANGE = 1,
+};
+
+int as3722_adc_read(struct as3722 *as3722,
+ enum as3722_adc_channel channel,
+ enum as3722_adc_source source,
+ enum as3722_adc_voltange_range voltage_range);
+
+#endif
+
+
+
+
+
+
--
1.7.2.5
Signed-off-by: Florian Lobmaier <[email protected]>
---
drivers/mfd/as3722-regmap.c | 417 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 417 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/as3722-regmap.c
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 <[email protected]>
+ *
+ * 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),
+};
--
1.7.2.5
Signed-off-by: Florian Lobmaier <[email protected]>
---
include/linux/mfd/as3722-reg.h | 495 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 495 insertions(+), 0 deletions(-)
create mode 100644 include/linux/mfd/as3722-reg.h
diff --git a/include/linux/mfd/as3722-reg.h b/include/linux/mfd/as3722-reg.h
new file mode 100644
index 0000000..cc77584
--- /dev/null
+++ b/include/linux/mfd/as3722-reg.h
@@ -0,0 +1,495 @@
+/*
+ * as3722.h definitions
+ *
+ * Copyright (C) 2013 ams
+ *
+ * Author: Florian Lobmaier <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __LINUX_MFD_AS3722_REG_H
+#define __LINUX_MFD_AS3722_REG_H
+
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/power_supply.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+#include <linux/regulator/machine.h>
+
+#define AS3722_DEVICE_ID 0x0C
+#define AS3722_REGISTER_COUNT 0x92
+#define AS3722_NUM_REGULATORS 18
+#define AS3722_NUM_STEPDOWN_REGULATORS 7
+#define AS3722_MAX_REG_STBY_COUNT 10
+
+/* defines for register init */
+#define AS3722_REG_INIT(reg_offset, reg_value) \
+{ \
+ .reg = (reg_offset), \
+ .val = (reg_value), \
+}
+
+#define AS3722_REG_INIT_TERMINATE 0xFF
+
+/* regulator IDs */
+#define AS3722_LDO0 0
+#define AS3722_LDO1 1
+#define AS3722_LDO2 2
+#define AS3722_LDO3 3
+#define AS3722_LDO4 4
+#define AS3722_LDO5 5
+#define AS3722_LDO6 6
+#define AS3722_LDO7 7
+#define AS3722_LDO9 8
+#define AS3722_LDO10 9
+#define AS3722_LDO11 10
+#define AS3722_SD0 11
+#define AS3722_SD1 12
+#define AS3722_SD2 13
+#define AS3722_SD3 14
+#define AS3722_SD4 15
+#define AS3722_SD5 16
+#define AS3722_SD6 17
+
+/* AS3722 ASIC ID */
+#define AS3722_ADDR_ASIC_ID1 0x90
+#define AS3722_ADDR_ASIC_ID2 0x91
+
+/* GPIO IDs */
+#define AS3722_GPIO0 0
+#define AS3722_GPIO1 1
+#define AS3722_GPIO2 2
+#define AS3722_GPIO3 3
+#define AS3722_GPIO4 4
+#define AS3722_GPIO5 5
+#define AS3722_GPIO6 6
+#define AS3722_GPIO7 7
+
+#define AS3722_NUM_GPIO 8
+#define AS3722_GPIO_IRQ_BASE 0
+
+/* GPIO modes */
+#define AS3722_GPIO_MODE_MASK 0x07
+#define AS3722_GPIO_MODE_INPUT 0
+#define AS3722_GPIO_MODE_OUTPUT_VDDH 1
+#define AS3722_GPIO_MODE_IO_OPEN_DRAIN 2
+#define AS3722_GPIO_MODE_ADC_IN 3
+#define AS3722_GPIO_MODE_INPUT_W_PULLUP 4
+#define AS3722_GPIO_MODE_INPUT_W_PULLDOWN 5
+#define AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULLUP 6
+#define AS3722_GPIO_MODE_OUTPUT_VDDL 7
+
+/* Interrupt IDs */
+#define AS3722_IRQ_MAX_HANDLER 18
+#define AS3722_IRQ_LID 0
+#define AS3722_IRQ_ACOK 1
+#define AS3722_IRQ_ENABLE1 2
+#define AS3722_IRQ_OCURR_ACOK 3
+#define AS3722_IRQ_ONKEY_LONG 4
+#define AS3722_IRQ_ONKEY 5
+#define AS3722_IRQ_OVTMP 6
+#define AS3722_IRQ_LOWBAT 7
+#define AS3722_IRQ_RTC_REP 8
+#define AS3722_IRQ_RTC_ALARM 9
+#define AS3722_IRQ_SD0 10
+#define AS3722_IRQ_WATCHDOG 11
+#define AS3722_IRQ_ADC 12
+#define AS3722_IRQ_GPIO1 13
+#define AS3722_IRQ_GPIO2 14
+#define AS3722_IRQ_GPIO3 15
+#define AS3722_IRQ_GPIO4 16
+#define AS3722_IRQ_GPIO5 17
+#define AS3722_IRQ_TEMP_SD0_SHUTDOWN 18
+#define AS3722_IRQ_TEMP_SD1_SHUTDOWN 19
+#define AS3722_IRQ_TEMP_SD6_SHUTDOWN 20
+#define AS3722_IRQ_TEMP_SD0_ALARM 21
+#define AS3722_IRQ_TEMP_SD1_ALARM 22
+#define AS3722_IRQ_TEMP_SD6_ALARM 23
+
+/* AS3722 registers */
+#define AS3722_SD0_VOLTAGE_REG 0x00
+#define AS3722_SD1_VOLTAGE_REG 0x01
+#define AS3722_SD2_VOLTAGE_REG 0x02
+#define AS3722_SD3_VOLTAGE_REG 0x03
+#define AS3722_SD4_VOLTAGE_REG 0x04
+#define AS3722_SD5_VOLTAGE_REG 0x05
+#define AS3722_SD6_VOLTAGE_REG 0x06
+#define AS3722_GPIO0_CONTROL_REG 0x08
+#define AS3722_GPIO1_CONTROL_REG 0x09
+#define AS3722_GPIO2_CONTROL_REG 0x0A
+#define AS3722_GPIO3_CONTROL_REG 0x0B
+#define AS3722_GPIO4_CONTROL_REG 0x0C
+#define AS3722_GPIO5_CONTROL_REG 0x0D
+#define AS3722_GPIO6_CONTROL_REG 0x0E
+#define AS3722_GPIO7_CONTROL_REG 0x0F
+#define AS3722_LDO0_VOLTAGE_REG 0x10
+#define AS3722_LDO1_VOLTAGE_REG 0x11
+#define AS3722_LDO2_VOLTAGE_REG 0x12
+#define AS3722_LDO3_VOLTAGE_REG 0x13
+#define AS3722_LDO4_VOLTAGE_REG 0x14
+#define AS3722_LDO5_VOLTAGE_REG 0x15
+#define AS3722_LDO6_VOLTAGE_REG 0x16
+#define AS3722_LDO7_VOLTAGE_REG 0x17
+#define AS3722_LDO9_VOLTAGE_REG 0x19
+#define AS3722_LDO10_VOLTAGE_REG 0x1A
+#define AS3722_LDO11_VOLTAGE_REG 0x1B
+
+#define AS3722_GPIO_SIGNAL_OUT_REG 0x20
+#define AS3722_GPIO_SIGNAL_IN_REG 0x21
+
+#define AS3722_SD0_CONTROL_REG 0x29
+#define AS3722_SD1_CONTROL_REG 0x2A
+#define AS3722_SDmph_CONTROL_REG 0x2B
+#define AS3722_SD23_CONTROL_REG 0x2C
+#define AS3722_SD4_CONTROL_REG 0x2D
+#define AS3722_SD5_CONTROL_REG 0x2E
+#define AS3722_SD6_CONTROL_REG 0x2F
+
+#define AS3722_RESETTIMER_REG 0x34
+#define AS3722_OVERTEMPERATURE_CONTROL_REG 0x37
+#define AS3722_WATCHDOG_CONTROL_REG 0x38
+#define AS3722_REG_STANDBY_MOD1_REG 0x39
+#define AS3722_REG_STANDBY_MOD2_REG 0x3A
+#define AS3722_REG_STANDBY_MOD3_REG 0x3B
+#define AS3722_PWM_CONTROL_L_REG 0x41
+#define AS3722_PWM_CONTROL_H_REG 0x42
+#define AS3722_WATCHDOG_TIMER_REG 0x46
+#define AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG 0x48
+#define AS3722_IOVOLTAGE_REG 0x49
+#define AS3722_SD_CONTROL_REG 0x4D
+#define AS3722_LDOCONTROL0_REG 0x4E
+#define AS3722_LDOCONTROL1_REG 0x4F
+
+#define AS3722_CTRL1_REG 0x58
+#define AS3722_CTRL2_REG 0x59
+#define AS3722_SD_LV_DEB_REG 0x5C
+#define AS3722_OC_PG_CONTROL_REG 0x5D
+#define AS3722_OC_PG_CONTROL2_REG 0x5E
+#define AS3722_RTC_CONTROL_REG 0x60
+#define AS3722_RTC_SECOND_REG 0x61
+#define AS3722_RTC_MINUTE_REG 0x62
+#define AS3722_RTC_HOUR_REG 0x63
+#define AS3722_RTC_DAY_REG 0x64
+#define AS3722_RTC_MONTH_REG 0x65
+#define AS3722_RTC_YEAR_REG 0x66
+#define AS3722_RTC_ALARM_SECOND_REG 0x67
+#define AS3722_RTC_ALARM_MINUTE_REG 0x68
+#define AS3722_RTC_ALARM_HOUR_REG 0x69
+#define AS3722_RTC_ALARM_DAY_REG 0x6A
+#define AS3722_RTC_ALARM_MONTH_REG 0x6B
+#define AS3722_RTC_ALARM_YEAR_REG 0x6C
+
+#define AS3722_INTERRUPTMASK1_REG 0x74
+#define AS3722_INTERRUPTMASK2_REG 0x75
+#define AS3722_INTERRUPTMASK3_REG 0x76
+#define AS3722_INTERRUPTMASK4_REG 0x77
+#define AS3722_INTERRUPTSTATUS1_REG 0x78
+#define AS3722_INTERRUPTSTATUS2_REG 0x79
+#define AS3722_INTERRUPTSTATUS3_REG 0x7A
+#define AS3722_INTERRUPTSTATUS4_REG 0x7B
+#define AS3722_TEMP_STATUS_REG 0x7D
+
+#define AS3722_ADC0_CONTROL_REG 0x80
+#define AS3722_ADC1_CONTROL_REG 0x81
+#define AS3722_ADC0_MSB_RESULT_REG 0x82
+#define AS3722_ADC0_LSB_RESULT_REG 0x83
+#define AS3722_ADC1_MSB_RESULT_REG 0x84
+#define AS3722_ADC1_LSB_RESULT_REG 0x85
+#define AS3722_ADC1_THRESHOLD_HI_MSB_REG 0x86
+#define AS3722_ADC1_THRESHOLD_HI_LSB_REG 0x87
+#define AS3722_ADC1_THRESHOLD_LO_MSB_REG 0x88
+#define AS3722_ADC1_THRESHOLD_LO_LSB_REG 0x89
+#define AS3722_ADC_CONFIG_REG 0x8A
+
+#define AS3722_REG0_CONTROL_REG 0xE0
+#define AS3722_REG1_CONTROL_REG 0xE1
+#define AS3722_REG2_CONTROL_REG 0xE2
+#define AS3722_REG3_CONTROL_REG 0xE3
+#define AS3722_REG4_CONTROL_REG 0xE4
+#define AS3722_REG5_CONTROL_REG 0xE5
+#define AS3722_REG6_CONTROL_REG 0xE6
+#define AS3722_REG7_CONTROL_REG 0xE7
+#define AS3722_REG8_CONTROL_REG 0xE8
+#define AS3722_REG9_CONTROL_REG 0xE9
+#define AS3722_REG0_VOLTAGE_REG 0xEA
+#define AS3722_REG1_VOLTAGE_REG 0xEB
+#define AS3722_REG2_VOLTAGE_REG 0xEC
+#define AS3722_REG3_VOLTAGE_REG 0xED
+#define AS3722_REG4_VOLTAGE_REG 0xEE
+#define AS3722_REG5_VOLTAGE_REG 0xEF
+#define AS3722_REG6_VOLTAGE_REG 0xF0
+#define AS3722_REG7_VOLTAGE_REG 0xF1
+#define AS3722_REG8_VOLTAGE_REG 0xF2
+#define AS3722_REG9_VOLTAGE_REG 0xF3
+
+/* AS3722 register bits and bit masks */
+#define AS3722_LDO_ILIMIT_MASK (1 << 7)
+#define AS3722_LDO_ILIMIT_BIT (1 << 7)
+#define AS3722_LDO0_VSEL_MASK 0x1F
+#define AS3722_LDO0_VSEL_MIN 0x01
+#define AS3722_LDO0_VSEL_MAX 0x12
+#define AS3722_LDO3_VSEL_MASK 0x3F
+#define AS3722_LDO3_VSEL_MIN 0x01
+#define AS3722_LDO3_VSEL_MAX 0x45
+#define AS3722_LDO_VSEL_MASK 0x7F
+#define AS3722_LDO_VSEL_MIN 0x01
+#define AS3722_LDO_VSEL_MAX 0x7F
+#define AS3722_LDO_VSEL_DNU_MIN 0x25
+#define AS3722_LDO_VSEL_DNU_MAX 0x3F
+#define AS3722_LDO_NUM_VOLT 100
+
+#define AS3722_LDO0_ON (1 << 0)
+#define AS3722_LDO0_OFF (0 << 0)
+#define AS3722_LDO0_CTRL_MASK (1 << 0)
+#define AS3722_LDO1_ON (1 << 1)
+#define AS3722_LDO1_OFF (0 << 1)
+#define AS3722_LDO1_CTRL_MASK (1 << 1)
+#define AS3722_LDO2_ON (1 << 2)
+#define AS3722_LDO2_OFF (0 << 2)
+#define AS3722_LDO2_CTRL_MASK (1 << 2)
+#define AS3722_LDO3_ON (1 << 3)
+#define AS3722_LDO3_OFF (0 << 3)
+#define AS3722_LDO3_CTRL_MASK (1 << 3)
+#define AS3722_LDO4_ON (1 << 4)
+#define AS3722_LDO4_OFF (0 << 4)
+#define AS3722_LDO4_CTRL_MASK (1 << 4)
+#define AS3722_LDO5_ON (1 << 5)
+#define AS3722_LDO5_OFF (0 << 5)
+#define AS3722_LDO5_CTRL_MASK (1 << 5)
+#define AS3722_LDO6_ON (1 << 6)
+#define AS3722_LDO6_OFF (0 << 6)
+#define AS3722_LDO6_CTRL_MASK (1 << 6)
+#define AS3722_LDO7_ON (1 << 7)
+#define AS3722_LDO7_OFF (0 << 7)
+#define AS3722_LDO7_CTRL_MASK (1 << 7)
+#define AS3722_LDO9_ON (1 << 1)
+#define AS3722_LDO9_OFF (0 << 1)
+#define AS3722_LDO9_CTRL_MASK (1 << 1)
+#define AS3722_LDO10_ON (1 << 2)
+#define AS3722_LDO10_OFF (0 << 2)
+#define AS3722_LDO10_CTRL_MASK (1 << 2)
+#define AS3722_LDO11_ON (1 << 3)
+#define AS3722_LDO11_OFF (0 << 3)
+#define AS3722_LDO11_CTRL_MASK (1 << 3)
+
+#define AS3722_SD_VSEL_MASK 0x7F
+#define AS3722_SD0_VSEL_MIN 0x01
+#define AS3722_SD0_VSEL_MAX 0x5A
+#define AS3722_SD2_VSEL_MIN 0x01
+#define AS3722_SD2_VSEL_MAX 0x7F
+#define AS3722_SD0_ON (1 << 0)
+#define AS3722_SD0_OFF (0 << 0)
+#define AS3722_SD0_CTRL_MASK (1 << 0)
+#define AS3722_SD1_ON (1 << 1)
+#define AS3722_SD1_OFF (0 << 1)
+#define AS3722_SD1_CTRL_MASK (1 << 1)
+#define AS3722_SD2_ON (1 << 2)
+#define AS3722_SD2_OFF (0 << 2)
+#define AS3722_SD2_CTRL_MASK (1 << 2)
+#define AS3722_SD3_ON (1 << 3)
+#define AS3722_SD3_OFF (0 << 3)
+#define AS3722_SD3_CTRL_MASK (1 << 3)
+#define AS3722_SD4_ON (1 << 4)
+#define AS3722_SD4_OFF (0 << 4)
+#define AS3722_SD4_CTRL_MASK (1 << 4)
+#define AS3722_SD5_ON (1 << 5)
+#define AS3722_SD5_OFF (0 << 5)
+#define AS3722_SD5_CTRL_MASK (1 << 5)
+#define AS3722_SD6_ON (1 << 6)
+#define AS3722_SD6_OFF (0 << 6)
+#define AS3722_SD6_CTRL_MASK (1 << 6)
+
+#define AS3722_SD0_MODE_FAST (1 << 4)
+#define AS3722_SD0_MODE_NORMAL (0 << 4)
+#define AS3722_SD0_MODE_MASK (1 << 4)
+#define AS3722_SD1_MODE_FAST (1 << 4)
+#define AS3722_SD1_MODE_NORMAL (0 << 4)
+#define AS3722_SD1_MODE_MASK (1 << 4)
+#define AS3722_SD2_MODE_FAST (1 << 2)
+#define AS3722_SD2_MODE_NORMAL (0 << 2)
+#define AS3722_SD2_MODE_MASK (1 << 2)
+#define AS3722_SD3_MODE_FAST (1 << 6)
+#define AS3722_SD3_MODE_NORMAL (0 << 6)
+#define AS3722_SD3_MODE_MASK (1 << 6)
+#define AS3722_SD4_MODE_FAST (1 << 2)
+#define AS3722_SD4_MODE_NORMAL (0 << 2)
+#define AS3722_SD4_MODE_MASK (1 << 2)
+#define AS3722_SD5_MODE_FAST (1 << 2)
+#define AS3722_SD5_MODE_NORMAL (0 << 2)
+#define AS3722_SD5_MODE_MASK (1 << 2)
+#define AS3722_SD6_MODE_FAST (1 << 4)
+#define AS3722_SD6_MODE_NORMAL (0 << 4)
+#define AS3722_SD6_MODE_MASK (1 << 4)
+
+#define AS3722_DELAY_TIME_STBY_MASK (1 << 6)
+#define AS3722_REG_DELAY_STBY_MASK (1 << 5)
+#define AS3722_REG_SELECT_STBY_MASK (0x1F)
+#define AS3722_REG_VOLTAGE_STBY_MASK (0xFF)
+
+#define AS3722_SD0_LV_DEB_MASK (0x03)
+#define AS3722_SD1_LV_DEB_MASK (0x0C)
+#define AS3722_SD6_LV_DEB_MASK (0x30)
+#define AS3722_PG_SD6_VMASK_TIME_MASK (0xC0)
+#define AS3722_SD0_LV_DEB_SHIFT (0)
+#define AS3722_SD1_LV_DEB_SHIFT (2)
+#define AS3722_SD6_LV_DEB_SHIFT (4)
+#define AS3722_PG_SD6_VMASK_TIME_SHIFT (6)
+
+#define AS3722_PG_AC_OK_INV_MASK (1 << 0)
+#define AS3722_PG_AC_OK_MASK_MASK (1 << 1)
+#define AS3722_PG_GPIO3_MASK_MASK (1 << 2)
+#define AS3722_PG_GPIO4_MASK_MASK (1 << 3)
+#define AS3722_PG_GPIO5_MASK_MASK (1 << 4)
+#define AS3722_PG_PWRGOOD_SD0_MASK_MASK (1 << 5)
+#define AS3722_PG_OVCURR_SD0_MASK_MASK (1 << 6)
+#define AS3722_PG_VRESFALL_MASK_MASK (1 << 7)
+
+#define AS3722_OC_PG_INV_MASK (1 << 0)
+#define AS3722_PG_SD0_VMASK_TIME_MASK (0x06)
+#define AS3722_PG_SD6_OVC_ALARM_MASK (0x38)
+#define AS3722_PG_PWRGOOD_SD6_MASK_MASK (1 << 6)
+#define AS3722_PG_OVCURR_SD6_MASK_MASK (1 << 7)
+
+#define AS3722_IRQ_MASK_LID (1 << 0)
+#define AS3722_IRQ_MASK_ACOK (1 << 1)
+#define AS3722_IRQ_MASK_ENABLE1 (1 << 2)
+#define AS3722_IRQ_MASK_OCURR_ACOK (1 << 3)
+#define AS3722_IRQ_MASK_ONKEY_LONG (1 << 4)
+#define AS3722_IRQ_MASK_ONKEY (1 << 5)
+#define AS3722_IRQ_MASK_OVTMP (1 << 6)
+#define AS3722_IRQ_MASK_LOWBAT (1 << 7)
+#define AS3722_IRQ_MASK_SD0 (1 << 0)
+#define AS3722_IRQ_MASK_RTC_REP (1 << 7)
+#define AS3722_IRQ_MASK_RTC_ALARM (1 << 0)
+#define AS3722_IRQ_MASK_WATCHDOG (1 << 6)
+#define AS3722_IRQ_MASK_ADC (1 << 7)
+#define AS3722_IRQ_MASK_GPIO1 (1 << 1)
+#define AS3722_IRQ_MASK_GPIO2 (1 << 2)
+#define AS3722_IRQ_MASK_GPIO3 (1 << 3)
+#define AS3722_IRQ_MASK_GPIO4 (1 << 4)
+#define AS3722_IRQ_MASK_GPIO5 (1 << 5)
+#define AS3722_IRQ_MASK_TEMP_SD0_SHUTDOWN (1 << 0)
+#define AS3722_IRQ_MASK_TEMP_SD1_SHUTDOWN (1 << 1)
+#define AS3722_IRQ_MASK_TEMP_SD6_SHUTDOWN (1 << 2)
+#define AS3722_IRQ_MASK_TEMP_SD0_ALARM (1 << 3)
+#define AS3722_IRQ_MASK_TEMP_SD1_ALARM (1 << 4)
+#define AS3722_IRQ_MASK_TEMP_SD6_ALARM (1 << 5)
+
+#define AS3722_IRQ_BIT_LID (1 << 0)
+#define AS3722_IRQ_BIT_ACOK (1 << 1)
+#define AS3722_IRQ_BIT_ENABLE1 (1 << 2)
+#define AS3722_IRQ_BIT_SD0 (1 << 3)
+#define AS3722_IRQ_BIT_ONKEY_LONG (1 << 4)
+#define AS3722_IRQ_BIT_ONKEY (1 << 5)
+#define AS3722_IRQ_BIT_OVTMP (1 << 6)
+#define AS3722_IRQ_BIT_LOWBAT (1 << 7)
+#define AS3722_IRQ_BIT_RTC_REP (1 << 7)
+#define AS3722_IRQ_BIT_RTC_ALARM (1 << 0)
+#define AS3722_IRQ_BIT_WATCHDOG (1 << 6)
+#define AS3722_IRQ_BIT_ADC (1 << 7)
+
+#define AS3722_OVTMP_MASK (1 << 3)
+#define AS3722_OVTMP_SHIFT 3
+
+/* ADC bit masks */
+#define AS3722_ADC_MASK_BUF_ON (1 << 2)
+#define AS3722_ADC_BIT_BUF_ON (1 << 2)
+#define AS3722_ADC1_MASK_INT_MODE_ON (1 << 1)
+#define AS3722_ADC1_BIT_INT_MODE_ON (1 << 1)
+#define AS3722_ADC1_MASK_INTERVAL_TIME (1 << 0)
+#define AS3722_ADC1_BIT_INTERVAL_TIME (1 << 0)
+
+#define AS3722_ADC_MASK_MSB_VAL 0x3F
+#define AS3722_ADC_MASK_LSB_VAL 0x07
+
+#define AS3722_ADC_MASK_CONV_START (1 << 7)
+#define AS3722_ADC_BIT_CONV_START (1 << 7)
+#define AS3722_ADC_MASK_CONV_NOTREADY (1 << 7)
+#define AS3722_ADC_BIT_CONV_NOTREADY (1 << 7)
+#define AS3722_ADC_MASK_SOURCE_SELECT 0x1F
+#define AS3722_ADC_MASK_VOLTAGE_RANGE (1 << 5)
+#define AS3722_ADC_SHIFT_VOLTAGE_RANGE 5
+
+#define AS3722_GPIO_INV_MASK 0x80
+#define AS3722_GPIO_INV 0x80
+#define AS3722_GPIO_IOSF_MASK 0x78
+#define AS3722_GPIO_IOSF_NORMAL 0
+#define AS3722_GPIO_IOSF_INTERRUPT_OUT (1 << 3)
+#define AS3722_GPIO_IOSF_VSUP_LOW_OUT (2 << 3)
+#define AS3722_GPIO_IOSF_GPIO_INTERRUPT_IN (3 << 3)
+#define AS3722_GPIO_IOSF_ISINK_PWM_IN (4 << 3)
+#define AS3722_GPIO_IOSF_VOLTAGE_STBY (5 << 3)
+#define AS3722_GPIO_IOSF_PWR_GOOD_OUT (7 << 3)
+#define AS3722_GPIO_IOSF_Q32K_OUT (8 << 3)
+#define AS3722_GPIO_IOSF_WATCHDOG_IN (9 << 3)
+#define AS3722_GPIO_IOSF_SOFT_RESET_IN (11 << 3)
+#define AS3722_GPIO_IOSF_PWM_OUT (12 << 3)
+#define AS3722_GPIO_IOSF_VSUP_LOW_DEB_OUT (13 << 3)
+#define AS3722_GPIO_IOSF_SD6_LOW_VOLT_LOW (14 << 3)
+
+#define AS3722_GPIO0_SIGNAL_MASK (1 << 0)
+#define AS3722_GPIO1_SIGNAL_MASK (1 << 1)
+#define AS3722_GPIO2_SIGNAL_MASK (1 << 2)
+#define AS3722_GPIO3_SIGNAL_MASK (1 << 3)
+#define AS3722_GPIO4_SIGNAL_MASK (1 << 4)
+#define AS3722_GPIO5_SIGNAL_MASK (1 << 5)
+#define AS3722_GPIO6_SIGNAL_MASK (1 << 6)
+#define AS3722_GPIO7_SIGNAL_MASK (1 << 7)
+
+#define AS3722_INT_PULLUP_MASK (1 << 5)
+#define AS3722_INT_PULLUP_ON (1 << 5)
+#define AS3722_INT_PULLUP_OFF (0 << 5)
+#define AS3722_I2C_PULLUP_MASK (1 << 4)
+#define AS3722_I2C_PULLUP_ON (1 << 4)
+#define AS3722_I2C_PULLUP_OFF (0 << 4)
+
+#define AS3722_RTC_REP_WAKEUP_EN_MASK (1 << 0)
+#define AS3722_RTC_ALARM_WAKEUP_EN_MASK (1 << 1)
+#define AS3722_RTC_ON_MASK (1 << 2)
+#define AS3722_RTC_IRQMODE_MASK (3 << 3)
+#define AS3722_CLK32OUT_ENABLE_MASK (1 << 5)
+
+#define AS3722_CLK32OUT_ENABLE_ON (1 << 5)
+#define AS3722_CLK32OUT_ENABLE_OFF (0 << 5)
+
+#define AS3722_OFF_DELAY_MASK (0x18)
+#define AS3722_OFF_DELAY_SHIFT (3)
+
+#define AS3722_ENABLE1_INVERT_MASK (1 << 4)
+#define AS3722_ENABLE1_INVERT_ON (1 << 4)
+#define AS3722_ENABLE1_INVERT_OFF (0 << 4)
+#define AS3722_ENABLE1_DEEPSLEEP_MASK (1 << 5)
+#define AS3722_ENABLE1_DEEPSLEEP_ON (1 << 5)
+#define AS3722_ENABLE1_DEEPSLEEP_OFF (0 << 5)
+
+#define AS3722_PWM_DIV_MASK 0xC0
+#define AS3722_PWM_DIV_SHIFT (6)
+#define AS3722_PWM_DIV_DIVIDE_BY_1 0x00
+#define AS3722_PWM_DIV_DIVIDE_BY_16 0x40
+#define AS3722_PWM_DIV_DIVIDE_BY_256 0x80
+#define AS3722_PWM_DIV_DIVIDE_BY_16384 0xC0
+
+#define AS3722_WATCHDOG_TIMER_MAX 127
+#define AS3722_WATCHDOG_ON_MASK (1 << 0)
+#define AS3722_WATCHDOG_ON (1 << 0)
+#define AS3722_WATCHDOG_SW_SIG_MASK (1 << 0)
+#define AS3722_WATCHDOG_SW_SIG (1 << 0)
+
+#endif
--
1.7.2.5
I'm going to comment on the format of the patches before I do the code
review.
The $SUBJECT line needs to use the same formatting as previous patches
accepted by the subsystem. In the case of MFD they're formatted like this:
mfd: <driver_name>: <what you're doing>
This information can be obtained by issuing something like:
git log --oneline -- drivers/mfd
> now using git send-email and splitted mfd patch into multiple patches (4).
> Suggestions from 23.05.2013 added.
Anything mentioned here will end up in the Mainline kernel `git log`,
so it needs to only contain what the patch is trying to achieve. The
information you've mentioned above 'could, perhaps' be useful, but it
lives in the cover letter i.e. [PATCH 0/x] instead of in a patch's
commit log.
You are lacking proper commit logs on all 4 patches here. You are also
missing a cover letter.
Once this is all in order, I'll commence the code review.
> Signed-off-by: Florian Lobmaier <[email protected]>
> ---
> drivers/mfd/Kconfig | 15 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/as3722-core.c | 747 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 763 insertions(+), 0 deletions(-)
> create mode 100644 drivers/mfd/as3722-core.c
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index aecd6dd..a02777c 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -27,6 +27,21 @@ config MFD_AS3711
> help
> Support for the AS3711 PMIC from AMS
>
> +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 PMIC_ADP5520
> bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
> depends on I2C=y
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 3c90051..358e46e 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -159,3 +159,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 <[email protected]>
> + *
> + * 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, ®);
> + 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, ®);
> + 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 <[email protected]>");
--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
On Wed, Aug 14, 2013 at 04:54:55PM +0200, Florian Lobmaier wrote:
> +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,
> +};
wake_base looks wrong - that should be either absent or a register name.
> +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++;
> + }
> +}
This looks like it might be supposed to be a register patch?
> +int as3722_read_adc(struct as3722 *as3722,
> + enum as3722_adc_channel channel,
> + enum as3722_adc_source source,
> + enum as3722_adc_voltange_range voltage_range)
This should be moved over to IIO - the ADC code in MFDs predates IIO
being available.
> +static irqreturn_t as3722_onkey_press_irq(int irq, void *irq_data)
> +static irqreturn_t as3722_onkey_lpress_irq(int irq, void *irq_data)
These should be handled by an input driver.
> +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;
> +}
You probably want these to complain loudly rather than as dev_dbg(), I'm
not sure what the status of the thermal framework is.
> + /* 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);
This looks like a job for the clk API.
On Wed, Aug 14, 2013 at 04:54:56PM +0200, Florian Lobmaier wrote:
> +static bool as3722_readable(struct device *dev, unsigned int reg)
> +{
> + switch (reg) {
> + case AS3722_SD0_VOLTAGE_REG:
Are there any gaps in this register map? If not just checking the range
would be easier (it looks like this is the case here).
> + case AS3722_INTERRUPTSTATUS1_REG:
> + case AS3722_INTERRUPTSTATUS2_REG:
> + case AS3722_INTERRUPTSTATUS3_REG:
> + case AS3722_INTERRUPTSTATUS4_REG:
> +static bool as3722_volatile(struct device *dev, unsigned int reg)
> +{
> + return false;
> +}
At least the interrupt status register above should be volatile
otherwise you'll never be able to read the actual stauts.
> ---
> include/linux/mfd/as3722-reg.h | 495 ++++++++++++++++++++++++++++++++++++++++
So the way you've split up the patch isn't quite right. It shouldn't
be split by files, rather by functionality.
Quoting from Documentation/SubmittingPatches:
"If your changes produce a lot of deltas, you may want to look into
splitting them into individual patches which modify things in
logical stages. This will facilitate easier reviewing by other
kernel developers, very important if you want your patch accepted."
Note "logical stages".
So things like:
- Driver introduction including Kconfig and Makefile entries
- Resource allocation; memory and irqs
- Everything else, bit by bit
Within reason, the simpler the patches, they more likely they are to
be reviewed and accepted.
--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog