]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00141391-1 PMIC: Add DA9053 source code from Dialog
authorZhou Jingyu <b02241@freescale.com>
Wed, 2 Mar 2011 07:36:28 +0000 (15:36 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:32:31 +0000 (08:32 +0200)
Add DA9053 original source code

Signed-off-by: Zhou Jingyu <Jingyu.Zhou@freescale.com>
Acked-by: Lily Zhang <r58066@freescale.com>
32 files changed:
drivers/gpio/da9052-gpio.c [new file with mode: 0644]
drivers/hwmon/da9052-adc.c [new file with mode: 0644]
drivers/input/misc/da9052_onkey.c [new file with mode: 0644]
drivers/input/touchscreen/da9052_tsi.c [new file with mode: 0644]
drivers/input/touchscreen/da9052_tsi_calibrate.c [new file with mode: 0644]
drivers/input/touchscreen/da9052_tsi_filter.c [new file with mode: 0644]
drivers/leds/leds-da9052.c [new file with mode: 0644]
drivers/mfd/da9052-core.c [new file with mode: 0644]
drivers/mfd/da9052-i2c.c [new file with mode: 0644]
drivers/mfd/da9052-spi.c [new file with mode: 0644]
drivers/power/da9052-battery.c [new file with mode: 0644]
drivers/regulator/da9052-regulator.c [new file with mode: 0644]
drivers/rtc/rtc-da9052.c [new file with mode: 0644]
drivers/spi/spi_sam.c [new file with mode: 0644]
drivers/video/backlight/da9052_bl.c [new file with mode: 0644]
drivers/watchdog/da9052_wdt.c [new file with mode: 0644]
include/linux/mfd/da9052/adc.h [new file with mode: 0644]
include/linux/mfd/da9052/bat.h [new file with mode: 0644]
include/linux/mfd/da9052/bl.h [new file with mode: 0644]
include/linux/mfd/da9052/da9052.h [new file with mode: 0644]
include/linux/mfd/da9052/eh.h [new file with mode: 0644]
include/linux/mfd/da9052/gpio.h [new file with mode: 0644]
include/linux/mfd/da9052/led.h [new file with mode: 0644]
include/linux/mfd/da9052/pm.h [new file with mode: 0644]
include/linux/mfd/da9052/reg.h [new file with mode: 0644]
include/linux/mfd/da9052/rtc.h [new file with mode: 0644]
include/linux/mfd/da9052/tsi.h [new file with mode: 0644]
include/linux/mfd/da9052/tsi_calibrate.h [new file with mode: 0644]
include/linux/mfd/da9052/tsi_cfg.h [new file with mode: 0644]
include/linux/mfd/da9052/tsi_filter.h [new file with mode: 0644]
include/linux/mfd/da9052/wdt.h [new file with mode: 0644]
include/linux/regulator/da9052-regulator.h [new file with mode: 0644]

diff --git a/drivers/gpio/da9052-gpio.c b/drivers/gpio/da9052-gpio.c
new file mode 100644 (file)
index 0000000..a9c53f2
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * da9052-gpio.c  --  GPIO Driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/syscalls.h>
+#include <linux/seq_file.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/gpio.h>
+
+#define DRIVER_NAME "da9052-gpio"
+static inline struct da9052_gpio_chip *to_da9052_gpio(struct gpio_chip *chip)
+{
+       return container_of(chip, struct da9052_gpio_chip, gp);
+}
+
+void da9052_gpio_notifier(struct da9052_eh_nb *eh_data, unsigned int event)
+{
+       struct da9052_gpio_chip *gpio =
+                       container_of(eh_data, struct da9052_gpio_chip, eh_data);
+       kobject_uevent(&gpio->gp.dev->kobj, KOBJ_CHANGE);
+       printk(KERN_INFO "Event received from GPIO8\n");
+}
+
+static u8 create_gpio_config_value(u8 gpio_function, u8 gpio_type, u8 gpio_mode)
+{
+       /* The format is -
+               function - 2 bits
+               type - 1 bit
+               mode - 1 bit */
+       return gpio_function | (gpio_type << 2) | (gpio_mode << 3);
+}
+
+static s32 write_default_gpio_values(struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg;
+       u8 created_val = 0;
+
+#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0001_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO0_FUNCTION,
+                       DEFAULT_GPIO0_TYPE, DEFAULT_GPIO0_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_1 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0001_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO1_FUNCTION,
+                       DEFAULT_GPIO1_TYPE, DEFAULT_GPIO1_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 2-3*/
+#if (DA9052_GPIO_PIN_2 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0203_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO2_FUNCTION,
+                       DEFAULT_GPIO2_TYPE, DEFAULT_GPIO2_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_3 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0203_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO3_FUNCTION,
+                       DEFAULT_GPIO3_TYPE, DEFAULT_GPIO3_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 4-5*/
+#if (DA9052_GPIO_PIN_4 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0405_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO4_FUNCTION,
+                       DEFAULT_GPIO4_TYPE, DEFAULT_GPIO4_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_5 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0405_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO5_FUNCTION,
+                       DEFAULT_GPIO5_TYPE, DEFAULT_GPIO5_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 6-7*/
+#if (DA9052_GPIO_PIN_6 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0607_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO6_FUNCTION,
+                       DEFAULT_GPIO6_TYPE, DEFAULT_GPIO6_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_7 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0607_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO7_FUNCTION,
+                       DEFAULT_GPIO7_TYPE, DEFAULT_GPIO7_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 8-9*/
+#if (DA9052_GPIO_PIN_8 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0809_REG;
+       msg.data = 0;
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO8_FUNCTION,
+                       DEFAULT_GPIO8_TYPE, DEFAULT_GPIO8_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_9 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO0809_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO9_FUNCTION,
+                       DEFAULT_GPIO9_TYPE, DEFAULT_GPIO9_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 10-11*/
+#if (DA9052_GPIO_PIN_10 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO1011_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO10_FUNCTION,
+                       DEFAULT_GPIO10_TYPE, DEFAULT_GPIO10_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_11 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO1011_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO11_FUNCTION,
+                       DEFAULT_GPIO11_TYPE, DEFAULT_GPIO11_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 12-13*/
+#if (DA9052_GPIO_PIN_12 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO1213_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO12_FUNCTION,
+                       DEFAULT_GPIO12_TYPE, DEFAULT_GPIO12_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_13 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO1213_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO13_FUNCTION,
+                       DEFAULT_GPIO13_TYPE, DEFAULT_GPIO13_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+/* GPIO 14-15*/
+#if (DA9052_GPIO_PIN_14 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO1415_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO14_FUNCTION,
+                       DEFAULT_GPIO14_TYPE, DEFAULT_GPIO14_MODE);
+       msg.data &= DA9052_GPIO_MASK_UPPER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+#if (DA9052_GPIO_PIN_15 == DA9052_GPIO_CONFIG)
+       da9052_lock(da9052);
+       msg.addr = DA9052_GPIO1415_REG;
+       msg.data = 0;
+
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+
+       created_val = create_gpio_config_value(DEFAULT_GPIO15_FUNCTION,
+                       DEFAULT_GPIO15_TYPE, DEFAULT_GPIO15_MODE);
+       created_val = created_val << DA9052_GPIO_NIBBLE_SHIFT;
+       msg.data &= DA9052_GPIO_MASK_LOWER_NIBBLE;
+       msg.data |= created_val;
+
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+#endif
+       return 0;
+}
+
+s32 da9052_gpio_read_port(struct da9052_gpio_read_write *read_port,
+                               struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg;
+       u8 shift_value = 0;
+       u8 port_functionality = 0;
+       msg.addr = (read_port->port_number / 2) + DA9052_GPIO0001_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+       port_functionality =
+                       (read_port->port_number % 2) ?
+                       ((msg.data & DA9052_GPIO_ODD_PORT_FUNCTIONALITY) >>
+                                       DA9052_GPIO_NIBBLE_SHIFT) :
+                       (msg.data & DA9052_GPIO_EVEN_PORT_FUNCTIONALITY);
+
+       if (port_functionality != INPUT)
+               return DA9052_GPIO_INVALID_PORTNUMBER;
+
+       if (read_port->port_number >= (DA9052_GPIO_MAX_PORTNUMBER))
+               return DA9052_GPIO_INVALID_PORTNUMBER;
+
+       if (read_port->port_number < DA9052_GPIO_MAX_PORTS_PER_REGISTER)
+               msg.addr = DA9052_STATUSC_REG;
+       else
+               msg.addr = DA9052_STATUSD_REG;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+
+       shift_value = msg.data &
+               (1 << DA9052_GPIO_SHIFT_COUNT(read_port->port_number));
+       read_port->read_write_value = (shift_value >>
+                       DA9052_GPIO_SHIFT_COUNT(read_port->port_number));
+
+       return 0;
+}
+
+s32 da9052_gpio_multiple_read(struct da9052_gpio_multiple_read *multiple_port,
+                               struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg[2];
+       u8 port_number = 0;
+       u8 loop_index = 0;
+       msg[loop_index++].addr = DA9052_STATUSC_REG;
+       msg[loop_index++].addr = DA9052_STATUSD_REG;
+
+       da9052_lock(da9052);
+       if (da9052->read_many(da9052, msg, loop_index)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+       loop_index = 0;
+       for (port_number = 0; port_number < DA9052_GPIO_MAX_PORTS_PER_REGISTER;
+                                                       port_number++) {
+               multiple_port->signal_value[port_number] =
+                       msg[loop_index].data & 1;
+               msg[loop_index].data = msg[loop_index].data >> 1;
+       }
+       loop_index++;
+       for (port_number = DA9052_GPIO_MAX_PORTS_PER_REGISTER;
+               port_number < DA9052_GPIO_MAX_PORTNUMBER; port_number++) {
+               multiple_port->signal_value[port_number] =
+                       msg[loop_index].data & 1;
+               msg[loop_index].data = msg[loop_index].data >> 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(da9052_gpio_multiple_read);
+
+s32 da9052_gpio_write_port(struct da9052_gpio_read_write *write_port,
+                               struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg;
+       u8 port_functionality  = 0;
+       u8 bit_pos = 0;
+       msg.addr = DA9052_GPIO0001_REG + (write_port->port_number / 2);
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+
+       port_functionality =
+                       (write_port->port_number % 2) ?
+                       ((msg.data & DA9052_GPIO_ODD_PORT_FUNCTIONALITY) >>
+                                               DA9052_GPIO_NIBBLE_SHIFT) :
+                       (msg.data & DA9052_GPIO_EVEN_PORT_FUNCTIONALITY);
+
+       if (port_functionality < 2)
+               return DA9052_GPIO_INVALID_PORTNUMBER;
+
+       bit_pos = (write_port->port_number % 2) ?
+                       DA9052_GPIO_ODD_PORT_WRITE_MODE :
+                               DA9052_GPIO_EVEN_PORT_WRITE_MODE;
+
+       if (write_port->read_write_value)
+               msg.data = msg.data | bit_pos;
+       else
+               msg.data = (msg.data & ~(bit_pos));
+
+       da9052_lock(da9052);
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+       return 0;
+}
+
+s32 da9052_gpio_configure_port(struct da9052_gpio *gpio_data,
+                               struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg;
+       u8 register_value = 0;
+       u8 function = 0;
+       u8 port_functionality = 0;
+       msg.addr = (gpio_data->port_number / 2) + DA9052_GPIO0001_REG;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+
+       port_functionality =
+                       (gpio_data->port_number % 2) ?
+                       ((msg.data & DA9052_GPIO_ODD_PORT_FUNCTIONALITY) >>
+                                       DA9052_GPIO_NIBBLE_SHIFT) :
+                       (msg.data & DA9052_GPIO_EVEN_PORT_FUNCTIONALITY);
+       if (port_functionality < INPUT)
+               return DA9052_GPIO_INVALID_PORTNUMBER;
+       if (gpio_data->gpio_config.input.type > ACTIVE_HIGH)
+               return DA9052_GPIO_INVALID_TYPE;
+       if (gpio_data->gpio_config.input.mode > DEBOUNCING_ON)
+               return DA9052_GPIO_INVALID_MODE;
+       function = gpio_data->gpio_function;
+       switch (function) {
+       case INPUT:
+               register_value = create_gpio_config_value(function,
+                                       gpio_data->gpio_config.input.type,
+                                       gpio_data->gpio_config.input.mode);
+       break;
+       case OUTPUT_OPENDRAIN:
+       case OUTPUT_PUSHPULL:
+               register_value = create_gpio_config_value(function,
+                                       gpio_data->gpio_config.input.type,
+                                       gpio_data->gpio_config.input.mode);
+       break;
+       default:
+               return DA9052_GPIO_INVALID_FUNCTION;
+       break;
+       }
+
+       if (gpio_data->port_number % 2) {
+               msg.data = (msg.data & ~(DA9052_GPIO_MASK_UPPER_NIBBLE)) |
+                               (register_value << DA9052_GPIO_NIBBLE_SHIFT);
+       } else {
+               msg.data = (msg.data & ~(DA9052_GPIO_MASK_LOWER_NIBBLE)) |
+                               register_value;
+       }
+       da9052_lock(da9052);
+       if (da9052->write(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return -EIO;
+       }
+       da9052_unlock(da9052);
+       return 0;
+}
+
+static s32 da9052_gpio_read(struct gpio_chip *gc, u32 offset)
+{
+       struct da9052_gpio_chip *gpio;
+       gpio = to_da9052_gpio(gc);
+       gpio->read_write.port_number            = offset;
+       da9052_gpio_read_port(&gpio->read_write, gpio->da9052);
+       return gpio->read_write.read_write_value;
+}
+
+static void da9052_gpio_write(struct gpio_chip *gc, u32 offset, s32 value)
+{
+       struct da9052_gpio_chip *gpio;
+       gpio = to_da9052_gpio(gc);
+       gpio->read_write.port_number            = offset;
+       gpio->read_write.read_write_value       = (u8)value;
+       da9052_gpio_write_port(&gpio->read_write, gpio->da9052);
+}
+
+static s32 da9052_gpio_ip(struct gpio_chip *gc, u32 offset)
+{
+       struct da9052_gpio_chip *gpio;
+       gpio = to_da9052_gpio(gc);
+       gpio->gpio.gpio_function                        = INPUT;
+       gpio->gpio.gpio_config.input.type       = ACTIVE_LOW;
+       gpio->gpio.gpio_config.input.mode       = DEBOUNCING_ON;
+       gpio->gpio.port_number                          = offset;
+       return da9052_gpio_configure_port(&gpio->gpio, gpio->da9052);
+}
+
+static s32 da9052_gpio_op(struct gpio_chip *gc, u32 offset, s32 value)
+{
+       struct da9052_gpio_chip *gpio;
+       gpio = to_da9052_gpio(gc);
+       gpio->gpio.gpio_function                = OUTPUT_PUSHPULL;
+       gpio->gpio.gpio_config.output.type      = SUPPLY_VDD_IO1;
+       gpio->gpio.gpio_config.output.mode      = value;
+       gpio->gpio.port_number                  = offset;
+       return da9052_gpio_configure_port(&gpio->gpio, gpio->da9052);
+}
+
+static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
+{
+       struct da9052_gpio_chip *gpio;
+       gpio = to_da9052_gpio(gc);
+       kobject_uevent(&gpio->gp.dev->kobj, KOBJ_CHANGE);
+       printk(KERN_INFO"gpio->gp.base +offset = %d\n", gpio->gp.base + offset);
+       printk(KERN_INFO"Test1\n\n");
+       return gpio->gp.base + offset;
+}
+
+static int __devinit da9052_gpio_probe(struct platform_device *pdev)
+{
+       struct da9052_gpio_chip *gpio;
+       struct da9052_platform_data *pdata = (pdev->dev.platform_data);
+       s32 ret;
+       gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
+       if (gpio == NULL)
+               return -ENOMEM;
+       gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
+       gpio->gp.get                    = da9052_gpio_read;
+       gpio->gp.direction_input        = da9052_gpio_ip;
+       gpio->gp.direction_output       = da9052_gpio_op;
+       gpio->gp.set                    = da9052_gpio_write;
+
+       gpio->gp.base                           = pdata->gpio_base;
+       gpio->gp.ngpio                          = DA9052_GPIO_MAX_PORTNUMBER;
+       gpio->gp.can_sleep                      = 1;
+       gpio->gp.dev                            = &pdev->dev;
+       gpio->gp.owner                          = THIS_MODULE;
+       gpio->gp.label                          = "da9052-gpio";
+       gpio->gp.to_irq                         = da9052_gpio_to_irq;
+
+       gpio->eh_data.eve_type = GPI8_EVE;
+       gpio->eh_data.call_back = &da9052_gpio_notifier;
+       ret = gpio->da9052->register_event_notifier(gpio->da9052,
+                       &gpio->eh_data);
+
+       ret = write_default_gpio_values(gpio->da9052);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "GPIO initial config failed, %d\n",
+                       ret);
+               goto ret;
+       }
+
+       ret = gpiochip_add(&gpio->gp);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
+                       ret);
+               goto ret;
+       }
+       platform_set_drvdata(pdev, gpio);
+
+       return ret;
+
+ret:
+       kfree(gpio);
+       return ret;
+
+}
+
+static int __devexit da9052_gpio_remove(struct platform_device *pdev)
+{
+       struct da9052_gpio_chip *gpio = platform_get_drvdata(pdev);
+       int ret;
+
+       gpio->da9052->unregister_event_notifier
+                       (gpio->da9052, &gpio->eh_data);
+       ret = gpiochip_remove(&gpio->gp);
+       if (ret == 0)
+               kfree(gpio);
+       return 0;
+}
+
+static struct platform_driver da9052_gpio_driver = {
+       .probe          = da9052_gpio_probe,
+       .remove         = __devexit_p(da9052_gpio_remove),
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init da9052_gpio_init(void)
+{
+       return platform_driver_register(&da9052_gpio_driver);
+}
+
+static void __exit da9052_gpio_exit(void)
+{
+       return platform_driver_unregister(&da9052_gpio_driver);
+}
+
+module_init(da9052_gpio_init);
+module_exit(da9052_gpio_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9052 GPIO Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/hwmon/da9052-adc.c b/drivers/hwmon/da9052-adc.c
new file mode 100644 (file)
index 0000000..647e580
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * da9052-adc.c  --  ADC Driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/adc.h>
+
+#define DRIVER_NAME "da9052-adc"
+
+static const char *input_names[] = {
+       [DA9052_ADC_VDDOUT]     =       "VDDOUT",
+       [DA9052_ADC_ICH]        =       "CHARGING CURRENT",
+       [DA9052_ADC_TBAT]       =       "BATTERY TEMP",
+       [DA9052_ADC_VBAT]       =       "BATTERY VOLTAGE",
+       [DA9052_ADC_ADCIN4]     =       "ADC INPUT 4",
+       [DA9052_ADC_ADCIN5]     =       "ADC INPUT 5",
+       [DA9052_ADC_ADCIN6]     =       "ADC INPUT 6",
+       [DA9052_ADC_TSI]        =       "TSI",
+       [DA9052_ADC_TJUNC]      =       "BATTERY JUNCTION TEMP",
+       [DA9052_ADC_VBBAT]      =       "BACK-UP BATTERY TEMP",
+};
+
+
+int da9052_manual_read(struct da9052 *da9052,
+                       unsigned char channel)
+{
+       unsigned char man_timeout_cnt = DA9052_ADC_MAX_MANCONV_RETRY_COUNT;
+       struct da9052_ssc_msg msg;
+       unsigned short calc_data;
+       unsigned int ret;
+       u16 data = 0;
+
+       msg.addr = DA9052_ADCMAN_REG;
+       msg.data = channel;
+       msg.data =  (msg.data | DA9052_ADCMAN_MANCONV);
+
+       mutex_lock(&da9052->manconv_lock);
+       da9052_lock(da9052);
+
+       ret = da9052->write(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+
+       /* Wait for the event */
+       do {
+               msg.addr = DA9052_ADCCONT_REG;
+               msg.data = 0;
+               da9052_lock(da9052);
+               ret = da9052->read(da9052, &msg);
+               if (ret)
+                       goto err_ssc_comm;
+               da9052_unlock(da9052);
+
+               if (DA9052_ADCCONT_ADCMODE & msg.data)
+                       msleep(1);
+               else
+                       msleep(10);
+
+               msg.addr = DA9052_ADCMAN_REG;
+               msg.data = 0;
+               da9052_lock(da9052);
+               ret = da9052->read(da9052, &msg);
+               if (ret)
+                       goto err_ssc_comm;
+               da9052_unlock(da9052);
+
+               /* Counter to avoid endless while loop */
+               man_timeout_cnt--;
+               if (man_timeout_cnt == 1) {
+                       if (!(msg.data & DA9052_ADCMAN_MANCONV))
+                               break;
+                       else
+                               goto err_ssc_comm;
+               }
+       /* Wait until the MAN_CONV bit is cleared to zero */
+       } while (msg.data & DA9052_ADCMAN_MANCONV);
+
+       msg.addr = DA9052_ADCRESH_REG;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+
+       calc_data = (unsigned short)msg.data;
+       data = (calc_data << 2);
+
+       msg.addr = DA9052_ADCRESL_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+
+       /* Clear first 14 bits before ORing */
+       calc_data = (unsigned short)msg.data & 0x0003;
+       data |= calc_data;
+
+       mutex_unlock(&da9052->manconv_lock);
+
+       return data;
+err_ssc_comm:
+       mutex_unlock(&da9052->manconv_lock);
+       da9052_unlock(da9052);
+       return -EIO;
+}
+EXPORT_SYMBOL(da9052_manual_read);
+
+int da9052_read_tjunc(struct da9052 *da9052, char *buf)
+{
+       struct da9052_ssc_msg msg;
+       unsigned char temp;
+       int ret;
+
+       msg.addr = DA9052_TJUNCRES_REG;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+
+       temp = msg.data;
+
+       msg.addr = DA9052_TOFFSET_REG;
+       msg.data = 0;
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+       /* Calculate Junction temperature */
+       temp = (temp - msg.data);
+       *buf = temp;
+       return 0;
+err_ssc_comm:
+       da9052_unlock(da9052);
+       return -EIO;
+}
+EXPORT_SYMBOL(da9052_read_tjunc);
+
+int da9052_read_tbat_ich(struct da9052 *da9052, char *data, int channel_no)
+{
+       struct da9052_ssc_msg msg;
+       int ret;
+
+       /* Read TBAT conversion result */
+       switch (channel_no) {
+       case DA9052_ADC_TBAT:
+               msg.addr = DA9052_TBATRES_REG;
+       break;
+       case DA9052_ADC_ICH:
+               msg.addr = DA9052_ICHGAV_REG;
+       break;
+       default:
+               return -EINVAL;
+       }
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+       *data = msg.data;
+       printk(KERN_INFO"msg.data 1= %d\n", msg.data);
+       msg.data = 28;
+       da9052_lock(da9052);
+       ret = da9052->write(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+       printk(KERN_INFO"msg.data2 = %d\n", msg.data);
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+       printk(KERN_INFO"msg.data3 = %d\n", msg.data);
+       return 0;
+
+err_ssc_comm:
+       da9052_unlock(da9052);
+       return ret;
+}
+EXPORT_SYMBOL(da9052_read_tbat_ich);
+
+static int da9052_start_adc(struct da9052 *da9052, unsigned channel)
+{
+       struct da9052_ssc_msg msg;
+       int ret;
+
+       msg.addr = DA9052_ADCCONT_REG;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+
+       if (channel == DA9052_ADC_VDDOUT)
+               msg.data = (msg.data | DA9052_ADCCONT_AUTOVDDEN);
+       else if (channel == DA9052_ADC_ADCIN4)
+               msg.data = (msg.data | DA9052_ADCCONT_AUTOAD4EN);
+       else if (channel == DA9052_ADC_ADCIN5)
+               msg.data = (msg.data | DA9052_ADCCONT_AUTOAD5EN);
+       else if (channel == DA9052_ADC_ADCIN6)
+               msg.data = (msg.data | DA9052_ADCCONT_AUTOAD6EN);
+       else
+               return -EINVAL;
+
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+       return 0;
+
+err_ssc_comm:
+       da9052_unlock(da9052);
+       return -EIO;
+}
+
+static int da9052_stop_adc(struct da9052 *da9052, unsigned channel)
+{
+       int ret;
+       struct da9052_ssc_msg msg;
+
+       msg.addr = DA9052_ADCCONT_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+
+       if (channel == DA9052_ADC_VDDOUT)
+               msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOVDDEN));
+       else if (channel == DA9052_ADC_ADCIN4)
+               msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD4EN));
+       else if (channel == DA9052_ADC_ADCIN5)
+               msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD5EN));
+       else if (channel == DA9052_ADC_ADCIN6)
+               msg.data =  (msg.data & ~(DA9052_ADCCONT_AUTOAD6EN));
+       else
+               return -EINVAL;
+
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+
+       return 0;
+err_ssc_comm:
+       da9052_unlock(da9052);
+       return -EIO;
+}
+
+static ssize_t da9052_adc_read_start_stop(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+       struct da9052_ssc_msg msg;
+       int channel = to_sensor_dev_attr(devattr)->index;
+       int ret;
+
+       ret = da9052_start_adc(priv->da9052, channel);
+       if (ret < 0)
+               return ret;
+
+       /* Read the ADC converted value */
+       switch (channel) {
+       case DA9052_ADC_VDDOUT:
+               msg.addr = DA9052_VDDRES_REG;
+       break;
+#if (DA9052_ADC_CONF_ADC4 == 1)
+       case DA9052_ADC_ADCIN4:
+               msg.addr = DA9052_ADCIN4RES_REG;
+       break;
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+       case DA9052_ADC_ADCIN5:
+               msg.addr = DA9052_ADCIN5RES_REG;
+       break;
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+       case DA9052_ADC_ADCIN6:
+               msg.addr = DA9052_ADCIN6RES_REG;
+       break;
+#endif
+       default:
+               return -EINVAL;
+       }
+       msg.data = 0;
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(priv->da9052);
+
+       ret = da9052_stop_adc(priv->da9052, channel);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%u\n", msg.data);
+
+err_ssc_comm:
+       da9052_unlock(priv->da9052);
+       return ret;
+}
+
+static ssize_t da9052_adc_read_ich(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = da9052_read_tbat_ich(priv->da9052, buf, DA9052_ADC_ICH);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%u\n", *buf);
+}
+
+static ssize_t da9052_adc_read_tbat(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = da9052_read_tbat_ich(priv->da9052, buf, DA9052_ADC_TBAT);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%u\n", *buf);
+}
+
+static ssize_t da9052_adc_read_vbat(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+       s32 ret;
+
+       ret = da9052_manual_read(priv->da9052, DA9052_ADC_VBAT);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%u\n", ret);
+}
+
+static ssize_t da9052_adc_read_tjunc(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+       int ret;
+       ret = da9052_read_tjunc(priv->da9052, buf);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%u\n", *buf);
+}
+
+static ssize_t da9052_adc_read_vbbat(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+       s32 ret;
+
+       ret = da9052_manual_read(priv->da9052, DA9052_ADC_VBBAT);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%u\n", ret);
+}
+
+static int da9052_adc_hw_init(struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg;
+       int ret;
+
+       /* ADC channel 4 and 5 are by default enabled */
+#if (DA9052_ADC_CONF_ADC4 == 1)
+       msg.addr = DA9052_GPIO0001_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+
+       msg.data = (msg.data & ~(DA9052_GPIO0001_GPIO0PIN));
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+#endif
+
+#if (DA9052_ADC_CONF_ADC5 == 1)
+       msg.addr = DA9052_GPIO0001_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+
+       msg.data = (msg.data & ~(DA9052_GPIO0001_GPIO0PIN));
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+#endif
+
+#if (DA9052_ADC_CONF_ADC6 == 1)
+       msg.addr = DA9052_GPIO0203_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto err_ssc_comm;
+
+       msg.data = (msg.data & ~(DA9052_GPIO0203_GPIO2PIN));
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+#endif
+#if 0
+       /* By default configure the Measurement sequence interval to 10ms */
+       msg.addr = DA9052_ADCCONT_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+
+       /* Set the ADC MODE bit for 10msec sampling timer */
+       msg.data = (msg.data & ~(DA9052_ADCCONT_ADCMODE));
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0)
+               goto err_ssc_comm;
+       da9052_unlock(da9052);
+#endif
+       return 0;
+err_ssc_comm:
+       da9052_unlock(da9052);
+       return -EIO;
+}
+
+static ssize_t da9052_adc_show_name(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       return sprintf(buf, "da9052-adc\n");
+}
+
+static ssize_t show_label(struct device *dev,
+                         struct device_attribute *devattr, char *buf)
+{
+       int channel = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%s\n", input_names[channel]);
+}
+#define DA9052_ADC_CHANNELS(id, name) \
+       static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \
+                                 NULL, name)
+
+DA9052_ADC_CHANNELS(0, DA9052_ADC_VDDOUT);
+DA9052_ADC_CHANNELS(1, DA9052_ADC_ICH);
+DA9052_ADC_CHANNELS(2, DA9052_ADC_TBAT);
+DA9052_ADC_CHANNELS(3, DA9052_ADC_VBAT);
+#if (DA9052_ADC_CONF_ADC4 == 1)
+DA9052_ADC_CHANNELS(4, DA9052_ADC_ADCIN4);
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+DA9052_ADC_CHANNELS(5, DA9052_ADC_ADCIN5);
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+DA9052_ADC_CHANNELS(6, DA9052_ADC_ADCIN6);
+#endif
+DA9052_ADC_CHANNELS(7, DA9052_ADC_TSI);
+DA9052_ADC_CHANNELS(8, DA9052_ADC_TJUNC);
+DA9052_ADC_CHANNELS(9, DA9052_ADC_VBBAT);
+
+
+static DEVICE_ATTR(name, S_IRUGO, da9052_adc_show_name, NULL);
+static SENSOR_DEVICE_ATTR(read_vddout, S_IRUGO,
+                               da9052_adc_read_start_stop, NULL,
+                               DA9052_ADC_VDDOUT);
+static SENSOR_DEVICE_ATTR(read_ich, S_IRUGO, da9052_adc_read_ich, NULL,
+                               DA9052_ADC_ICH);
+static SENSOR_DEVICE_ATTR(read_tbat, S_IRUGO, da9052_adc_read_tbat, NULL,
+                               DA9052_ADC_TBAT);
+static SENSOR_DEVICE_ATTR(read_vbat, S_IRUGO, da9052_adc_read_vbat, NULL,
+                               DA9052_ADC_VBAT);
+#if (DA9052_ADC_CONF_ADC4 == 1)
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, da9052_adc_read_start_stop, NULL,
+                               DA9052_ADC_ADCIN4);
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, da9052_adc_read_start_stop, NULL,
+                               DA9052_ADC_ADCIN5);
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, da9052_adc_read_start_stop, NULL,
+                               DA9052_ADC_ADCIN6);
+#endif
+static SENSOR_DEVICE_ATTR(read_tjunc, S_IRUGO, da9052_adc_read_tjunc, NULL,
+                               DA9052_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(read_vbbat, S_IRUGO, da9052_adc_read_vbbat, NULL,
+                               DA9052_ADC_VBBAT);
+
+static struct attribute *da9052_attr[] = {
+       &dev_attr_name.attr,
+       &sensor_dev_attr_read_vddout.dev_attr.attr,
+       &sensor_dev_attr_in0_label.dev_attr.attr,
+       &sensor_dev_attr_read_ich.dev_attr.attr,
+       &sensor_dev_attr_in1_label.dev_attr.attr,
+       &sensor_dev_attr_read_tbat.dev_attr.attr,
+       &sensor_dev_attr_in2_label.dev_attr.attr,
+       &sensor_dev_attr_read_vbat.dev_attr.attr,
+       &sensor_dev_attr_in3_label.dev_attr.attr,
+#if (DA9052_ADC_CONF_ADC4 == 1)
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_label.dev_attr.attr,
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in5_label.dev_attr.attr,
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in6_label.dev_attr.attr,
+#endif
+       &sensor_dev_attr_in7_label.dev_attr.attr,
+       &sensor_dev_attr_read_tjunc.dev_attr.attr,
+       &sensor_dev_attr_in8_label.dev_attr.attr,
+       &sensor_dev_attr_read_vbbat.dev_attr.attr,
+       &sensor_dev_attr_in9_label.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group da9052_group = {
+       .attrs = da9052_attr,
+};
+
+static int __init da9052_adc_probe(struct platform_device *pdev)
+{
+       struct da9052_adc_priv *priv;
+       int ret;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->da9052 = dev_get_drvdata(pdev->dev.parent);
+
+       platform_set_drvdata(pdev, priv);
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&pdev->dev.kobj, &da9052_group);
+       if (ret)
+               goto out_err_create1;
+
+       priv->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(priv->hwmon_dev)) {
+               ret = PTR_ERR(priv->hwmon_dev);
+               goto out_err_create2;
+       }
+       /* Initializes the hardware for ADC module */
+       da9052_adc_hw_init(priv->da9052);
+
+       /* Initialize mutex required for ADC Manual read */
+       mutex_init(&priv->da9052->manconv_lock);
+
+       return 0;
+
+out_err_create2:
+       sysfs_remove_group(&pdev->dev.kobj, &da9052_group);
+out_err_create1:
+       platform_set_drvdata(pdev, NULL);
+       kfree(priv);
+
+       return ret;
+}
+
+static int __devexit da9052_adc_remove(struct platform_device *pdev)
+{
+       struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+
+       mutex_destroy(&priv->da9052->manconv_lock);
+
+       hwmon_device_unregister(priv->hwmon_dev);
+
+       sysfs_remove_group(&pdev->dev.kobj, &da9052_group);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(priv);
+
+       return 0;
+}
+
+static struct platform_driver da9052_adc_driver = {
+       .remove         = __devexit_p(da9052_adc_remove),
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init da9052_adc_init(void)
+{
+       return platform_driver_probe(&da9052_adc_driver, da9052_adc_probe);
+}
+module_init(da9052_adc_init);
+
+static void __exit da9052_adc_exit(void)
+{
+       platform_driver_unregister(&da9052_adc_driver);
+}
+module_exit(da9052_adc_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>")
+MODULE_DESCRIPTION("DA9052 ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
new file mode 100644 (file)
index 0000000..2271b59
--- /dev/null
@@ -0,0 +1,133 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+#define DRIVER_NAME "da9052-onkey"
+
+struct da9052_onkey_data {
+       struct da9052 *da9052;
+       struct da9052_eh_nb eh_data;
+       struct input_dev *input;
+};
+
+static void da9052_onkey_report_event(struct da9052_eh_nb *eh_data,
+                               unsigned int event)
+{
+       struct da9052_onkey_data *da9052_onkey =
+               container_of(eh_data, struct da9052_onkey_data, eh_data);
+       struct da9052_ssc_msg msg;
+       unsigned int ret;
+
+       /* Read the Evnet Register */
+       msg.addr = DA9052_EVENTB_REG;
+       da9052_lock(da9052_onkey->da9052);
+       ret = da9052_onkey->da9052->read(da9052_onkey->da9052, &msg);
+       if (ret) {
+               da9052_unlock(da9052_onkey->da9052);
+               return;
+       }
+       da9052_unlock(da9052_onkey->da9052);
+       msg.data = msg.data & DA9052_EVENTB_ENONKEY;
+
+       input_report_key(da9052_onkey->input, KEY_POWER, msg.data);
+       input_sync(da9052_onkey->input);
+       printk(KERN_INFO "DA9052 ONKEY EVENT REPORTED \n");
+}
+
+static int __devinit da9052_onkey_probe(struct platform_device *pdev)
+{
+       struct da9052_onkey_data *da9052_onkey;
+       int error;
+
+       da9052_onkey = kzalloc(sizeof(*da9052_onkey), GFP_KERNEL);
+       da9052_onkey->input = input_allocate_device();
+       if (!da9052_onkey->input) {
+               dev_err(&pdev->dev, "failed to allocate data device\n");
+               error = -ENOMEM;
+               goto fail1;
+       }
+       da9052_onkey->da9052 = dev_get_drvdata(pdev->dev.parent);
+
+       if (!da9052_onkey->input) {
+               dev_err(&pdev->dev, "failed to allocate input device\n");
+               error = -ENOMEM;
+               goto fail2;
+       }
+
+       da9052_onkey->input->evbit[0] = BIT_MASK(EV_KEY);
+       da9052_onkey->input->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+       da9052_onkey->input->name = "da9052-onkey";
+       da9052_onkey->input->phys = "da9052-onkey/input0";
+       da9052_onkey->input->dev.parent = &pdev->dev;
+
+       /* Set the EH structure */
+       da9052_onkey->eh_data.eve_type = ONKEY_EVE;
+       da9052_onkey->eh_data.call_back = &da9052_onkey_report_event;
+       error = da9052_onkey->da9052->register_event_notifier(
+                               da9052_onkey->da9052,
+                               &da9052_onkey->eh_data);
+       if (error)
+               goto fail2;
+
+       error = input_register_device(da9052_onkey->input);
+       if (error) {
+               dev_err(&pdev->dev, "Unable to register input\
+                               device,error: %d\n", error);
+               goto fail3;
+       }
+
+       platform_set_drvdata(pdev, da9052_onkey);
+
+       return 0;
+
+fail3:
+       da9052_onkey->da9052->unregister_event_notifier(da9052_onkey->da9052,
+                                       &da9052_onkey->eh_data);
+fail2:
+       input_free_device(da9052_onkey->input);
+fail1:
+       kfree(da9052_onkey);
+       return error;
+}
+
+static int __devexit da9052_onkey_remove(struct platform_device *pdev)
+{
+       struct da9052_onkey_data *da9052_onkey = pdev->dev.platform_data;
+       da9052_onkey->da9052->unregister_event_notifier(da9052_onkey->da9052,
+                                       &da9052_onkey->eh_data);
+       input_unregister_device(da9052_onkey->input);
+       kfree(da9052_onkey);
+
+       return 0;
+}
+
+static struct platform_driver da9052_onkey_driver = {
+       .probe          = da9052_onkey_probe,
+       .remove         = __devexit_p(da9052_onkey_remove),
+       .driver         = {
+               .name   = "da9052-onkey",
+               .owner  = THIS_MODULE,
+       }
+};
+
+static int __init da9052_onkey_init(void)
+{
+       return platform_driver_register(&da9052_onkey_driver);
+}
+
+static void __exit da9052_onkey_exit(void)
+{
+       platform_driver_unregister(&da9052_onkey_driver);
+}
+
+module_init(da9052_onkey_init);
+module_exit(da9052_onkey_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Onkey driver for DA9052");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
new file mode 100644 (file)
index 0000000..3b79cf3
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ * da9052_tsi.c  --  TSI driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
+
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/tsi_cfg.h>
+#include <linux/mfd/da9052/tsi.h>
+#include <linux/mfd/da9052/gpio.h>
+#include <linux/mfd/da9052/adc.h>
+
+#define WAIT_FOR_PEN_DOWN      0
+#define WAIT_FOR_SAMPLING      1
+#define SAMPLING_ACTIVE                2
+
+static ssize_t __init da9052_tsi_create_input_dev(struct input_dev **ip_dev,
+                                       u8 n);
+static ssize_t read_da9052_reg(struct da9052 *da9052, u8 reg_addr);
+static ssize_t write_da9052_reg(struct da9052 *da9052, u8 reg_addr, u8 data);
+
+static void da9052_tsi_reg_pendwn_event(struct da9052_ts_priv *priv);
+static void da9052_tsi_reg_datardy_event(struct da9052_ts_priv *priv);
+static ssize_t da9052_tsi_config_delay(struct da9052_ts_priv *priv,
+                                       enum TSI_DELAY delay);
+static ssize_t da9052_tsi_config_measure_seq(struct da9052_ts_priv *priv,
+                                       enum TSI_MEASURE_SEQ seq);
+static ssize_t da9052_tsi_config_state(struct da9052_ts_priv *ts,
+                                       enum TSI_STATE state);
+static ssize_t da9052_tsi_set_sampling_mode(struct da9052_ts_priv *priv,
+                                       u8 interval);
+static ssize_t da9052_tsi_config_skip_slots(struct da9052_ts_priv *priv,
+                                       enum TSI_SLOT_SKIP skip);
+static ssize_t da9052_tsi_config_pen_detect(struct da9052_ts_priv *priv,
+                                       u8 flag);
+static ssize_t da9052_tsi_disable_irq(struct da9052_ts_priv *priv,
+                                       enum TSI_IRQ tsi_irq);
+static ssize_t da9052_tsi_enable_irq(struct da9052_ts_priv *priv,
+                                       enum TSI_IRQ tsi_irq);
+static ssize_t da9052_tsi_config_manual_mode(struct da9052_ts_priv *priv,
+                                       u8 coordinate);
+static ssize_t da9052_tsi_config_auto_mode(struct da9052_ts_priv *priv,
+                                       u8 state);
+static ssize_t da9052_tsi_config_gpio(struct da9052_ts_priv *priv);
+static ssize_t da9052_tsi_config_power_supply(struct da9052_ts_priv *priv,
+                                       u8 state);
+static struct da9052_tsi_info *get_tsi_drvdata(void);
+static void da9052_tsi_penup_event(struct da9052_ts_priv *priv);
+static s32 da9052_tsi_get_rawdata(struct da9052_tsi_reg *buf, u8 cnt);
+static ssize_t da9052_tsi_reg_proc_thread(void *ptr);
+static ssize_t da9052_tsi_resume(struct platform_device *dev);
+static ssize_t da9052_tsi_suspend(struct platform_device *dev,
+                                       pm_message_t state);
+struct da9052_tsi tsi_reg;
+struct da9052_tsi_info gda9052_tsi_info;
+
+static ssize_t write_da9052_reg(struct da9052 *da9052, u8 reg_addr, u8 data)
+{
+       ssize_t ret = 0;
+       struct da9052_ssc_msg ssc_msg;
+
+       ssc_msg.addr =  reg_addr;
+       ssc_msg.data =  data;
+       ret = da9052->write(da9052, &ssc_msg);
+       if (ret) {
+               DA9052_DEBUG("%s: ",__FUNCTION__);
+               DA9052_DEBUG("da9052_ssc_write Failed %d\n",ret );
+       }
+
+       return ret;
+}
+
+static ssize_t read_da9052_reg(struct da9052 *da9052, u8 reg_addr)
+{
+        ssize_t ret = 0;
+        struct da9052_ssc_msg ssc_msg;
+
+       ssc_msg.addr =  reg_addr;
+       ssc_msg.data =  0;
+       ret = da9052->read(da9052, &ssc_msg);
+       if (ret) {
+               DA9052_DEBUG("%s: ",__FUNCTION__);
+               DA9052_DEBUG("da9052_ssc_read Failed => %d\n" ,ret);
+               return -ret;
+       }
+       return ssc_msg.data;
+}
+
+static struct da9052_tsi_info *get_tsi_drvdata(void)
+{
+       return &gda9052_tsi_info;
+}
+
+static ssize_t da9052_tsi_config_measure_seq(struct da9052_ts_priv *priv,
+                                               enum TSI_MEASURE_SEQ seq)
+{
+       ssize_t ret = 0;
+       u8 data = 0;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (seq > 1)
+               return -EINVAL;
+
+       da9052_lock(priv->da9052);
+       ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       data = (u8)ret;
+
+       if (seq == XYZP_MODE)
+               data = enable_xyzp_mode(data);
+       else if (seq == XP_MODE)
+               data = enable_xp_mode(data);
+       else {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("Invalid Value passed \n" );
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data;
+
+       return 0;
+}
+
+static ssize_t da9052_tsi_set_sampling_mode(struct da9052_ts_priv *priv,
+                                       u8 mode)
+{
+       u8 data = 0;
+       ssize_t ret = 0;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       da9052_lock(priv->da9052);
+
+       ret = read_da9052_reg(priv->da9052, DA9052_ADCCONT_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("DA9052_TSI:%s:", __FUNCTION__);
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       data = (u8)ret;
+
+       if (mode == ECONOMY_MODE)
+               data = adc_mode_economy_mode(data);
+       else if (mode == FAST_MODE)
+               data = adc_mode_fast_mode(data);
+       else {
+               DA9052_DEBUG("DA9052_TSI:%s:", __FUNCTION__);
+               DA9052_DEBUG("Invalid interval passed \n" );
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       ret = write_da9052_reg(priv->da9052, DA9052_ADCCONT_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI:%s:", __FUNCTION__);
+               DA9052_DEBUG("write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       switch (mode) {
+       case ECONOMY_MODE:
+               priv->tsi_reg_data_poll_interval =
+                       TSI_ECO_MODE_REG_DATA_PROCESSING_INTERVAL;
+               priv->tsi_raw_data_poll_interval =
+                       TSI_ECO_MODE_RAW_DATA_PROCESSING_INTERVAL;
+               break;
+       case FAST_MODE:
+               priv->tsi_reg_data_poll_interval =
+                       TSI_FAST_MODE_REG_DATA_PROCESSING_INTERVAL;
+               priv->tsi_raw_data_poll_interval =
+                       TSI_FAST_MODE_RAW_DATA_PROCESSING_INTERVAL;
+               break;
+       default:
+               DA9052_DEBUG("DA9052_TSI:%s:", __FUNCTION__);
+               DA9052_DEBUG("Invalid interval passed \n" );
+               return -EINVAL;
+       }
+
+       ts->tsi_penup_count =
+               (u32)priv->tsi_pdata->pen_up_interval /
+               priv->tsi_reg_data_poll_interval;
+
+       return 0;
+}
+
+static ssize_t da9052_tsi_config_delay(struct da9052_ts_priv *priv,
+                                       enum TSI_DELAY delay)
+{
+       ssize_t ret = 0;
+       u8 data = 0;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (delay > priv->tsi_pdata->max_tsi_delay) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" invalid value for tsi delay!!!\n" );
+               return -EINVAL;
+       }
+
+       da9052_lock(priv->da9052);
+
+       ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
+       if(ret < 0) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       data = clear_bits((u8)ret, DA9052_TSICONTA_TSIDELAY);
+
+       data = set_bits(data, (delay << priv->tsi_pdata->tsi_delay_bit_shift));
+
+       ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data;
+
+       return 0;
+}
+
+ssize_t da9052_tsi_config_skip_slots(struct da9052_ts_priv *priv,
+                                       enum TSI_SLOT_SKIP skip)
+{
+       ssize_t ret = 0;
+       u8 data = 0;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (skip > priv->tsi_pdata->max_tsi_skip_slot) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" invalid value for tsi skip slots!!!\n" );
+               return -EINVAL;
+       }
+
+       da9052_lock(priv->da9052);
+
+       ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       data = clear_bits((u8)ret, DA9052_TSICONTA_TSISKIP);
+
+       data = set_bits(data, (skip << priv->tsi_pdata->tsi_skip_bit_shift));
+
+       ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_config_skip_slots:");
+               DA9052_DEBUG(" write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data;
+
+       return 0;
+}
+
+static ssize_t da9052_tsi_config_state(struct da9052_ts_priv *priv,
+                                       enum TSI_STATE state)
+{
+       s32 ret;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (ts->tsi_conf.state == state)
+               return 0;
+
+       switch (state) {
+       case TSI_AUTO_MODE:
+               ts->tsi_zero_data_cnt = 0;
+               priv->early_data_flag = TRUE;
+               priv->debounce_over = FALSE;
+               priv->win_reference_valid = FALSE;
+
+               clean_tsi_fifos(priv);
+
+               ret = da9052_tsi_config_auto_mode(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               ret = da9052_tsi_config_manual_mode(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               ret = da9052_tsi_config_power_supply(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               ret = da9052_tsi_enable_irq(priv, TSI_PEN_DWN);
+               if (ret)
+                       return ret;
+               ts->tsi_conf.tsi_pendown_irq_mask = RESET;
+
+               ret = da9052_tsi_disable_irq(priv, TSI_DATA_RDY);
+               if (ret)
+                       return ret;
+               ts->tsi_conf.tsi_ready_irq_mask   = SET;
+
+               da9052_tsi_reg_pendwn_event(priv);
+               da9052_tsi_reg_datardy_event(priv);
+
+               ret = da9052_tsi_config_pen_detect(priv, ENABLE);
+               if (ret)
+                       return ret;
+               break;
+
+       case TSI_IDLE:
+               ts->pen_dwn_event = RESET;
+
+               ret = da9052_tsi_config_pen_detect(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               ret = da9052_tsi_config_auto_mode(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               ret = da9052_tsi_config_manual_mode(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               ret = da9052_tsi_config_power_supply(priv, DISABLE);
+               if (ret)
+                       return ret;
+
+               if (ts->pd_reg_status) {
+                       priv->da9052->unregister_event_notifier(priv->da9052,
+                                                               &priv->pd_nb);
+               ts->pd_reg_status = RESET;
+               }
+               break;
+
+       default:
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" Invalid state passed");
+               return -EINVAL;
+       }
+
+       ts->tsi_conf.state = state;
+
+       return 0;
+}
+
+static void da9052_tsi_reg_pendwn_event(struct da9052_ts_priv *priv)
+{
+       ssize_t ret = 0;
+       struct da9052_tsi_info  *ts = get_tsi_drvdata();
+
+       if (ts->pd_reg_status) {
+               DA9052_DEBUG("%s: Pen down ",__FUNCTION__);
+               DA9052_DEBUG("Registeration is already done \n");
+               return;
+       }
+
+       priv->pd_nb.eve_type = PEN_DOWN_EVE;
+       priv->pd_nb.call_back = &da9052_tsi_pen_down_handler;
+
+       ret = priv->da9052->register_event_notifier(priv->da9052, &priv->pd_nb);
+       if (ret) {
+               DA9052_DEBUG("%s: EH Registeration",__FUNCTION__);
+               DA9052_DEBUG(" Failed: ret = %d\n",ret );
+               ts->pd_reg_status = RESET;
+       } else
+               ts->pd_reg_status = SET;
+
+       priv->os_data_cnt = 0;
+       priv->raw_data_cnt = 0;
+
+       return;
+}
+
+static void da9052_tsi_reg_datardy_event(struct da9052_ts_priv *priv)
+{
+       ssize_t ret = 0;
+       struct da9052_tsi_info  *ts = get_tsi_drvdata();
+
+       if(ts->datardy_reg_status)
+       {
+               DA9052_DEBUG("%s: Data Ready ",__FUNCTION__);
+               DA9052_DEBUG("Registeration is already done \n");
+               return;
+       }
+
+       priv->datardy_nb.eve_type = TSI_READY_EVE;
+       priv->datardy_nb.call_back = &da9052_tsi_data_ready_handler;
+
+       ret = priv->da9052->register_event_notifier(priv->da9052,
+                                               &priv->datardy_nb);
+
+       if(ret)
+       {
+               DA9052_DEBUG("%s: EH Registeration",__FUNCTION__);
+               DA9052_DEBUG(" Failed: ret = %d\n",ret );
+               ts->datardy_reg_status = RESET;
+       } else
+               ts->datardy_reg_status = SET;
+
+       return;
+}
+
+static ssize_t __init da9052_tsi_create_input_dev(struct input_dev **ip_dev,
+                                                       u8 n)
+{
+       u8 i;
+       s32 ret;
+       struct input_dev *dev = NULL;
+
+       if (!n)
+               return -EINVAL;
+
+       for (i = 0; i < n; i++) {
+               dev = input_allocate_device();
+               if (!dev) {
+                       DA9052_DEBUG(KERN_ERR "%s:%s():memory allocation for \
+                                       inputdevice failed\n", __FILE__,
+                                                               __FUNCTION__);
+                       return -ENOMEM;
+               }
+
+               ip_dev[i] = dev;
+               switch (i) {
+               case TSI_INPUT_DEVICE_OFF:
+                       dev->name = DA9052_TSI_INPUT_DEV;
+                       dev->phys = "input(tsi)";
+                       break;
+               default:
+                       break;
+               }
+       }
+       dev->id.vendor = DA9052_VENDOR_ID;
+       dev->id.product = DA9052_PRODUCT_ID;
+       dev->id.bustype = BUS_RS232;
+       dev->id.version = TSI_VERSION;
+       dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       dev->evbit[0] = (BIT_MASK(EV_SYN) |
+                       BIT_MASK(EV_KEY) |
+                       BIT_MASK(EV_ABS));
+
+       input_set_abs_params(dev, ABS_X, 0, DA9052_DISPLAY_X_MAX, 0, 0);
+       input_set_abs_params(dev, ABS_Y, 0, DA9052_DISPLAY_Y_MAX, 0, 0);
+       input_set_abs_params(dev, ABS_PRESSURE, 0, DA9052_TOUCH_PRESSURE_MAX,
+                               0, 0);
+
+       ret = input_register_device(dev);
+       if (ret) {
+               DA9052_DEBUG(KERN_ERR "%s: Could ", __FUNCTION__);
+               DA9052_DEBUG("not register input device(touchscreen)!\n");
+               ret = -EIO;
+               goto fail;
+       }
+       return 0;
+
+fail:
+       for (; i-- != 0; )
+               input_free_device(ip_dev[i]);
+       return -EINVAL;
+}
+
+static ssize_t __init da9052_tsi_init_drv(struct da9052_ts_priv *priv)
+{
+       u8 cnt = 0;
+       ssize_t ret = 0;
+       struct da9052_tsi_info  *ts = get_tsi_drvdata();
+
+       if ((DA9052_GPIO_PIN_3 != DA9052_GPIO_CONFIG_TSI) ||
+               (DA9052_GPIO_PIN_4 != DA9052_GPIO_CONFIG_TSI) ||
+               (DA9052_GPIO_PIN_5 != DA9052_GPIO_CONFIG_TSI) ||
+               (DA9052_GPIO_PIN_6 != DA9052_GPIO_CONFIG_TSI) ||
+               (DA9052_GPIO_PIN_7 != DA9052_GPIO_CONFIG_TSI)) {
+               printk(KERN_ERR"DA9052_TSI: Configure DA9052 GPIO ");
+               printk(KERN_ERR"pins for TSI\n");
+               return -EINVAL;
+       }
+
+       ret = da9052_tsi_config_gpio(priv);
+
+       ret = da9052_tsi_config_state(priv, TSI_IDLE);
+       ts->tsi_conf.state = TSI_IDLE;
+
+       da9052_tsi_config_measure_seq(priv, TSI_MODE_VALUE);
+
+       da9052_tsi_config_skip_slots(priv, TSI_SLOT_SKIP_VALUE);
+
+       da9052_tsi_config_delay(priv, TSI_DELAY_VALUE);
+
+       da9052_tsi_set_sampling_mode(priv, DEFAULT_TSI_SAMPLING_MODE);
+
+       ts->tsi_calib = get_calib_config();
+
+       ret = da9052_tsi_create_input_dev(ts->input_devs, NUM_INPUT_DEVS);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s: ", __FUNCTION__);
+               DA9052_DEBUG("da9052_tsi_create_input_dev Failed \n" );
+               return ret;
+       }
+
+       da9052_init_tsi_fifos(priv);
+
+       init_completion(&priv->tsi_reg_proc_thread.notifier);
+       priv->tsi_reg_proc_thread.state = ACTIVE;
+       priv->tsi_reg_proc_thread.pid =
+                               kernel_thread(da9052_tsi_reg_proc_thread,
+                                       priv, CLONE_KERNEL | SIGCHLD);
+
+       init_completion(&priv->tsi_raw_proc_thread.notifier);
+       priv->tsi_raw_proc_thread.state = ACTIVE;
+       priv->tsi_raw_proc_thread.pid =
+                               kernel_thread(da9052_tsi_raw_proc_thread,
+                                       priv, CLONE_KERNEL | SIGCHLD);
+
+       ret = da9052_tsi_config_state(priv, DEFAULT_TSI_STATE);
+       if (ret) {
+               for (cnt = 0; cnt < NUM_INPUT_DEVS; cnt++) {
+                       if (ts->input_devs[cnt] != NULL)
+                               input_free_device(ts->input_devs[cnt]);
+               }
+       }
+
+       return 0;
+}
+
+u32 da9052_tsi_get_input_dev(u8 off)
+{
+       struct da9052_tsi_info   *ts = get_tsi_drvdata();
+
+       if (off > NUM_INPUT_DEVS-1)
+               return -EINVAL;
+
+       return (u32)ts->input_devs[off];
+}
+
+static ssize_t da9052_tsi_config_pen_detect(struct da9052_ts_priv *priv,
+                                               u8 flag)
+{
+       u8 data;
+       u32 ret;
+       struct da9052_tsi_info  *ts = get_tsi_drvdata();
+
+       da9052_lock(priv->da9052);
+       ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("%s:", __FUNCTION__);
+               DA9052_DEBUG(" read_da9052_reg  Failed\n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       if (flag == ENABLE)
+               data = set_bits((u8)ret, DA9052_TSICONTA_PENDETEN);
+       else if (flag == DISABLE)
+               data = clear_bits((u8)ret, DA9052_TSICONTA_PENDETEN);
+       else {
+               DA9052_DEBUG("%s:", __FUNCTION__);
+               DA9052_DEBUG(" Invalid flag passed \n" );
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data);
+       if (ret < 0) {
+               DA9052_DEBUG("%s:", __FUNCTION__);
+               DA9052_DEBUG(" write_da9052_reg Failed\n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data;
+       return 0;
+}
+
+static ssize_t da9052_tsi_disable_irq(struct da9052_ts_priv *priv,
+                                       enum TSI_IRQ tsi_irq)
+{
+       u8 data = 0;
+       ssize_t ret =0;
+       struct da9052_tsi_info  *ts = get_tsi_drvdata();
+
+       da9052_lock(priv->da9052);
+       ret = read_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG);
+       if (ret < 0)    {
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_disable_irq:");
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       data = ret;
+       switch (tsi_irq) {
+       case TSI_PEN_DWN:
+               data = mask_pendwn_irq(data);
+       break;
+       case TSI_DATA_RDY:
+               data = mask_tsi_rdy_irq(data);
+       break;
+       default:
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_disable_irq:");
+               DA9052_DEBUG("Invalid IRQ passed \n" );
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+       ret = write_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_disable_irq:");
+               DA9052_DEBUG("write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+       switch (tsi_irq) {
+       case TSI_PEN_DWN:
+               ts->tsi_conf.tsi_pendown_irq_mask = SET;
+       break;
+       case TSI_DATA_RDY:
+               ts->tsi_conf.tsi_ready_irq_mask = SET;
+       break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0; 
+
+}
+
+static ssize_t da9052_tsi_enable_irq(struct da9052_ts_priv *priv,
+                                       enum TSI_IRQ tsi_irq)
+{
+       u8 data =0;
+       ssize_t ret =0;
+       struct da9052_tsi_info  *ts = get_tsi_drvdata();
+
+       da9052_lock(priv->da9052);
+       ret = read_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_enable_irq:");
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       data = ret;
+       switch (tsi_irq) {
+       case TSI_PEN_DWN:
+               data = unmask_pendwn_irq(data);
+       break;
+       case TSI_DATA_RDY:
+               data = unmask_tsi_rdy_irq(data);
+       break;
+       default:
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_enable_irq:");
+               DA9052_DEBUG("Invalid IRQ passed \n" );
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+       ret = write_da9052_reg(priv->da9052, DA9052_IRQMASKB_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI:da9052_tsi_enable_irq:");
+               DA9052_DEBUG("write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+       switch (tsi_irq) {
+       case TSI_PEN_DWN:
+               ts->tsi_conf.tsi_pendown_irq_mask = RESET;
+       break;
+       case TSI_DATA_RDY:
+               ts->tsi_conf.tsi_ready_irq_mask = RESET;
+       break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+ }
+
+static ssize_t da9052_tsi_config_gpio(struct da9052_ts_priv *priv)
+{
+       u8 idx = 0;
+       ssize_t ret = 0;
+       struct da9052_ssc_msg ssc_msg[priv->tsi_pdata->num_gpio_tsi_register];
+
+       ssc_msg[idx++].addr  = DA9052_GPIO0203_REG;
+       ssc_msg[idx++].addr  = DA9052_GPIO0405_REG;
+       ssc_msg[idx++].addr  = DA9052_GPIO0607_REG;
+
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read_many(priv->da9052, ssc_msg,idx);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("da9052_ssc_read_many Failed\n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       idx = 0;
+       ssc_msg[idx].data = clear_bits(ssc_msg[idx].data,
+                                               DA9052_GPIO0203_GPIO3PIN);
+       idx++;
+       ssc_msg[idx].data = clear_bits(ssc_msg[idx].data,
+               (DA9052_GPIO0405_GPIO4PIN | DA9052_GPIO0405_GPIO5PIN));
+       idx++;
+       ssc_msg[idx].data = clear_bits(ssc_msg[idx].data,
+               (DA9052_GPIO0607_GPIO6PIN | DA9052_GPIO0607_GPIO7PIN));
+       idx++;
+
+       ret = priv->da9052->write_many(priv->da9052, ssc_msg,idx);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("da9052_ssc_read_many Failed\n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+
+s32 da9052_pm_configure_ldo(struct da9052_ts_priv *priv,
+                               struct da9052_ldo_config ldo_config)
+{
+       struct da9052_ssc_msg msg;
+       u8 reg_num;
+       u8 ldo_volt;
+       u8 ldo_volt_bit = 0;
+       u8 ldo_conf_bit = 0;
+       u8 ldo_en_bit = 0;
+       s8 ldo_pd_bit = -1;
+       s32 ret = 0;
+
+       if (validate_ldo9_mV(ldo_config.ldo_volt))
+               return INVALID_LDO9_VOLT_VALUE;
+
+       ldo_volt = ldo9_mV_to_reg(ldo_config.ldo_volt);
+
+       reg_num = DA9052_LDO9_REG;
+       ldo_volt_bit = DA9052_LDO9_VLDO9;
+       ldo_conf_bit = DA9052_LDO9_LDO9CONF;
+       ldo_en_bit = DA9052_LDO9_LDO9EN;
+
+       da9052_lock(priv->da9052);
+
+       msg.addr = reg_num;
+
+       ret = priv->da9052->read(priv->da9052, &msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+       msg.data = ldo_volt |
+               (ldo_config.ldo_conf ? ldo_conf_bit : 0) |
+               (msg.data & ldo_en_bit);
+
+       ret = priv->da9052->write(priv->da9052, &msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       if (-1 != ldo_pd_bit) {
+               msg.addr = DA9052_PULLDOWN_REG;
+               ret = priv->da9052->read(priv->da9052, &msg);
+               if (ret) {
+                       da9052_unlock(priv->da9052);
+                       return -EINVAL;
+               }
+
+               msg.data = (ldo_config.ldo_pd ?
+                               set_bits(msg.data, ldo_pd_bit) :
+                               clear_bits(msg.data, ldo_pd_bit));
+
+               ret = priv->da9052->write(priv->da9052, &msg);
+               if (ret) {
+                       da9052_unlock(priv->da9052);
+                       return -EINVAL;
+               }
+
+       }
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+
+
+s32 da9052_pm_set_ldo(struct da9052_ts_priv *priv, u8 ldo_num, u8 flag)
+{
+       struct da9052_ssc_msg msg;
+       u8 reg_num = 0;
+       u8 value = 0;
+       s32 ret = 0;
+
+       DA9052_DEBUG("I am in function: %s\n", __FUNCTION__);
+
+       reg_num = DA9052_LDO9_REG;
+       value = DA9052_LDO9_LDO9EN;
+       da9052_lock(priv->da9052);
+
+       msg.addr = reg_num;
+
+       ret = priv->da9052->read(priv->da9052, &msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       msg.data = flag ?
+               set_bits(msg.data, value) :
+               clear_bits(msg.data, value);
+
+       ret = priv->da9052->write(priv->da9052, &msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+
+static ssize_t da9052_tsi_config_power_supply(struct da9052_ts_priv *priv,
+                                               u8 state)
+{
+       struct da9052_ldo_config ldo_config;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (state != ENABLE && state != DISABLE) {
+               DA9052_DEBUG("DA9052_TSI: %s: ", __FUNCTION__);
+               DA9052_DEBUG("Invalid state Passed\n" );
+               return -EINVAL;
+       }
+
+       ldo_config.ldo_volt = priv->tsi_pdata->tsi_supply_voltage;
+       ldo_config.ldo_num =  priv->tsi_pdata->tsi_ref_source;
+       ldo_config.ldo_conf = RESET;
+
+       if (da9052_pm_configure_ldo(priv, ldo_config))
+               return -EINVAL;
+
+       if (da9052_pm_set_ldo(priv, priv->tsi_pdata->tsi_ref_source, state))
+               return -EINVAL;
+
+       if (state == ENABLE)
+               ts->tsi_conf.ldo9_en = SET;
+       else
+               ts->tsi_conf.ldo9_en = RESET;
+
+       return 0;
+}
+
+static ssize_t da9052_tsi_config_auto_mode(struct da9052_ts_priv *priv,
+                                               u8 state)
+{
+       u8 data;
+       s32 ret = 0;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (state != ENABLE && state != DISABLE)
+               return -EINVAL;
+
+       da9052_lock(priv->da9052);
+
+       ret = read_da9052_reg(priv->da9052, DA9052_TSICONTA_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       data = (u8)ret;
+
+       if (state == ENABLE)
+               data = set_auto_tsi_en(data);
+       else if (state == DISABLE)
+               data = reset_auto_tsi_en(data);
+       else {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("Invalid Parameter Passed \n" );
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       ret = write_da9052_reg(priv->da9052, DA9052_TSICONTA_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" Failed to configure Auto TSI mode\n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+       ts->tsi_conf.auto_cont.da9052_tsi_cont_a = data;
+       return 0;
+}
+
+static ssize_t da9052_tsi_config_manual_mode(struct da9052_ts_priv *priv,
+                                               u8 state)
+{
+       u8 data = 0;
+       ssize_t ret=0;
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+
+       if (state != ENABLE && state != DISABLE) {
+               DA9052_DEBUG("DA9052_TSI: %s: ", __FUNCTION__);
+               DA9052_DEBUG("Invalid state Passed\n" );
+               return -EINVAL;
+       }
+
+       da9052_lock(priv->da9052);
+
+       ret = read_da9052_reg(priv->da9052, DA9052_TSICONTB_REG);
+       if (ret < 0) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("read_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       data = (u8)ret;
+       if (state == DISABLE)
+               data = disable_tsi_manual_mode(data);
+       else
+               data = enable_tsi_manual_mode(data);
+
+       ret = write_da9052_reg(priv->da9052, DA9052_TSICONTB_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("write_da9052_reg Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+
+       if (state == DISABLE)
+               ts->tsi_conf.man_cont.tsi_cont_b.tsi_man = RESET;
+       else
+               ts->tsi_conf.man_cont.tsi_cont_b.tsi_man = SET;
+
+       data = 0;
+       data = set_bits(data, DA9052_ADC_TSI);
+
+       ret = write_da9052_reg(priv->da9052, DA9052_ADCMAN_REG, data);
+       if (ret) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG("ADC write Failed \n" );
+               da9052_unlock(priv->da9052);
+               return ret;
+       }
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+
+static u32 da9052_tsi_get_reg_data(struct da9052_ts_priv *priv)
+{
+       u32 free_cnt, copy_cnt, cnt;
+
+       if (down_interruptible(&priv->tsi_reg_fifo.lock))
+               return 0;
+
+       copy_cnt = 0;
+
+       if ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail) > 1) {
+               free_cnt = get_reg_free_space_cnt(priv);
+               if (free_cnt > TSI_POLL_SAMPLE_CNT)
+                       free_cnt = TSI_POLL_SAMPLE_CNT;
+
+               cnt = da9052_tsi_get_rawdata(
+                       &priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.tail],
+                       free_cnt);
+
+               if (cnt > free_cnt) {
+                       DA9052_DEBUG("EH copied more data");
+                       return -EINVAL;
+               }
+
+               copy_cnt = cnt;
+
+               while (cnt--)
+                       incr_with_wrap_reg_fifo(priv->tsi_reg_fifo.tail);
+
+       } else if ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail) <= 0) {
+
+               free_cnt = (TSI_REG_DATA_BUF_SIZE - priv->tsi_reg_fifo.tail);
+               if (free_cnt > TSI_POLL_SAMPLE_CNT) {
+                       free_cnt = TSI_POLL_SAMPLE_CNT;
+
+                       cnt = da9052_tsi_get_rawdata(
+                       &priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.tail],
+                       free_cnt);
+                       if (cnt > free_cnt) {
+                               DA9052_DEBUG("EH copied more data");
+                               return -EINVAL;
+                       }
+                       copy_cnt = cnt;
+
+                       while (cnt--)
+                               incr_with_wrap_reg_fifo(
+                                               priv->tsi_reg_fifo.tail);
+               } else {
+                       if (free_cnt) {
+                               cnt = da9052_tsi_get_rawdata(
+                                       &priv->
+                                       tsi_reg_fifo.data[priv->
+                                       tsi_reg_fifo.tail],
+                                       free_cnt
+                                       );
+                               if (cnt > free_cnt) {
+                                       DA9052_DEBUG("EH copied more data");
+                                       return -EINVAL;
+                               }
+                               copy_cnt = cnt;
+                               while (cnt--)
+                                       incr_with_wrap_reg_fifo(
+                                               priv->tsi_reg_fifo.tail);
+                       }
+                       free_cnt = priv->tsi_reg_fifo.head;
+                       if (free_cnt > TSI_POLL_SAMPLE_CNT - copy_cnt)
+                               free_cnt = TSI_POLL_SAMPLE_CNT - copy_cnt;
+                       if (free_cnt) {
+                               cnt = da9052_tsi_get_rawdata(
+                                       &priv->tsi_reg_fifo.data[priv->
+                                       tsi_reg_fifo.tail], free_cnt
+                                       );
+                               if (cnt > free_cnt) {
+                                       DA9052_DEBUG("EH copied more data");
+                                       return -EINVAL;
+                               }
+
+                               copy_cnt += cnt;
+
+                               while (cnt--)
+                                       incr_with_wrap_reg_fifo(
+                                               priv->tsi_reg_fifo.tail);
+                       }
+               }
+       } else
+               copy_cnt = 0;
+
+       up(&priv->tsi_reg_fifo.lock);
+
+       return copy_cnt;
+}
+
+
+static ssize_t da9052_tsi_reg_proc_thread(void *ptr)
+{
+       u32 data_cnt;
+       ssize_t ret = 0;
+       struct da9052_tsi_info *ts;
+       struct da9052_ts_priv *priv = (struct da9052_ts_priv *)ptr;
+
+       set_freezable();
+
+       while (priv->tsi_reg_proc_thread.state == ACTIVE) {
+
+               try_to_freeze();
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(msecs_to_jiffies(priv->
+                                       tsi_reg_data_poll_interval));
+
+               ts = get_tsi_drvdata();
+
+               if (!ts->pen_dwn_event)
+                       continue;
+
+               data_cnt = da9052_tsi_get_reg_data(priv);
+
+               da9052_tsi_process_reg_data(priv);
+
+               if (data_cnt)
+                       ts->tsi_zero_data_cnt = 0;
+               else {
+                       if ((++(ts->tsi_zero_data_cnt)) >
+                                                    ts->tsi_penup_count) {
+                               ts->pen_dwn_event = RESET;
+                               da9052_tsi_penup_event(priv);
+                       }
+               }
+       }
+
+       complete_and_exit(&priv->tsi_reg_proc_thread.notifier, 0);
+       return 0;
+}
+
+
+static void da9052_tsi_penup_event(struct da9052_ts_priv *priv)
+{
+
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+       struct input_dev *ip_dev =
+               (struct input_dev *)da9052_tsi_get_input_dev(
+               (u8)TSI_INPUT_DEVICE_OFF);
+
+       if (da9052_tsi_config_auto_mode(priv, DISABLE))
+               goto exit;
+       ts->tsi_conf.auto_cont.tsi_cont_a.auto_tsi_en = RESET;
+
+       if (da9052_tsi_config_power_supply(priv, ENABLE))
+               goto exit;
+
+       ts->tsi_conf.ldo9_en = RESET;
+
+       if (da9052_tsi_enable_irq(priv, TSI_PEN_DWN))
+               goto exit;
+       ts->tsi_conf.tsi_pendown_irq_mask = RESET;
+       tsi_reg.tsi_state =  WAIT_FOR_PEN_DOWN;
+
+       if (da9052_tsi_disable_irq(priv, TSI_DATA_RDY))
+               goto exit;
+
+       ts->tsi_zero_data_cnt = 0;
+       priv->early_data_flag = TRUE;
+       priv->debounce_over = FALSE;
+       priv->win_reference_valid = FALSE;
+
+       printk(KERN_INFO "The raw data count is %d \n", priv->raw_data_cnt);
+       printk(KERN_INFO "The OS data count is %d \n", priv->os_data_cnt);
+       printk(KERN_INFO "PEN UP DECLARED \n");
+       input_report_abs(ip_dev, BTN_TOUCH, 0);
+       input_sync(ip_dev);
+       priv->os_data_cnt = 0;
+       priv->raw_data_cnt = 0;
+
+exit:
+       clean_tsi_fifos(priv);
+       return;
+}
+
+void da9052_tsi_pen_down_handler(struct da9052_eh_nb *eh_data, u32 event)
+{
+       ssize_t ret = 0;
+       struct da9052_ts_priv *priv =
+               container_of(eh_data, struct da9052_ts_priv, pd_nb);
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+       struct input_dev *ip_dev = 
+               (struct input_dev*)da9052_tsi_get_input_dev(
+               (u8)TSI_INPUT_DEVICE_OFF);
+
+       if (tsi_reg.tsi_state !=  WAIT_FOR_PEN_DOWN)
+               return;
+
+       tsi_reg.tsi_state = WAIT_FOR_SAMPLING;
+
+       if (ts->tsi_conf.state != TSI_AUTO_MODE) {
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" Configure TSI to auto mode.\n" );
+               DA9052_DEBUG("DA9052_TSI: %s:", __FUNCTION__);
+               DA9052_DEBUG(" Then call this API.\n" );
+               goto fail;
+       }
+
+       if (da9052_tsi_config_power_supply(priv, ENABLE))
+               goto fail;
+
+       if (da9052_tsi_disable_irq(priv, TSI_PEN_DWN))
+               goto fail;
+
+       if (da9052_tsi_config_auto_mode(priv, ENABLE))
+               goto fail;
+       ts->tsi_conf.auto_cont.tsi_cont_a.auto_tsi_en = SET;
+
+       if (da9052_tsi_enable_irq(priv, TSI_DATA_RDY))
+               goto fail;
+
+       input_sync(ip_dev);
+
+       ts->tsi_rdy_event = (DA9052_EVENTB_ETSIREADY & (event>>8));
+       ts->pen_dwn_event = (DA9052_EVENTB_EPENDOWN & (event>>8));
+
+       tsi_reg.tsi_state =  SAMPLING_ACTIVE;
+
+       goto success;
+
+fail:
+       if (ts->pd_reg_status) {
+               priv->da9052->unregister_event_notifier(priv->da9052,
+                                               &priv->pd_nb);
+               ts->pd_reg_status = RESET;
+
+               priv->da9052->register_event_notifier(priv->da9052,
+                                       &priv->datardy_nb);
+               da9052_tsi_reg_pendwn_event(priv);
+       }
+
+success:
+       ret = 0;
+       printk(KERN_INFO "Exiting PEN DOWN HANDLER \n");
+}
+
+void da9052_tsi_data_ready_handler(struct da9052_eh_nb *eh_data, u32 event)
+{
+       struct da9052_ssc_msg tsi_data[4];
+       s32 ret;
+       struct da9052_ts_priv *priv =
+               container_of(eh_data, struct da9052_ts_priv, datardy_nb);
+
+       if (tsi_reg.tsi_state !=  SAMPLING_ACTIVE)
+               return;
+
+       tsi_data[0].addr  = DA9052_TSIXMSB_REG;
+       tsi_data[1].addr  = DA9052_TSIYMSB_REG;
+       tsi_data[2].addr  = DA9052_TSILSB_REG;
+       tsi_data[3].addr  = DA9052_TSIZMSB_REG;
+
+       tsi_data[0].data  = 0;
+       tsi_data[1].data  = 0;
+       tsi_data[2].data  = 0;
+       tsi_data[3].data  = 0;
+
+       da9052_lock(priv->da9052);
+
+       ret = priv->da9052->read_many(priv->da9052, tsi_data, 4);
+       if (ret) {
+               DA9052_DEBUG("Error in reading TSI data \n" );
+               da9052_unlock(priv->da9052);
+               return;
+       }
+       da9052_unlock(priv->da9052);
+
+#if 1
+       mutex_lock(&tsi_reg.tsi_fifo_lock);
+
+       tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].x_msb = tsi_data[0].data;
+       tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].y_msb = tsi_data[1].data;
+       tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].lsb   = tsi_data[2].data;
+       tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_end].z_msb = tsi_data[3].data;
+       incr_with_wrap(tsi_reg.tsi_fifo_end);
+
+       if (tsi_reg.tsi_fifo_end == tsi_reg.tsi_fifo_start)
+               tsi_reg.tsi_fifo_start++;
+
+       mutex_unlock(&tsi_reg.tsi_fifo_lock);
+#endif
+//     printk(KERN_INFO "Exiting Data ready handler \n");
+}
+
+static s32 da9052_tsi_get_rawdata(struct da9052_tsi_reg *buf, u8 cnt) {
+       u32 data_cnt = 0;
+       u32 rem_data_cnt = 0;
+
+       mutex_lock(&tsi_reg.tsi_fifo_lock);
+
+       if (tsi_reg.tsi_fifo_start < tsi_reg.tsi_fifo_end) {
+               data_cnt = (tsi_reg.tsi_fifo_end - tsi_reg.tsi_fifo_start);
+
+               if (cnt < data_cnt)
+                       data_cnt = cnt;
+
+               memcpy(buf, &tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_start],
+                               sizeof(struct da9052_tsi_reg) * data_cnt);
+
+               tsi_reg.tsi_fifo_start += data_cnt;
+
+               if (tsi_reg.tsi_fifo_start == tsi_reg.tsi_fifo_end) {
+                       tsi_reg.tsi_fifo_start = 0;
+                       tsi_reg.tsi_fifo_end = 0;
+               }
+       } else if (tsi_reg.tsi_fifo_start > tsi_reg.tsi_fifo_end) {
+               data_cnt = ((TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start)
+               + tsi_reg.tsi_fifo_end);
+
+               if (cnt < data_cnt)
+                       data_cnt = cnt;
+
+               if (data_cnt <= (TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start)) {
+                       memcpy(buf, &tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_start],
+                               sizeof(struct da9052_tsi_reg) * data_cnt);
+
+                       tsi_reg.tsi_fifo_start += data_cnt;
+                       if (tsi_reg.tsi_fifo_start >= TSI_FIFO_SIZE)
+                               tsi_reg.tsi_fifo_start = 0;
+               } else {
+                       memcpy(buf, &tsi_reg.tsi_fifo[tsi_reg.tsi_fifo_start],
+                               sizeof(struct da9052_tsi_reg)
+                               * (TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start));
+
+                       rem_data_cnt = (data_cnt -
+                               (TSI_FIFO_SIZE - tsi_reg.tsi_fifo_start));
+
+                       memcpy(buf, &tsi_reg.tsi_fifo[0],
+                               sizeof(struct da9052_tsi_reg) * rem_data_cnt);
+
+                       tsi_reg.tsi_fifo_start = rem_data_cnt;
+               }
+
+               if (tsi_reg.tsi_fifo_start == tsi_reg.tsi_fifo_end) {
+                               tsi_reg.tsi_fifo_start = 0;
+                       tsi_reg.tsi_fifo_end = 0;
+               }
+       } else
+               data_cnt = 0;
+
+       mutex_unlock(&tsi_reg.tsi_fifo_lock);
+
+       return data_cnt;
+}
+
+static ssize_t da9052_tsi_suspend(struct platform_device *dev, 
+                                                       pm_message_t state)
+{
+       printk(KERN_INFO "%s: called\n", __FUNCTION__);
+       return 0;
+}
+
+static ssize_t da9052_tsi_resume(struct platform_device *dev)
+{
+       printk(KERN_INFO "%s: called\n", __FUNCTION__);
+       return 0;
+}
+
+static s32 __devinit da9052_tsi_probe(struct platform_device *pdev)
+{
+
+       struct da9052_ts_priv *priv;
+       struct da9052_tsi_platform_data *pdata = pdev->dev.platform_data;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       priv->da9052 = dev_get_drvdata(pdev->dev.parent);
+       platform_set_drvdata(pdev, priv);
+
+       priv->tsi_pdata = pdata;
+
+       if (da9052_tsi_init_drv(priv))
+                       return -EFAULT;
+
+       mutex_init(&tsi_reg.tsi_fifo_lock);
+       tsi_reg.tsi_state = WAIT_FOR_PEN_DOWN;
+
+       printk(KERN_INFO "TSI Drv Successfully Inserted %s\n",
+                                       DA9052_TSI_DEVICE_NAME);
+       return 0;
+}
+
+static int __devexit da9052_tsi_remove(struct platform_device *pdev)
+{
+       struct da9052_ts_priv *priv = platform_get_drvdata(pdev);
+       struct da9052_tsi_info *ts = get_tsi_drvdata();
+       s32 ret = 0, i = 0;
+
+       ret = da9052_tsi_config_state(priv, TSI_IDLE);
+       if (!ret)
+               return -EINVAL;
+
+       if (ts->pd_reg_status) {
+               priv->da9052->unregister_event_notifier(priv->da9052,
+                                                       &priv->pd_nb);
+               ts->pd_reg_status = RESET;
+       }
+
+       if (ts->datardy_reg_status) {
+               priv->da9052->unregister_event_notifier(priv->da9052,
+                                                       &priv->datardy_nb);
+               ts->datardy_reg_status = RESET;
+       }
+
+       mutex_destroy(&tsi_reg.tsi_fifo_lock);
+
+       priv->tsi_reg_proc_thread.state = INACTIVE;
+       wait_for_completion(&priv->tsi_reg_proc_thread.notifier);
+
+       priv->tsi_raw_proc_thread.state = INACTIVE;
+       wait_for_completion(&priv->tsi_raw_proc_thread.notifier);
+
+       for (i = 0; i < NUM_INPUT_DEVS; i++) {
+               input_unregister_device(ts->input_devs[i]);
+       }
+
+       platform_set_drvdata(pdev, NULL);
+       DA9052_DEBUG(KERN_DEBUG "Removing %s \n", DA9052_TSI_DEVICE_NAME);
+
+       return 0;
+}
+
+static struct platform_driver da9052_tsi_driver = {
+       .probe          = da9052_tsi_probe,
+       .remove         = __devexit_p(da9052_tsi_remove),
+       .suspend        = da9052_tsi_suspend,
+       .resume         = da9052_tsi_resume,
+       .driver         = {
+                               .name   = DA9052_TSI_DEVICE_NAME,
+                               .owner  = THIS_MODULE,
+                       },
+};
+
+static int __init da9052_tsi_init(void)
+{
+       printk("DA9052 TSI Device Driver, v1.0\n");
+       return platform_driver_register(&da9052_tsi_driver);
+}
+module_init(da9052_tsi_init);
+
+static void __exit da9052_tsi_exit(void)
+{
+       printk(KERN_ERR "TSI Driver %s Successfully Removed \n",
+                                       DA9052_TSI_DEVICE_NAME);
+       return;
+
+}
+module_exit(da9052_tsi_exit);
+
+MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/input/touchscreen/da9052_tsi_calibrate.c b/drivers/input/touchscreen/da9052_tsi_calibrate.c
new file mode 100644 (file)
index 0000000..4ffd0bb
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * da9052_tsi_calibrate.c  --  TSI Calibration driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+
+#include <linux/mfd/da9052/tsi.h>
+
+static struct Calib_xform_matrix_t xform = {
+               .An = DA9052_TSI_CALIB_AN,
+               .Bn = DA9052_TSI_CALIB_BN,
+               .Cn = DA9052_TSI_CALIB_CN,
+               .Dn = DA9052_TSI_CALIB_DN,
+               .En = DA9052_TSI_CALIB_EN,
+               .Fn = DA9052_TSI_CALIB_FN,
+               .Divider = DA9052_TSI_CALIB_DIVIDER
+};
+
+static struct calib_cfg_t calib = {
+       .calibrate_flag = TSI_USE_CALIBRATION,
+};
+
+struct calib_cfg_t *get_calib_config(void)
+{
+       return &calib;
+}
+
+ssize_t da9052_tsi_set_calib_matrix(struct da9052_tsi_data *displayPtr,
+                               struct da9052_tsi_data *screenPtr)
+{
+
+       int  retValue = SUCCESS ;
+
+       xform.Divider = ((screenPtr[0].x - screenPtr[1].x)
+                       * (screenPtr[1].y - screenPtr[2].y))
+                       - ((screenPtr[1].x - screenPtr[2].x)
+                       * (screenPtr[0].y - screenPtr[1].y));
+
+       if (xform.Divider == 0)
+               retValue = -FAILURE;
+       else    {
+               xform.An = ((displayPtr[0].x - displayPtr[1].x)
+                       * (screenPtr[1].y - screenPtr[2].y))
+                       - ((displayPtr[1].x - displayPtr[2].x)
+                       * (screenPtr[0].y - screenPtr[1].y));
+
+               xform.Bn = ((displayPtr[1].x - displayPtr[2].x)
+                       * (screenPtr[0].x - screenPtr[1].x))
+                       - ((screenPtr[1].x - screenPtr[2].x)
+                       * (displayPtr[0].x - displayPtr[1].x));
+
+                xform.Cn = (displayPtr[0].x * xform.Divider)
+                       - (screenPtr[0].x * xform.An)
+                       - (screenPtr[0].y * xform.Bn);
+
+               xform.Dn = ((displayPtr[0].y - displayPtr[1].y)
+                       * (screenPtr[1].y - screenPtr[2].y))
+                       - ((displayPtr[1].y - displayPtr[2].y)
+                       * (screenPtr[0].y - screenPtr[1].y));
+
+               xform.En = ((displayPtr[1].y - displayPtr[2].y)
+                       * (screenPtr[0].x - screenPtr[1].x))
+                       - ((screenPtr[1].x - screenPtr[2].x)
+                       * (displayPtr[0].y - displayPtr[1].y));
+
+               xform.Fn = (displayPtr[0].y * xform.Divider)
+                       - (screenPtr[0].x * xform.Dn)
+                       - (screenPtr[0].y * xform.En);
+       }
+
+       return retValue;
+}
+
+ssize_t da9052_tsi_get_calib_display_point(struct da9052_tsi_data *displayPtr)
+{
+       int  retValue = TRUE;
+       struct da9052_tsi_data screen_coord;
+
+       screen_coord = *displayPtr;
+       if (xform.Divider != 0) {
+               displayPtr->x = ((xform.An * screen_coord.x) +
+                       (xform.Bn * screen_coord.y) +
+                               xform.Cn
+                       ) / xform.Divider;
+
+       displayPtr->y = ((xform.Dn * screen_coord.x) +
+                       (xform.En * screen_coord.y) +
+                               xform.Fn
+                       ) / xform.Divider;
+       } else
+               retValue = FALSE;
+
+#if DA9052_TSI_CALIB_DATA_PROFILING
+       printk("C\tX\t%4d\tY\t%4d\n",
+                                       displayPtr->x,
+                                       displayPtr->y);
+#endif
+       return retValue;
+}
diff --git a/drivers/input/touchscreen/da9052_tsi_filter.c b/drivers/input/touchscreen/da9052_tsi_filter.c
new file mode 100644 (file)
index 0000000..16467ed
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * da9052_tsi_filter.c  --  TSI filter driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/freezer.h>
+#include <linux/mfd/da9052/tsi.h>
+
+#define get_abs(x)     (x < 0 ? ((-1) * x) : (x))
+
+#define WITHIN_WINDOW(x, y)    ((get_abs(x) <= TSI_X_WINDOW_SIZE) && \
+                               (get_abs(y) <= TSI_Y_WINDOW_SIZE))
+
+#define FIRST_SAMPLE                                   0
+
+#define incr_with_wrap_raw_fifo(x)                     \
+               if (++x >= TSI_RAW_DATA_BUF_SIZE)       \
+                       x = 0
+
+#define decr_with_wrap_raw_fifo(x)                     \
+               if (--x < 0)                            \
+                       x = (TSI_RAW_DATA_BUF_SIZE-1)
+
+static u32 get_raw_data_cnt(struct da9052_ts_priv *priv);
+static void da9052_tsi_convert_reg_to_coord(struct da9052_ts_priv *priv,
+                                       struct da9052_tsi_data *raw_data);
+static inline void clean_tsi_reg_fifo(struct da9052_ts_priv *priv);
+static inline void clean_tsi_raw_fifo(struct da9052_ts_priv *priv);
+
+#if (ENABLE_AVERAGE_FILTER)
+static void da9052_tsi_avrg_filter(struct da9052_ts_priv *priv,
+                                       struct da9052_tsi_data *tsi_avg_data);
+
+#endif
+#if (ENABLE_TSI_DEBOUNCE)
+static s32 da9052_tsi_calc_debounce_data(struct da9052_ts_priv *priv,
+                                       struct da9052_tsi_data *raw_data);
+
+#endif
+# if (ENABLE_WINDOW_FILTER)
+static s32 diff_within_window(struct da9052_tsi_data *prev_raw_data,
+                             struct da9052_tsi_data *cur_raw_data);
+#endif
+static s32 da9052_tsi_window_filter(struct da9052_ts_priv *ts,
+                                       struct da9052_tsi_data *raw_data);
+
+void clean_tsi_fifos(struct da9052_ts_priv *priv)
+{
+       clean_tsi_raw_fifo(priv);
+       clean_tsi_reg_fifo(priv);
+}
+
+void __init da9052_init_tsi_fifos(struct da9052_ts_priv *priv)
+{
+       init_MUTEX(&priv->tsi_raw_fifo.lock);
+       init_MUTEX(&priv->tsi_reg_fifo.lock);
+
+       clean_tsi_raw_fifo(priv);
+       clean_tsi_reg_fifo(priv);
+}
+
+u32 get_reg_data_cnt(struct da9052_ts_priv *priv)
+{
+       u8 reg_data_cnt;
+
+       if (priv->tsi_reg_fifo.head <= priv->tsi_reg_fifo.tail) {
+               reg_data_cnt = (priv->tsi_reg_fifo.tail -
+                               priv->tsi_reg_fifo.head);
+       } else {
+               reg_data_cnt = (priv->tsi_reg_fifo.tail +
+                               (TSI_REG_DATA_BUF_SIZE -
+                               priv->tsi_reg_fifo.head));
+       }
+
+       return reg_data_cnt;
+}
+
+u32 get_reg_free_space_cnt(struct da9052_ts_priv *priv)
+{
+       u32 free_cnt;
+
+       if (priv->tsi_reg_fifo.head <= priv->tsi_reg_fifo.tail) {
+               free_cnt = ((TSI_REG_DATA_BUF_SIZE - 1) -
+                       (priv->tsi_reg_fifo.tail - priv->tsi_reg_fifo.head));
+       } else
+               free_cnt = ((priv->tsi_reg_fifo.head - priv->tsi_reg_fifo.tail)
+                               - 1);
+
+       return free_cnt;
+}
+
+void da9052_tsi_process_reg_data(struct da9052_ts_priv *priv)
+{
+       s32 ret;
+       struct da9052_tsi_data tmp_raw_data;
+       u32 reg_data_cnt;
+
+       if (down_interruptible(&priv->tsi_reg_fifo.lock))
+               return;
+
+       reg_data_cnt = get_reg_data_cnt(priv);
+
+       while (reg_data_cnt-- > 0) {
+
+               ret = 0;
+
+               if (get_raw_data_cnt(priv) >= (TSI_RAW_DATA_BUF_SIZE - 1)) {
+                       DA9052_DEBUG("%s: RAW data FIFO is full\n",
+                                                       __FUNCTION__);
+                       break;
+               }
+
+               da9052_tsi_convert_reg_to_coord(priv, &tmp_raw_data);
+
+               if ((tmp_raw_data.x < TS_X_MIN) ||
+                       (tmp_raw_data.x > TS_X_MAX) ||
+                       (tmp_raw_data.y < TS_Y_MIN) ||
+                       (tmp_raw_data.y > TS_Y_MAX)) {
+                       DA9052_DEBUG("%s: ", __FUNCTION__);
+                       DA9052_DEBUG("sample beyond touchscreen panel ");
+                       DA9052_DEBUG("dimensions\n");
+                       continue;
+               }
+
+#if (ENABLE_TSI_DEBOUNCE)
+               if (debounce_over == FALSE) {
+                       ret =
+                       da9052_tsi_calc_debounce_data(priv, &tmp_raw_data);
+                       if (ret != SUCCESS)
+                               continue;
+               }
+#endif
+
+# if (ENABLE_WINDOW_FILTER)
+               ret = da9052_tsi_window_filter(priv, &tmp_raw_data);
+               if (ret != SUCCESS)
+                       continue;
+#endif
+               priv->early_data_flag = FALSE;
+
+               if (down_interruptible(&priv->tsi_raw_fifo.lock)) {
+                       DA9052_DEBUG("%s: Failed to ", __FUNCTION__);
+                       DA9052_DEBUG("acquire RAW FIFO Lock!\n");
+
+                       up(&priv->tsi_reg_fifo.lock);
+                       return;
+               }
+
+               priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = tmp_raw_data;
+               incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail);
+
+               up(&priv->tsi_raw_fifo.lock);
+       }
+
+
+       up(&priv->tsi_reg_fifo.lock);
+
+       return;
+}
+
+static u32 get_raw_data_cnt(struct da9052_ts_priv *priv)
+{
+       u32 raw_data_cnt;
+
+       if (priv->tsi_raw_fifo.head <= priv->tsi_raw_fifo.tail)
+               raw_data_cnt =
+                       (priv->tsi_raw_fifo.tail - priv->tsi_raw_fifo.head);
+       else
+               raw_data_cnt =
+                       (priv->tsi_raw_fifo.tail + (TSI_RAW_DATA_BUF_SIZE -
+                       priv->tsi_raw_fifo.head));
+
+       return raw_data_cnt;
+}
+
+static void da9052_tsi_convert_reg_to_coord(struct da9052_ts_priv *priv,
+                                       struct da9052_tsi_data *raw_data)
+{
+
+       struct da9052_tsi_reg *src;
+       struct da9052_tsi_data *dst = raw_data;
+
+       src = &priv->tsi_reg_fifo.data[priv->tsi_reg_fifo.head];
+
+       dst->x = (src->x_msb << X_MSB_SHIFT);
+       dst->x |= (src->lsb & X_LSB_MASK) >> X_LSB_SHIFT;
+
+       dst->y = (src->y_msb << Y_MSB_SHIFT);
+       dst->y |= (src->lsb & Y_LSB_MASK) >> Y_LSB_SHIFT;
+
+       dst->z = (src->z_msb << Z_MSB_SHIFT);
+       dst->z |= (src->lsb & Z_LSB_MASK) >> Z_LSB_SHIFT;
+
+#if DA9052_TSI_RAW_DATA_PROFILING
+       printk("R\tX\t%4d\tY\t%4d\tZ\t%4d\n",
+                                       (u16)dst->x,
+                                       (u16)dst->y,
+                                       (u16)dst->z);
+#endif
+       priv->raw_data_cnt++;
+       incr_with_wrap_reg_fifo(priv->tsi_reg_fifo.head);
+}
+
+#if (ENABLE_AVERAGE_FILTER)
+static void da9052_tsi_avrg_filter(struct da9052_ts_priv *priv,
+                                       struct da9052_tsi_data *tsi_avg_data)
+{
+       u8 cnt;
+
+       if (down_interruptible(&priv->tsi_raw_fifo.lock)) {
+               printk("%s: No RAW Lock !\n", __FUNCTION__);
+               return;
+       }
+
+       (*tsi_avg_data) = priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head];
+       incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head);
+
+       for (cnt = 2; cnt <= TSI_AVERAGE_FILTER_SIZE; cnt++) {
+
+               tsi_avg_data->x +=
+                       priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].x;
+               tsi_avg_data->y +=
+                       priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].y;
+               tsi_avg_data->z +=
+                       priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].z;
+
+               incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head);
+       }
+
+       up(&priv->tsi_raw_fifo.lock);
+
+       tsi_avg_data->x /= TSI_AVERAGE_FILTER_SIZE;
+       tsi_avg_data->y /= TSI_AVERAGE_FILTER_SIZE;
+       tsi_avg_data->z /= TSI_AVERAGE_FILTER_SIZE;
+
+#if DA9052_TSI_AVG_FLT_DATA_PROFILING
+       printk("A\tX\t%4d\tY\t%4d\tZ\t%4d\n",
+                       (u16)tsi_avg_data->x,
+                       (u16)tsi_avg_data->y,
+                       (u16)tsi_avg_data->z);
+#endif
+
+       return;
+}
+#endif
+
+s32 da9052_tsi_raw_proc_thread(void *ptr)
+{
+       struct da9052_tsi_data coord;
+       u8 calib_ok, range_ok;
+       struct calib_cfg_t *tsi_calib = get_calib_config();
+       struct input_dev *ip_dev = (struct input_dev *)
+                               da9052_tsi_get_input_dev(
+                                               (u8)TSI_INPUT_DEVICE_OFF);
+       struct da9052_ts_priv *priv = (struct da9052_ts_priv *)ptr;
+
+       set_freezable();
+
+       while (priv->tsi_raw_proc_thread.state == ACTIVE) {
+
+               try_to_freeze();
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(
+                       msecs_to_jiffies(priv->tsi_raw_data_poll_interval));
+
+               if (priv->early_data_flag || (get_raw_data_cnt(priv) == 0))
+                       continue;
+
+               calib_ok = TRUE;
+               range_ok = TRUE;
+
+#if (ENABLE_AVERAGE_FILTER)
+
+               if (get_raw_data_cnt(priv) < TSI_AVERAGE_FILTER_SIZE)
+                       continue;
+
+               da9052_tsi_avrg_filter(priv, &coord);
+
+#else
+
+               if (down_interruptible(&priv->tsi_raw_fifo.lock))
+                       continue;
+
+               coord = priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head];
+               incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head);
+
+               up(&priv->tsi_raw_fifo.lock);
+
+#endif
+
+               if (tsi_calib->calibrate_flag) {
+                       calib_ok = da9052_tsi_get_calib_display_point(&coord);
+
+                       if ((coord.x < DISPLAY_X_MIN) ||
+                               (coord.x > DISPLAY_X_MAX) ||
+                               (coord.y < DISPLAY_Y_MIN) ||
+                                               (coord.y > DISPLAY_Y_MAX))
+                               range_ok = FALSE;
+               }
+
+               if (calib_ok && range_ok) {
+                       input_report_abs(ip_dev, BTN_TOUCH, 1);
+                       input_report_abs(ip_dev, ABS_X, coord.x);
+                       input_report_abs(ip_dev, ABS_Y, coord.y);
+                       input_sync(ip_dev);
+
+                       priv->os_data_cnt++;
+
+#if DA9052_TSI_OS_DATA_PROFILING
+                       printk("O\tX\t%4d\tY\t%4d\tZ\t%4d\n",  (u16)coord.x,
+                                               (u16)coord.y, (u16)coord.z);
+#endif
+               } else {
+                       if (!calib_ok) {
+                               DA9052_DEBUG("%s: ", __FUNCTION__);
+                               DA9052_DEBUG("calibration Failed\n");
+                       }
+                       if (!range_ok) {
+                               DA9052_DEBUG("%s: ", __FUNCTION__);
+                               DA9052_DEBUG("sample beyond display ");
+                               DA9052_DEBUG("panel dimension\n");
+                       }
+               }
+       }
+       priv->tsi_raw_proc_thread.thread_task = NULL;
+       complete_and_exit(&priv->tsi_raw_proc_thread.notifier, 0);
+       return 0;
+
+}
+
+#if (ENABLE_TSI_DEBOUNCE)
+static s32 da9052_tsi_calc_debounce_data(struct da9052_tsi_data *raw_data)
+{
+#if (TSI_DEBOUNCE_DATA_CNT)
+       u8 cnt;
+       struct da9052_tsi_data  temp = {.x = 0, .y = 0, .z = 0};
+
+       priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = (*raw_data);
+       incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail);
+
+       if (get_raw_data_cnt(priv) <= TSI_DEBOUNCE_DATA_CNT)
+               return -FAILURE;
+
+       for (cnt = 1; cnt <= TSI_DEBOUNCE_DATA_CNT; cnt++) {
+               temp.x += priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].x;
+               temp.y += priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].y;
+               temp.z += priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.head].z;
+
+               incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.head);
+       }
+
+       temp.x /= TSI_DEBOUNCE_DATA_CNT;
+       temp.y /= TSI_DEBOUNCE_DATA_CNT;
+       temp.z /= TSI_DEBOUNCE_DATA_CNT;
+
+       priv->tsi_raw_fifo.tail = priv->tsi_raw_fifo.head;
+       priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = temp;
+       incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail);
+
+#if DA9052_TSI_PRINT_DEBOUNCED_DATA
+       printk("D: X: %d Y: %d Z: %d\n",
+              (u16)temp.x, (u16)temp.y, (u16)temp.z);
+#endif
+
+#endif
+       priv->debounce_over = TRUE;
+
+       return 0;
+}
+#endif
+
+# if (ENABLE_WINDOW_FILTER)
+static s32 diff_within_window(struct da9052_tsi_data *prev_raw_data,
+                               struct da9052_tsi_data *cur_raw_data)
+{
+       s32 ret = -EINVAL;
+       s32 x, y;
+       x = ((cur_raw_data->x) - (prev_raw_data->x));
+       y = ((cur_raw_data->y) - (prev_raw_data->y));
+
+       if (WITHIN_WINDOW(x, y)) {
+
+#if DA9052_TSI_WIN_FLT_DATA_PROFILING
+               printk("W\tX\t%4d\tY\t%4d\tZ\t%4d\n",
+                                       (u16)cur_raw_data->x,
+                                       (u16)cur_raw_data->y,
+                                       (u16)cur_raw_data->z);
+#endif
+               ret = 0;
+       }
+       return ret;
+}
+
+static s32 da9052_tsi_window_filter(struct da9052_ts_priv *priv,
+                                       struct da9052_tsi_data *raw_data)
+{
+       u8 ref_found;
+       u32 cur, next;
+       s32 ret = -EINVAL;
+       static struct da9052_tsi_data prev_raw_data;
+
+       if (priv->win_reference_valid == TRUE) {
+
+#if DA9052_TSI_PRINT_PREVIOUS_DATA
+               printk("P: X: %d Y: %d Z: %d\n",
+               (u16)prev_raw_data.x, (u16)prev_raw_data.y,
+               (u16)prev_raw_data.z);
+#endif
+               ret = diff_within_window(&prev_raw_data, raw_data);
+               if (!ret)
+                       prev_raw_data = (*raw_data);
+       } else {
+               priv->tsi_raw_fifo.data[priv->tsi_raw_fifo.tail] = (*raw_data);
+               incr_with_wrap_raw_fifo(priv->tsi_raw_fifo.tail);
+
+               if (get_raw_data_cnt(priv) == SAMPLE_CNT_FOR_WIN_REF) {
+
+                       ref_found = FALSE;
+
+                       next = cur = priv->tsi_raw_fifo.head;
+                       incr_with_wrap_raw_fifo(next);
+
+                       while (next <= priv->tsi_raw_fifo.tail) {
+                               ret = diff_within_window(
+                                               &priv->tsi_raw_fifo.data[cur],
+                                               &priv->tsi_raw_fifo.data[next]
+                                               );
+                               if (ret == SUCCESS) {
+                                       ref_found = TRUE;
+                                       break;
+                               }
+                               incr_with_wrap_raw_fifo(cur);
+                               incr_with_wrap_raw_fifo(next);
+
+                       }
+
+                       if (ref_found == FALSE)
+                               priv->tsi_raw_fifo.tail =
+                                       priv->tsi_raw_fifo.head;
+                       else {
+                               prev_raw_data = priv->tsi_raw_fifo.data[cur];
+
+                               prev_raw_data.x +=
+                                       priv->tsi_raw_fifo.data[next].x;
+                               prev_raw_data.y +=
+                                       priv->tsi_raw_fifo.data[next].y;
+                               prev_raw_data.z +=
+                                       priv->tsi_raw_fifo.data[next].z;
+
+                               prev_raw_data.x = prev_raw_data.x / 2;
+                               prev_raw_data.y = prev_raw_data.y / 2;
+                               prev_raw_data.z = prev_raw_data.z / 2;
+
+                               (*raw_data) = prev_raw_data;
+
+                               priv->tsi_raw_fifo.tail =
+                                               priv->tsi_raw_fifo.head;
+
+                               priv->win_reference_valid = TRUE;
+                               ret = SUCCESS;
+                       }
+               }
+       }
+       return ret;
+}
+#endif
+static inline void clean_tsi_reg_fifo(struct da9052_ts_priv *priv)
+{
+       priv->tsi_reg_fifo.head = FIRST_SAMPLE;
+       priv->tsi_reg_fifo.tail = FIRST_SAMPLE;
+}
+
+static inline void clean_tsi_raw_fifo(struct da9052_ts_priv *priv)
+{
+       priv->tsi_raw_fifo.head = FIRST_SAMPLE;
+       priv->tsi_raw_fifo.tail = FIRST_SAMPLE;
+}
+
diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c
new file mode 100644 (file)
index 0000000..187d4d2
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * leds-da9052.c  --  LED Driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/led.h>
+
+#define DRIVER_NAME            "da9052-leds"
+
+#define DA9052_LED4_PRESENT    1
+#define DA9052_LED5_PRESENT    1
+
+
+struct da9052_led_data {
+       struct led_classdev cdev;
+       struct work_struct work;
+       struct da9052 *da9052;
+       int id;
+       int new_brightness;
+       int is_led4_present;
+       int is_led5_present;
+};
+
+#define GPIO14_PIN             2 /* GPO Open Drain */
+#define GPIO14_TYPE            0 /* VDD_IO1 */
+#define GPIO14_MODE            1 /* Output High */
+
+#define GPIO15_PIN             2 /* GPO Open Drain */
+#define GPIO15_TYPE            0 /* VDD_IO1 */
+#define GPIO15_MODE            1 /* Output High */
+
+#define MAXIMUM_PWM            95
+#define MASK_GPIO14            0x0F
+#define MASK_GPIO15            0xF0
+#define GPIO15_PIN_BIT_POSITION        4
+
+static void da9052_led_work(struct work_struct *work)
+{
+       struct da9052_led_data *led = container_of(work,
+                                struct da9052_led_data, work);
+       int reg = 0;
+       int led_dim_bit = 0;
+       struct da9052_ssc_msg msg;
+       int ret = 0;
+
+       switch (led->id) {
+       case DA9052_LED_4:
+               reg = DA9052_LED4CONT_REG;
+               led_dim_bit = DA9052_LED4CONT_LED4DIM;
+       break;
+       case DA9052_LED_5:
+               reg = DA9052_LED5CONT_REG;
+               led_dim_bit = DA9052_LED5CONT_LED5DIM;
+       break;
+       }
+
+       if (led->new_brightness > MAXIMUM_PWM)
+               led->new_brightness = MAXIMUM_PWM;
+
+       /* Always enable DIM feature
+        * This feature can be disabled if required
+        */
+       msg.addr = reg;
+       msg.data = led->new_brightness | led_dim_bit;
+       da9052_lock(led->da9052);
+       ret = led->da9052->write(led->da9052, &msg);
+       if (ret) {
+               da9052_unlock(led->da9052);
+               return;
+       }
+       da9052_unlock(led->da9052);
+}
+
+static void da9052_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness value)
+{
+       struct da9052_led_data *led;
+
+       led = container_of(led_cdev, struct da9052_led_data, cdev);
+       led->new_brightness = value;
+       schedule_work(&led->work);
+}
+
+static int __devinit da9052_led_setup(struct da9052_led_data *led)
+{
+       int reg = 0;
+       int ret = 0;
+
+       struct da9052_ssc_msg msg;
+
+       switch (led->id) {
+       case DA9052_LED_4:
+               reg = DA9052_LED4CONT_REG;
+       break;
+       case DA9052_LED_5:
+               reg = DA9052_LED5CONT_REG;
+       break;
+       }
+
+       msg.addr = reg;
+       msg.data = 0;
+
+       da9052_lock(led->da9052);
+       ret = led->da9052->write(led->da9052, &msg);
+       if (ret) {
+               da9052_unlock(led->da9052);
+               return ret;
+       }
+       da9052_unlock(led->da9052);
+       return ret;
+}
+
+static int da9052_leds_prepare(struct da9052_led_data *led)
+{
+       int ret = 0;
+       struct da9052_ssc_msg msg;
+
+       da9052_lock(led->da9052);
+
+       if (1 == led->is_led4_present) {
+               msg.addr = DA9052_GPIO1415_REG;
+               msg.data = 0;
+
+               ret = led->da9052->read(led->da9052, &msg);
+               if (ret)
+                       goto out;
+               msg.data = msg.data & ~(MASK_GPIO14);
+               msg.data = msg.data | (
+                               GPIO14_PIN |
+                               (GPIO14_TYPE ? DA9052_GPIO1415_GPIO14TYPE : 0) |
+                               (GPIO14_MODE ? DA9052_GPIO1415_GPIO14MODE : 0));
+
+               ret = led->da9052->write(led->da9052, &msg);
+               if (ret)
+                       goto out;
+       }
+
+       if (1 == led->is_led5_present) {
+               msg.addr = DA9052_GPIO1415_REG;
+               msg.data = 0;
+
+               ret = led->da9052->read(led->da9052, &msg);
+               if (ret)
+                       goto out;
+               msg.data = msg.data & ~(MASK_GPIO15);
+               msg.data = msg.data |
+                       (((GPIO15_PIN << GPIO15_PIN_BIT_POSITION) |
+                               (GPIO15_TYPE ? DA9052_GPIO1415_GPIO15TYPE : 0) |
+                               (GPIO15_MODE ? DA9052_GPIO1415_GPIO15MODE : 0))
+                               );
+               ret = led->da9052->write(led->da9052, &msg);
+               if (ret)
+                       goto out;
+       }
+
+       da9052_unlock(led->da9052);
+       return ret;
+out:
+       da9052_unlock(led->da9052);
+       return ret;
+}
+
+static int __devinit da9052_led_probe(struct platform_device *pdev)
+{
+       struct da9052_leds_platform_data *pdata = (pdev->dev.platform_data);
+       struct da9052_led_platform_data *led_cur;
+       struct da9052_led_data *led, *led_dat;
+       int ret, i;
+       int init_led = 0;
+
+       if (pdata->num_leds < 1 || pdata->num_leds > DA9052_LED_MAX) {
+               dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds);
+               return -EINVAL;
+       }
+
+       led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&pdev->dev, "failed to alloc memory\n");
+               return -ENOMEM;
+       }
+
+       led->is_led4_present = DA9052_LED4_PRESENT;
+       led->is_led5_present = DA9052_LED5_PRESENT;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               led_dat = &led[i];
+               led_cur = &pdata->led[i];
+               if (led_cur->id < 0) {
+                       dev_err(&pdev->dev, "invalid id %d\n", led_cur->id);
+                       ret = -EINVAL;
+                       goto err_register;
+               }
+
+               if (init_led & (1 << led_cur->id)) {
+                       dev_err(&pdev->dev, "led %d already initialized\n",
+                                       led_cur->id);
+                       ret = -EINVAL;
+                       goto err_register;
+               }
+
+               init_led |= 1 << led_cur->id;
+               
+               led_dat->cdev.name = led_cur->name;
+               // led_dat->cdev.default_trigger = led_cur[i]->default_trigger;
+               led_dat->cdev.brightness_set = da9052_led_set;
+               led_dat->cdev.brightness = LED_OFF;
+               led_dat->id = led_cur->id;
+               led_dat->da9052 = dev_get_drvdata(pdev->dev.parent);
+
+               INIT_WORK(&led_dat->work, da9052_led_work);
+
+               ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register led %d\n",
+                                       led_dat->id);
+                       goto err_register;
+
+               }
+               ret = da9052_led_setup(led_dat);
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to init led %d\n",
+                                       led_dat->id);
+                       i++;
+                       goto err_register;
+               }
+       }
+       ret = da9052_leds_prepare(led);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to init led driver\n");
+               goto err_free;
+       }
+
+       platform_set_drvdata(pdev, led);
+       return 0;
+
+err_register:
+       for (i = i - 1; i >= 0; i--) {
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+err_free:
+       kfree(led);
+       return ret;
+}
+
+static int __devexit da9052_led_remove(struct platform_device *pdev)
+{
+       struct da9052_leds_platform_data *pdata =
+               (struct da9052_leds_platform_data *)pdev->dev.platform_data;
+       struct da9052_led_data *led = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               da9052_led_setup(&led[i]);
+               led_classdev_unregister(&led[i].cdev);
+               cancel_work_sync(&led[i].work);
+       }
+
+       kfree(led);
+       return 0;
+}
+
+static struct platform_driver da9052_led_driver = {
+       .driver = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_led_probe,
+       .remove         = __devexit_p(da9052_led_remove),
+};
+
+static int __init da9052_led_init(void)
+{
+       return platform_driver_register(&da9052_led_driver);
+}
+module_init(da9052_led_init);
+
+static void __exit da9052_led_exit(void)
+{
+       platform_driver_unregister(&da9052_led_driver);
+}
+module_exit(da9052_led_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>    ");
+MODULE_DESCRIPTION("LED driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
new file mode 100644 (file)
index 0000000..b19eeaf
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * da9052-core.c  --  Device access for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/mfd/core.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/adc.h>
+
+#define SUCCESS                0
+#define FAILURE                1
+
+struct da9052_eh_nb eve_nb_array[EVE_CNT];
+static struct da9052_ssc_ops ssc_ops;
+struct mutex manconv_lock;
+static struct semaphore eve_nb_array_lock;
+
+void da9052_lock(struct da9052 *da9052)
+{
+       mutex_lock(&da9052->ssc_lock);
+}
+EXPORT_SYMBOL(da9052_lock);
+
+void da9052_unlock(struct da9052 *da9052)
+{
+       mutex_unlock(&da9052->ssc_lock);
+}
+EXPORT_SYMBOL(da9052_unlock);
+
+int da9052_ssc_write(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg)
+{
+       int ret = 0;
+
+       /* Reg address should be a valid address on PAGE0 or PAGE1 */
+       if ((sscmsg->addr < DA9052_PAGE0_REG_START) ||
+       (sscmsg->addr > DA9052_PAGE1_REG_END) ||
+       ((sscmsg->addr > DA9052_PAGE0_REG_END) &&
+       (sscmsg->addr < DA9052_PAGE1_REG_START)))
+               return INVALID_REGISTER;
+
+       ret = ssc_ops.write(da9052, sscmsg);
+
+       /* Update local cache if required */
+       if (!ret) {
+               /* Check if this register is Non-volatile*/
+               if (da9052->ssc_cache[sscmsg->addr].type != VOLATILE) {
+                       /* Update value */
+                       da9052->ssc_cache[sscmsg->addr].val = sscmsg->data;
+                       /* Make this cache entry valid */
+                       da9052->ssc_cache[sscmsg->addr].status = VALID;
+               }
+       }
+
+       return ret;
+}
+
+int da9052_ssc_read(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg)
+{
+       int ret = 0;
+
+       /* Reg addr should be a valid address on PAGE0 or PAGE1 */
+       if ((sscmsg->addr < DA9052_PAGE0_REG_START) ||
+       (sscmsg->addr > DA9052_PAGE1_REG_END) ||
+       ((sscmsg->addr > DA9052_PAGE0_REG_END) &&
+       (sscmsg->addr < DA9052_PAGE1_REG_START)))
+               return INVALID_REGISTER;
+
+       /*
+        * Check if this is a Non-volatile register, if yes then return value -
+        * from cache instead of actual reading from hardware. Before reading -
+        * cache entry, make sure that the entry is valid
+        */
+       /* The read request is for Non-volatile register */
+       /* Check if we have valid cached value for this */
+       if (da9052->ssc_cache[sscmsg->addr].status == VALID) {
+               /* We have valid cached value, copy this value */
+               sscmsg->data = da9052->ssc_cache[sscmsg->addr].val;
+
+               return 0;
+       }
+
+       ret = ssc_ops.read(da9052, sscmsg);
+
+       /* Update local cache if required */
+       if (!ret) {
+               /* Check if this register is Non-volatile*/
+               if (da9052->ssc_cache[sscmsg->addr].type != VOLATILE) {
+                       /* Update value */
+                       da9052->ssc_cache[sscmsg->addr].val = sscmsg->data;
+                       /* Make this cache entry valid */
+                       da9052->ssc_cache[sscmsg->addr].status = VALID;
+               }
+       }
+
+       return ret;
+}
+
+int da9052_ssc_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg,
+                               int msg_no)
+{
+       int ret = 0;
+       int cnt = 0;
+
+       /* Check request size */
+       if (msg_no > MAX_READ_WRITE_CNT)
+               return -EIO;
+
+       ret = ssc_ops.write_many(da9052, sscmsg, msg_no);
+       /* Update local cache, if required */
+       for (cnt = 0; cnt < msg_no; cnt++) {
+               /* Check if this register is Non-volatile*/
+               if (da9052->ssc_cache[sscmsg[cnt].addr].type != VOLATILE) {
+                       /* Update value */
+                       da9052->ssc_cache[sscmsg[cnt].addr].val =
+                       sscmsg[cnt].data;
+                       /* Make this cache entry valid */
+                       da9052->ssc_cache[sscmsg[cnt].addr].status = VALID;
+               }
+       }
+       return ret;
+}
+
+int da9052_ssc_read_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg,
+                       int msg_no)
+{
+       int ret = 0;
+       int cnt = 0;
+
+       /* Check request size */
+       if (msg_no > MAX_READ_WRITE_CNT)
+               return -EIO;
+
+       ret = ssc_ops.read_many(da9052, sscmsg, msg_no);
+       /* Update local cache, if required */
+       for (cnt = 0; cnt < msg_no; cnt++) {
+               /* Check if this register is Non-volatile*/
+               if (da9052->ssc_cache[sscmsg[cnt].addr].type
+                       != VOLATILE) {
+                       /* Update value */
+                       da9052->ssc_cache[sscmsg[cnt].addr].val =
+                       sscmsg[cnt].data;
+                       /* Make this cache entry valid */
+                       da9052->ssc_cache[sscmsg[cnt].addr].status = VALID;
+               }
+       }
+       return ret;
+}
+
+static irqreturn_t da9052_eh_isr(int irq, void *dev_id)
+{
+       struct da9052 *da9052 = dev_id;
+       /* Schedule work to be done */
+       schedule_work(&da9052->eh_isr_work);
+       /* Disable IRQ */
+       disable_irq_nosync(DA9052_IRQ);
+       return IRQ_HANDLED;
+}
+
+int eh_register_nb(struct da9052 *da9052, struct da9052_eh_nb *nb)
+{
+
+       if (nb == NULL) {
+               printk(KERN_INFO "EH REGISTER FUNCTION FAILED\n");
+               return -EINVAL;
+       }
+
+       if (nb->eve_type >= EVE_CNT) {
+               printk(KERN_INFO "Invalid DA9052 Event Type\n");
+               return -EINVAL;
+       }
+
+       /* Initialize list head inside notifier block */
+       INIT_LIST_HEAD(&nb->nb_list);
+
+       /* Acquire NB array lock */
+       if (down_interruptible(&eve_nb_array_lock))
+               return -EAGAIN;
+
+       /* Add passed NB to corresponding EVENT list */
+       list_add_tail(&nb->nb_list, &(eve_nb_array[nb->eve_type].nb_list));
+
+       /* Release NB array lock */
+       up(&eve_nb_array_lock);
+
+       return 0;
+}
+
+int eh_unregister_nb(struct da9052 *da9052, struct da9052_eh_nb *nb)
+{
+
+       if (nb == NULL)
+               return -EINVAL;
+
+       /* Acquire nb array lock */
+       if (down_interruptible(&eve_nb_array_lock))
+               return -EAGAIN;
+
+       /* Remove passed NB from list */
+       list_del_init(&(nb->nb_list));
+
+       /* Release NB array lock */
+       up(&eve_nb_array_lock);
+
+       return 0;
+}
+
+static int process_events(struct da9052 *da9052, int events_sts)
+{
+
+       int cnt = 0;
+       int tmp_events_sts = 0;
+       unsigned char event = 0;
+
+       struct list_head *ptr;
+       struct da9052_eh_nb *nb_ptr;
+
+       /* Now we have retrieved all events, process them one by one */
+       for (cnt = 0; cnt < EVE_CNT; cnt++) {
+               /*
+                * Starting with highest priority event,
+                * traverse through all event
+                */
+               tmp_events_sts = events_sts;
+
+               /* Find the event associated with higher priority */
+               event = cnt;
+
+               /* Check if interrupt is received for this event */
+               if (!((tmp_events_sts >> cnt) & 0x1))
+                       /* Event bit is not set for this event */
+                       /* Move to next event */
+                       continue;
+
+               if (event == PEN_DOWN_EVE) {
+                       if (list_empty(&(eve_nb_array[event].nb_list)))
+                               continue;
+               }
+
+               /* Event bit is set, execute all registered call backs */
+               if (down_interruptible(&eve_nb_array_lock)){
+                       printk(KERN_CRIT "Can't acquire eve_nb_array_lock \n");
+                       return -EIO;
+               }
+
+               list_for_each(ptr, &(eve_nb_array[event].nb_list)) {
+                       /*
+                        * nb_ptr will point to the structure in which
+                        * nb_list is embedded
+                        */
+                       nb_ptr = list_entry(ptr, struct da9052_eh_nb, nb_list);
+                       nb_ptr->call_back(nb_ptr, events_sts);
+               }
+               up(&eve_nb_array_lock);
+       }
+       return 0;
+}
+
+void eh_workqueue_isr(struct work_struct *work)
+{
+       struct da9052 *da9052 =
+               container_of(work, struct da9052, eh_isr_work);
+
+       struct da9052_ssc_msg eve_data[4];
+       struct da9052_ssc_msg eve_mask_data[4];
+       int events_sts, ret;
+       u32 mask;
+       unsigned char cnt = 0;
+
+       /* nIRQ is asserted, read event registeres to know what happened */
+       events_sts = 0;
+       mask = 0;
+
+       /* Prepare ssc message to read all four event registers */
+       for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++) {
+               eve_data[cnt].addr = (DA9052_EVENTA_REG + cnt);
+               eve_data[cnt].data = 0;
+       }
+
+       /* Prepare ssc message to read all four event registers */
+       for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++) {
+               eve_mask_data[cnt].addr = (DA9052_IRQMASKA_REG + cnt);
+               eve_mask_data[cnt].data = 0;
+       }
+
+       /* Now read all event and mask registers */
+       da9052_lock(da9052);
+
+       ret = da9052_ssc_read_many(da9052,eve_data, DA9052_EVE_REGISTERS);
+       if (ret) {
+               enable_irq(DA9052_IRQ);
+               da9052_unlock(da9052);
+               return;
+       }
+
+       ret = da9052_ssc_read_many(da9052,eve_mask_data, DA9052_EVE_REGISTERS);
+       if (ret) {
+               enable_irq(DA9052_IRQ);
+               da9052_unlock(da9052);
+               return;
+       }
+       /* Collect all events */
+       for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++)
+               events_sts |= (eve_data[cnt].data << (DA9052_EVE_REGISTER_SIZE
+                                                       * cnt));
+       /* Collect all mask */
+       for (cnt = 0; cnt < DA9052_EVE_REGISTERS; cnt++)
+               mask |= (eve_mask_data[cnt].data << (DA9052_EVE_REGISTER_SIZE
+                                               * cnt));
+       events_sts &= ~mask;
+       da9052_unlock(da9052);
+
+       /* Check if we really got any event */
+       if (events_sts == 0) {
+               enable_irq(DA9052_IRQ);
+               da9052_unlock(da9052);
+               return;
+       }
+
+       /* Process all events occurred */
+       process_events(da9052, events_sts);
+
+       da9052_lock(da9052);
+       /* Now clear EVENT registers */
+       for (cnt = 0; cnt < 4; cnt++) {
+               if (eve_data[cnt].data) {
+                       ret = da9052_ssc_write(da9052, &eve_data[cnt]);
+                       if (ret) {
+                               enable_irq(DA9052_IRQ);
+                               da9052_unlock(da9052);
+                               return;
+                       }
+               }
+       }
+       da9052_unlock(da9052);
+
+       /*
+       * This delay is necessary to avoid hardware fake interrupts
+       * from DA9052.
+       */
+#if defined  CONFIG_PMIC_DA9052 || defined  CONFIG_PMIC_DA9053AA
+       udelay(50);
+#endif
+       /* Enable HOST interrupt */
+       enable_irq(DA9052_IRQ);
+}
+
+static void da9052_eh_restore_irq(void)
+{
+       /* Put your platform and board specific code here */
+       free_irq(DA9052_IRQ, NULL);
+}
+
+static int da9052_add_subdevice_pdata(struct da9052 *da9052,
+               const char *name, void *pdata, size_t pdata_size)
+{
+       struct mfd_cell cell = {
+               .name = name,
+               .platform_data = pdata,
+               .data_size = pdata_size,
+       };
+       return mfd_add_devices(da9052->dev, -1, &cell, 1, NULL, 0);
+}
+
+static int da9052_add_subdevice(struct da9052 *da9052, const char *name)
+{
+       return da9052_add_subdevice_pdata(da9052, name, NULL, 0);
+}
+
+static int add_da9052_devices(struct da9052 *da9052)
+{
+       s32 ret = 0;
+       struct da9052_platform_data *pdata = da9052->dev->platform_data;
+       struct da9052_leds_platform_data leds_data = {
+                       .num_leds = pdata->led_data->num_leds,
+                       .led = pdata->led_data->led,
+       };
+       struct da9052_regulator_platform_data regulator_pdata = {
+               .regulators = pdata->regulators,
+       };
+
+       struct da9052_tsi_platform_data tsi_data = *(pdata->tsi_data);
+
+       if (pdata && pdata->init) {
+               ret = pdata->init(da9052);
+               if (ret != 0)
+                       return ret;
+       } else
+               printk(KERN_CRIT "No platform initialisation supplied \n");
+
+       ret = da9052_add_subdevice(da9052, "da9052-rtc");
+       if (ret)
+               return ret;
+       ret = da9052_add_subdevice(da9052, "da9052-onkey");
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice(da9052, "WLED-1");
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice(da9052, "WLED-2");
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice(da9052, "WLED-3");
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice(da9052, "da9052-adc");
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice(da9052, "da9052-wdt");
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice_pdata(da9052, "da9052-gpio",
+                               pdata, sizeof(*pdata));
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice_pdata(da9052, "da9052-leds",
+                               &leds_data, sizeof(leds_data));
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice_pdata(da9052, "da9052-regulator",
+               &regulator_pdata, sizeof(regulator_pdata));
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice_pdata(da9052, "da9052-tsi",
+                               &tsi_data, sizeof(tsi_data));
+       if (ret)
+               return ret;
+
+       ret = da9052_add_subdevice(da9052, "da9052-bat");
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+int da9052_ssc_init(struct da9052 *da9052)
+{
+       int cnt;
+       struct da9052_platform_data *pdata;
+
+       /* Initialize eve_nb_array */
+       for (cnt = 0; cnt < EVE_CNT; cnt++)
+               INIT_LIST_HEAD(&(eve_nb_array[cnt].nb_list));
+
+       /* Initialize mutex required for ADC Manual read */
+       mutex_init(&manconv_lock);
+
+       /* Initialize NB array lock */
+       init_MUTEX(&eve_nb_array_lock);
+
+       /* Assign the read-write function pointers */
+       da9052->read = da9052_ssc_read;
+       da9052->write = da9052_ssc_write;
+       da9052->read_many = da9052_ssc_read_many;
+       da9052->write_many = da9052_ssc_write_many;
+
+       if (SPI  == da9052->connecting_device && ssc_ops.write == NULL) {
+               /* Assign the read/write pointers to SPI/read/write */
+               ssc_ops.write = da9052_spi_write;
+               ssc_ops.read = da9052_spi_read;
+               ssc_ops.write_many = da9052_spi_write_many;
+               ssc_ops.read_many = da9052_spi_read_many;
+       }
+       else if (I2C  == da9052->connecting_device && ssc_ops.write == NULL) {
+               /* Assign the read/write pointers to SPI/read/write */
+               ssc_ops.write = da9052_i2c_write;
+               ssc_ops.read = da9052_i2c_read;
+               ssc_ops.write_many = da9052_i2c_write_many;
+               ssc_ops.read_many = da9052_i2c_read_many;
+       } else
+               return -1;
+       /* Assign the EH notifier block register/de-register functions */
+       da9052->register_event_notifier = eh_register_nb;
+       da9052->unregister_event_notifier = eh_unregister_nb;
+
+       /* Initialize ssc lock */
+       mutex_init(&da9052->ssc_lock);
+
+       pdata = da9052->dev->platform_data;
+       add_da9052_devices(da9052);
+
+       INIT_WORK(&da9052->eh_isr_work, eh_workqueue_isr);
+
+       if (request_irq(DA9052_IRQ, da9052_eh_isr, IRQ_TYPE_LEVEL_LOW,
+               DA9052_EH_DEVICE_NAME, da9052))
+               return -EIO;
+
+       return 0;
+}
+
+void da9052_ssc_exit(struct da9052 *da9052)
+{
+       printk(KERN_INFO "DA9052: Unregistering SSC device.\n");
+       mutex_destroy(&manconv_lock);
+       /* Restore IRQ line */
+       da9052_eh_restore_irq();
+       free_irq(DA9052_IRQ, NULL);
+       mutex_destroy(&da9052->ssc_lock);
+       mutex_destroy(&da9052->eve_nb_lock);
+       return;
+}
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9052 MFD Core");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DA9052_SSC_DEVICE_NAME);
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
new file mode 100644 (file)
index 0000000..5828b6d
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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.
+ *
+ * da9052-i2c.c: I2C SSC (Synchronous Serial Communication) driver for DA9052
+ */
+
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/i2c.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+static struct da9052 *da9052_i2c;
+
+#define I2C_CONNECTED 0
+
+static int da9052_i2c_is_connected(void)
+{
+
+        struct da9052_ssc_msg msg;
+
+        //printk("Entered da9052_i2c_is_connected.............\n");
+
+        msg.addr = DA9052_INTERFACE_REG;
+
+        /* Test spi connectivity by performing read of the GPIO_0-1 register */
+        if ( 0 != da9052_i2c_read(da9052_i2c, &msg)) {
+                printk("da9052_i2c_is_connected - i2c read failed.............\n");
+                return -1;
+        }
+        else {
+               printk("da9052_i2c_is_connected - i2c read success..............\n");
+                return 0;
+        }
+
+}
+
+static int __devinit da9052_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter;
+       // printk("\n\tEntered da9052_i2c_is_probe.............\n");
+
+        da9052_i2c = kzalloc(sizeof(struct da9052), GFP_KERNEL);
+
+        if (!da9052_i2c)
+                return -ENOMEM;
+
+       /* Get the bus driver handler */
+       adapter = to_i2c_adapter(client->dev.parent);
+
+       /* Check i2c bus driver supports byte data transfer */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_info(&client->dev,\
+               "Error in %s:i2c_check_functionality\n", __func__);
+               return -ENODEV;;
+       }
+
+       /* Store handle to i2c client */
+       da9052_i2c->i2c_client = client;
+
+       da9052_i2c->dev = &client->dev;
+
+       /* Initialize i2c data structure here*/
+       da9052_i2c->adapter = adapter;
+
+       /* host i2c driver looks only first 7 bits for the slave address */
+       da9052_i2c->slave_addr = DA9052_I2C_ADDR >> 1;
+
+       /* Store the i2c client data */
+       i2c_set_clientdata(client, da9052_i2c);
+
+        /* Validate I2C connectivity */
+        if ( I2C_CONNECTED  == da9052_i2c_is_connected()) {
+                /* I2C is connected */
+                da9052_i2c->connecting_device = I2C;
+                if( 0!= da9052_ssc_init(da9052_i2c) )
+                        return -ENODEV;
+        }
+        else {
+                return -ENODEV;
+        }
+
+        //printk("Exiting da9052_i2c_probe.....\n");
+
+       return 0;
+}
+
+static int da9052_i2c_remove(struct i2c_client *client)
+{
+
+       struct da9052 *da9052 = i2c_get_clientdata(client);
+
+       mfd_remove_devices(da9052->dev);
+       kfree(da9052);
+       return 0;
+}
+
+int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg)
+{
+       struct i2c_msg i2cmsg;
+       unsigned char buf[2] = {0};
+       int ret = 0;
+
+       /* Copy the ssc msg to local character buffer */
+       buf[0] = msg->addr;
+       buf[1] = msg->data;
+
+       /*Construct a i2c msg for a da9052 driver ssc message request */
+       i2cmsg.addr  = da9052->slave_addr;
+       i2cmsg.len   = 2;
+       i2cmsg.buf   = buf;
+
+       /* To write the data on I2C set flag to zero */
+       i2cmsg.flags = 0;
+
+       /* Start the i2c transfer by calling host i2c driver function */
+       ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
+
+       if (ret < 0) {
+               dev_info(&da9052->i2c_client->dev,\
+               "_%s:master_xfer Failed!!\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg)
+{
+
+       /*Get the da9052_i2c client details*/
+       unsigned char buf[2] = {0, 0};
+       struct i2c_msg i2cmsg[2];
+       int ret = 0;
+
+       /* Copy SSC Msg to local character buffer */
+       buf[0] = msg->addr;
+
+       /*Construct a i2c msg for a da9052 driver ssc message request */
+       i2cmsg[0].addr  = da9052->slave_addr ;
+       i2cmsg[0].len   = 1;
+       i2cmsg[0].buf   = &buf[0];
+
+       /*To write the data on I2C set flag to zero */
+       i2cmsg[0].flags = 0;
+
+       /* Read the data from da9052*/
+       /*Construct a i2c msg for a da9052 driver ssc message request */
+       i2cmsg[1].addr  = da9052->slave_addr ;
+       i2cmsg[1].len   = 1;
+       i2cmsg[1].buf   = &buf[1];
+
+       /*To read the data on I2C set flag to I2C_M_RD */
+       i2cmsg[1].flags = I2C_M_RD;
+
+       /* Start the i2c transfer by calling host i2c driver function */
+       ret = i2c_transfer(da9052->adapter, i2cmsg, 2);
+       if (ret < 0) {
+               dev_info(&da9052->i2c_client->dev,\
+               "2 - %s:master_xfer Failed!!\n", __func__);
+               return ret;
+       }
+
+       msg->data = *i2cmsg[1].buf;
+
+       return 0;
+}
+
+int da9052_i2c_write_many(struct da9052 *da9052,
+       struct da9052_ssc_msg *sscmsg, int msg_no)
+{
+
+       struct i2c_msg i2cmsg;
+       unsigned char data_buf[MAX_READ_WRITE_CNT+1];
+       struct da9052_ssc_msg ctrlb_msg;
+       struct da9052_ssc_msg *msg_queue = sscmsg;
+       int ret = 0;
+       /* Flag to check if requested registers are contiguous */
+       unsigned char cont_data = 1;
+       unsigned char cnt = 0;
+
+       /* Check if requested registers are contiguous */
+       for (cnt = 1; cnt < msg_no; cnt++) {
+               if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) {
+                       /* Difference is not 1, i.e. non-contiguous registers */
+                       cont_data = 0;
+                       break;
+               }
+       }
+
+       if (cont_data == 0) {
+               /* Requested registers are non-contiguous */
+               for (cnt = 0; cnt < msg_no; cnt++) {
+                       ret = da9052->write(da9052, &msg_queue[cnt]);
+                       if (ret != 0)
+                               return ret;
+               }
+               return 0;
+       }
+       /*
+       *  Requested registers are contiguous
+       * or PAGE WRITE sequence of I2C transactions is as below
+       * (slave_addr + reg_addr + data_1 + data_2 + ...)
+       * First read current WRITE MODE via CONTROL_B register of DA9052
+       */
+       ctrlb_msg.addr = DA9052_CONTROLB_REG;
+       ctrlb_msg.data = 0x0;
+       ret = da9052->read(da9052, &ctrlb_msg);
+
+       if (ret != 0)
+               return ret;
+
+       /* Check if PAGE WRITE mode is set */
+       if (ctrlb_msg.data & DA9052_CONTROLB_WRITEMODE) {
+               /* REPEAT WRITE mode is configured */
+               /* Now set DA9052 into PAGE WRITE mode */
+               ctrlb_msg.data &= ~DA9052_CONTROLB_WRITEMODE;
+               ret = da9052->write(da9052, &ctrlb_msg);
+
+               if (ret != 0)
+                       return ret;
+       }
+
+        /* Put first register address */
+       data_buf[0] = msg_queue[0].addr;
+
+       for (cnt = 0; cnt < msg_no; cnt++)
+               data_buf[cnt+1] = msg_queue[cnt].data;
+
+       /* Construct a i2c msg for PAGE WRITE */
+       i2cmsg.addr  = da9052->slave_addr ;
+       /* First register address + all data*/
+       i2cmsg.len   = (msg_no + 1);
+       i2cmsg.buf   = data_buf;
+
+       /*To write the data on I2C set flag to zero */
+       i2cmsg.flags = 0;
+
+       /* Start the i2c transfer by calling host i2c driver function */
+       ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
+       if (ret < 0) {
+               dev_info(&da9052->i2c_client->dev,\
+               "1 - i2c_transfer function falied in [%s]!!!\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+int da9052_i2c_read_many(struct da9052 *da9052,
+       struct da9052_ssc_msg *sscmsg, int msg_no)
+{
+
+       struct i2c_msg i2cmsg;
+       unsigned char data_buf[MAX_READ_WRITE_CNT];
+       struct da9052_ssc_msg *msg_queue = sscmsg;
+       int ret = 0;
+       /* Flag to check if requested registers are contiguous */
+       unsigned char cont_data = 1;
+       unsigned char cnt = 0;
+
+       /* Check if requested registers are contiguous */
+       for (cnt = 1; cnt < msg_no; cnt++) {
+               if ((msg_queue[cnt].addr - msg_queue[cnt-1].addr) != 1) {
+                       /* Difference is not 1, i.e. non-contiguous registers */
+                       cont_data = 0;
+                       break;
+               }
+       }
+
+       if (cont_data == 0) {
+               /* Requested registers are non-contiguous */
+               for (cnt = 0; cnt < msg_no; cnt++) {
+                       ret = da9052->read(da9052, &msg_queue[cnt]);
+                       if (ret != 0) {
+                               dev_info(&da9052->i2c_client->dev,\
+                               "Error in %s", __func__);
+                               return ret;
+                       }
+               }
+               return 0;
+       }
+
+       /*
+       * We want to perform PAGE READ via I2C
+       * For PAGE READ sequence of I2C transactions is as below
+       * (slave_addr + reg_addr) + (slave_addr + data_1 + data_2 + ...)
+       */
+       /* Copy address of first register */
+       data_buf[0] = msg_queue[0].addr;
+
+       /* Construct a i2c msg for first transaction of PAGE READ i.e. write */
+       i2cmsg.addr  = da9052->slave_addr ;
+       i2cmsg.len   = 1;
+       i2cmsg.buf   = data_buf;
+
+       /*To write the data on I2C set flag to zero */
+       i2cmsg.flags = 0;
+
+       /* Start the i2c transfer by calling host i2c driver function */
+       ret = i2c_transfer(da9052->adapter, &i2cmsg, 1);
+       if (ret < 0) {
+               dev_info(&da9052->i2c_client->dev,\
+               "1 - i2c_transfer function falied in [%s]!!!\n", __func__);
+               return ret;
+       }
+
+       /* Now Read the data from da9052 */
+       /* Construct a i2c msg for second transaction of PAGE READ i.e. read */
+       i2cmsg.addr  = da9052->slave_addr ;
+       i2cmsg.len   = msg_no;
+       i2cmsg.buf   = data_buf;
+
+       /*To read the data on I2C set flag to I2C_M_RD */
+       i2cmsg.flags = I2C_M_RD;
+
+       /* Start the i2c transfer by calling host i2c driver function */
+       ret = i2c_transfer(da9052->adapter,
+               &i2cmsg, 1);
+       if (ret < 0) {
+               dev_info(&da9052->i2c_client->dev,\
+               "2 - i2c_transfer function falied in [%s]!!!\n", __func__);
+               return ret;
+       }
+
+       /* Gather READ data */
+       for (cnt = 0; cnt < msg_no; cnt++)
+               sscmsg[cnt].data = data_buf[cnt];
+
+       return 0;
+}
+
+static struct i2c_device_id da9052_ssc_id[] = {
+       { DA9052_SSC_I2C_DEVICE_NAME, 0},
+       {}
+};
+
+static struct i2c_driver da9052_i2c_driver =  {
+       .driver = {
+               .name   = DA9052_SSC_I2C_DEVICE_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = da9052_i2c_probe,
+       .remove = da9052_i2c_remove,
+       .id_table       = da9052_ssc_id,
+};
+
+static int __init da9052_i2c_init(void)
+{
+        int ret = 0;
+       // printk("\n\nEntered da9052_i2c_init................\n\n");
+        ret = i2c_add_driver(&da9052_i2c_driver);
+        if (ret != 0) {
+                printk(KERN_ERR "Unable to register %s\n", DA9052_SSC_I2C_DEVICE_NAME);
+                return ret;
+        }
+        return 0;
+}
+module_init(da9052_i2c_init);
+
+static void  __exit da9052_i2c_exit(void)
+{
+        i2c_del_driver(&da9052_i2c_driver);
+}
+module_exit(da9052_i2c_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DA9052_SSC_I2C_DEVICE_NAME);
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
new file mode 100644 (file)
index 0000000..9dd90c2
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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.
+ *
+ * da9052-spi.c: SPI SSC (Synchronous Serial Communication) driver for DA9052
+ */
+
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+
+struct da9052 *da9052_spi;
+
+#define SPI_CONNECTED 0
+
+static int da9052_spi_is_connected(void)
+{
+
+        struct da9052_ssc_msg msg;
+       
+       //printk("Entered da9052_spi_is_connected.............\n");
+
+        msg.addr = DA9052_INTERFACE_REG;
+
+        /* Test spi connectivity by performing read of the GPIO_0-1 register and then verify the read value*/
+       if ( 0 != da9052_spi_read(da9052_spi, &msg)) {
+                printk("da9052_spi_is_connected - spi read failed.............\n");
+                return -1;
+        }
+        else if( 0x88 != msg.data ){
+                printk("da9052_spi_is_connected - spi read failed. Msg data =%x ..............\n",msg.data);
+                        return -1;
+        }
+
+       return 0;
+
+}
+
+static int da9052_spi_probe(struct spi_device *spi)
+{
+       //printk("\n\tEntered da9052_spi_probe.....\n");
+       
+       da9052_spi = kzalloc(sizeof(struct da9052), GFP_KERNEL);
+       
+       if (!da9052_spi)
+               return -ENOMEM;
+       
+       
+       spi->mode = SPI_MODE_0 | SPI_CPOL;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+       
+       da9052_spi->dev = &spi->dev;
+
+       da9052_spi->spi_dev = spi;
+       
+       /*
+        * Allocate memory for RX/TX bufferes used in single register read/write
+        */
+       da9052_spi->spi_rx_buf = kmalloc(2, GFP_KERNEL | GFP_DMA);
+       if (!da9052_spi->spi_rx_buf)
+               return -ENOMEM;
+       
+       da9052_spi->spi_tx_buf = kmalloc(2, GFP_KERNEL | GFP_DMA);
+       if (!da9052_spi->spi_tx_buf)
+               return -ENOMEM;
+
+       da9052_spi->spi_active_page  = PAGECON_0;
+       da9052_spi->rw_pol = 1;
+
+
+       dev_set_drvdata(&spi->dev, da9052_spi);
+
+
+        /* Validate SPI connectivity */
+        if ( SPI_CONNECTED  == da9052_spi_is_connected()) {
+               /* SPI is connected */
+               da9052_spi->connecting_device = SPI;
+                if( 0 != da9052_ssc_init(da9052_spi) )
+                       return -ENODEV;
+        }
+        else {
+                return -ENODEV;
+        }
+
+       //printk("Exiting da9052_spi_probe.....\n");
+       
+       return 0;
+}
+
+static int da9052_spi_remove(struct spi_device *spi)
+{
+       struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
+
+       printk("Entered da9052_spi_remove()\n");
+       if(SPI == da9052->connecting_device ) {
+               da9052_ssc_exit(da9052);
+       }
+       mfd_remove_devices(&spi->dev);
+       kfree(da9052->spi_rx_buf);
+       kfree(da9052->spi_tx_buf);
+       kfree(da9052);
+       return 0;
+}
+
+static struct spi_driver da9052_spi_driver = {
+       .driver = {
+               .name    = DA9052_SSC_SPI_DEVICE_NAME,
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_spi_probe,
+       .remove         = __devexit_p(da9052_spi_remove),
+};
+
+
+static int da9052_spi_set_page(struct da9052 *da9052, unsigned char page)
+{
+
+       struct da9052_ssc_msg sscmsg;
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int ret = 0;
+
+       printk("Entered da9052_spi_set_page.....\n");
+       if ((page != PAGECON_0) && ((page != PAGECON_128)))
+               return INVALID_PAGE;
+
+       /* Current configuration is PAGE-0 and write request for PAGE-1 */
+       /* set register address */
+       sscmsg.addr = DA9052_PAGECON0_REG;
+       /* set value */
+       sscmsg.data = page;
+
+       /* Check value of R/W_POL bit of INTERFACE register */
+       if (!da9052->rw_pol) {
+               /* We need to set 0th bit for write operation */
+               sscmsg.addr = ((sscmsg.addr << 1) | RW_POL);
+       } else {
+               /* We need to reset 0th bit for write operation */
+               sscmsg.addr = (sscmsg.addr << 1);
+       }
+
+       /* SMDK-6410 host SPI driver specific stuff */
+
+       /* Build our spi message */
+       printk("da9052_spi_set_page - Calling spi_message_init.....\n");
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+
+       xfer.len = 2;
+       xfer.tx_buf = da9052->spi_tx_buf;
+       xfer.rx_buf = da9052->spi_rx_buf;
+
+       da9052->spi_tx_buf[0] = sscmsg.addr;
+       da9052->spi_tx_buf[1] = sscmsg.data;
+
+       printk("da9052_spi_set_page - Calling spi_message_add_tail.....\n");
+       spi_message_add_tail(&xfer, &message);
+
+       /* Now, do the i/o */
+       printk("da9052_spi_set_page - Calling spi_sync.....\n");
+       ret = spi_sync(da9052->spi_dev, &message);
+
+       if (ret == 0) {
+               /* Active Page set successfully */
+               da9052->spi_active_page = page;
+               return 0;
+       } else {
+               /* Error in setting Active Page */
+               return ret;
+       }
+
+       return 0;
+}
+
+int da9052_spi_write(struct da9052 *da9052, struct da9052_ssc_msg *msg)
+{
+
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int ret;
+
+       /*
+        * We need a seperate copy of da9052_ssc_msg so that caller's
+        * copy remains intact
+       */
+       struct da9052_ssc_msg sscmsg;
+
+       /* Copy callers data in to our local copy */
+       sscmsg.addr = msg->addr;
+       sscmsg.data = msg->data;
+
+       if ((sscmsg.addr > PAGE_0_END) &&
+               (da9052->spi_active_page == PAGECON_0)) {
+               /*
+               * Current configuration is PAGE-0 and write request
+               * for PAGE-1
+               */
+               da9052_spi_set_page(da9052, PAGECON_128);
+               /* Set register address accordindly */
+               sscmsg.addr = (sscmsg.addr - PAGE_1_START);
+       } else if ((sscmsg.addr < PAGE_1_START) &&
+               (da9052->spi_active_page == PAGECON_128)) {
+               /*
+               * Current configuration is PAGE-1 and write request
+               * for PAGE-0
+               */
+               da9052_spi_set_page(da9052, PAGECON_0);
+       } else if (sscmsg.addr > PAGE_0_END) {
+               /*
+               * Current configuration is PAGE-1 and write request
+               * for PAGE-1. Just need to adjust register address
+               */
+               sscmsg.addr = (sscmsg.addr - PAGE_1_START);
+       }
+
+       /* Check value of R/W_POL bit of INTERFACE register */
+       if (!da9052->rw_pol) {
+               /* We need to set 0th bit for write operation */
+               sscmsg.addr = ((sscmsg.addr << 1) | RW_POL);
+       } else {
+               /* We need to reset 0th bit for write operation */
+               sscmsg.addr = (sscmsg.addr << 1);
+       }
+
+       /* SMDK-6410 host SPI driver specific stuff */
+
+       /* Build our spi message */
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+
+       xfer.len = 2;
+       xfer.tx_buf = da9052->spi_tx_buf;
+       xfer.rx_buf = da9052->spi_rx_buf;
+
+       da9052->spi_tx_buf[0] = sscmsg.addr;
+       da9052->spi_tx_buf[1] = sscmsg.data;
+
+       spi_message_add_tail(&xfer, &message);
+
+       /* Now, do the i/o */
+       ret = spi_sync(da9052->spi_dev, &message);
+
+       return ret;
+}
+
+int da9052_spi_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg,
+                                int msg_no)
+{
+       int cnt,ret=0;
+
+       for(cnt = 0; cnt < msg_no; cnt++, sscmsg++) {
+               ret = da9052_ssc_write(da9052,sscmsg);
+               if(ret != 0)
+               {
+                       printk("Error in %s", __FUNCTION__);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+int da9052_spi_read(struct da9052 *da9052, struct da9052_ssc_msg *msg)
+{
+
+       struct spi_message message;
+       struct spi_transfer xfer;
+       int ret;
+
+       /*
+       * We need a seperate copy of da9052_ssc_msg so that
+       * caller's copy remains intact
+       */
+       struct da9052_ssc_msg sscmsg;
+       
+
+       /* Copy callers data in to our local copy */
+       sscmsg.addr = msg->addr;
+       sscmsg.data = msg->data;
+
+       if ((sscmsg.addr > PAGE_0_END) &&
+               (da9052->spi_active_page == PAGECON_0)) {
+               /*
+               * Current configuration is PAGE-0 and
+               * read request for PAGE-1
+               */
+               printk("da9052_spi_read - if PAGECON_128.....\n");
+               da9052_spi_set_page(da9052, PAGECON_128);
+               /* Set register address accordindly */
+               sscmsg.addr = (sscmsg.addr - PAGE_1_START);
+       } else if ((sscmsg.addr < PAGE_1_START) &&
+               (da9052->spi_active_page == PAGECON_128)) {
+               /*
+               * Current configuration is PAGE-1 and
+               * write request for PAGE-0
+               */
+               printk("da9052_spi_read - if PAGECON_0.....\n");
+               da9052_spi_set_page(da9052, PAGECON_0);
+       } else if (sscmsg.addr > PAGE_0_END) {
+               /*
+               * Current configuration is PAGE-1 and write
+               * request for PAGE-1
+               * Just need to adjust register address
+               */
+               sscmsg.addr = (sscmsg.addr - PAGE_1_START);
+       }
+
+       /* Check value of R/W_POL bit of INTERFACE register */
+       if (da9052->rw_pol) {
+               /* We need to set 0th bit for read operation */
+               sscmsg.addr = ((sscmsg.addr << 1) | RW_POL);
+       } else {
+               /* We need to reset 0th bit for write operation */
+               sscmsg.addr = (sscmsg.addr << 1);
+       }
+
+       /* SMDK-6410 host SPI driver specific stuff */
+
+       /* Build our spi message */
+       spi_message_init(&message);
+       memset(&xfer, 0, sizeof(xfer));
+
+       xfer.len = 2;
+       xfer.tx_buf = da9052->spi_tx_buf;
+       xfer.rx_buf = da9052->spi_rx_buf;
+
+       da9052->spi_tx_buf[0] = sscmsg.addr;
+       da9052->spi_tx_buf[1] = 0xff;
+
+       da9052->spi_rx_buf[0] = 0;
+       da9052->spi_rx_buf[1] = 0;
+
+       spi_message_add_tail(&xfer, &message);
+
+       /* Now, do the i/o */
+       ret = spi_sync(da9052->spi_dev, &message);
+
+       if (ret == 0) {
+               /* Update read value in callers copy */
+               msg->data = da9052->spi_rx_buf[1];
+               return 0;
+       } else {
+               return ret;
+       }
+
+
+       return 0;
+}
+
+int da9052_spi_read_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg,
+                                int msg_no)
+{
+       int cnt,ret=0;
+
+       for(cnt = 0; cnt < msg_no; cnt++, sscmsg++) {
+               ret = da9052_ssc_read(da9052,sscmsg);
+               if(ret != 0)
+               {
+                       printk("Error in %s", __FUNCTION__);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int __init da9052_spi_init(void)
+{
+       int ret = 0;
+       //printk("Entered da9052_spi_init.....\n");
+       ret = spi_register_driver(&da9052_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Unable to register %s\n", DA9052_SSC_SPI_DEVICE_NAME);
+               return ret;
+       }
+        return 0;
+}
+module_init(da9052_spi_init);
+
+static void __exit da9052_spi_exit(void)
+{
+        spi_unregister_driver(&da9052_spi_driver);
+}
+
+module_exit(da9052_spi_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_DESCRIPTION("SPI driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DA9052_SSC_SPI_DEVICE_NAME);
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c
new file mode 100644 (file)
index 0000000..85561b4
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+ * da9052-battery.c  --  Batttery Driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/freezer.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/bat.h>
+#include <linux/mfd/da9052/adc.h>
+
+#define DA9052_BAT_DEVICE_NAME                 "da9052-bat"
+
+static const char  __initdata banner[] = KERN_INFO "DA9052 BAT, (c) \
+2009 Dialog semiconductor Ltd.\n";
+
+static struct da9052_bat_hysteresis bat_hysteresis;
+static struct da9052_bat_event_registration event_status;
+
+
+static u16 array_hys_batvoltage[2];
+static u16 bat_volt_arr[3];
+static u8 hys_flag = FALSE;
+
+static int da9052_read(struct da9052 *da9052, u8 reg_address, u8 *reg_data)
+{
+       struct da9052_ssc_msg msg;
+       int ret;
+
+       msg.addr = reg_address;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret)
+               goto ssc_comm_err;
+       da9052_unlock(da9052);
+
+       *reg_data = msg.data;
+       return 0;
+ssc_comm_err:
+       da9052_unlock(da9052);
+       return ret;
+}
+
+static s32 da9052_adc_read_ich(struct da9052 *da9052, u16 *data)
+{
+       struct da9052_ssc_msg msg;
+       da9052_lock(da9052);
+       /* Read charging conversion register */
+       msg.addr = DA9052_ICHGAV_REG;
+       msg.data = 0;
+       if (da9052->read(da9052, &msg)) {
+               da9052_unlock(da9052);
+               return DA9052_SSC_FAIL;
+       }
+       da9052_unlock(da9052);
+
+       *data = (u16)msg.data;
+       DA9052_DEBUG(
+       "In function: %s, ICHGAV_REG value read (1)= 0x%X \n",
+               __func__, msg.data);
+       return SUCCESS;
+}
+
+
+static s32 da9052_adc_read_tbat(struct da9052 *da9052, u16 *data)
+{
+       s32 ret;
+       u8 reg_data;
+
+       ret = da9052_read(da9052, DA9052_TBATRES_REG, &reg_data);
+       if (ret)
+               return ret;
+       *data = (u16)reg_data;
+
+       DA9052_DEBUG("In function: %s, TBATRES_REG value read (1)= 0x%X \n",
+               __func__, msg.data);
+       return SUCCESS;
+}
+
+s32 da9052_adc_read_vbat(struct da9052 *da9052, u16 *data)
+{
+       s32 ret;
+
+       ret = da9052_manual_read(da9052, DA9052_ADC_VBAT);
+       DA9052_DEBUG("In function: %s, VBAT value read (1)= 0x%X \n",
+               __func__, temp);
+       if (ret == -EIO) {
+               *data = 0;
+               return ret;
+       } else {
+               *data = ret;
+               return 0;
+       }
+       return 0;
+}
+
+
+static u16 filter_sample(u16 *buffer)
+{
+       u8 count;
+       u16 tempvalue = 0;
+       u16 ret;
+
+       if (buffer == NULL)
+               return -EINVAL;
+
+       for (count = 0; count < DA9052_FILTER_SIZE; count++)
+               tempvalue = tempvalue + *(buffer + count);
+
+       ret = tempvalue/DA9052_FILTER_SIZE;
+       return ret;
+}
+
+static s32  da9052_bat_get_battery_temperature(struct da9052_charger_device
+       *chg_device, u16 *buffer)
+{
+
+       u8 count;
+       u16 filterqueue[DA9052_FILTER_SIZE];
+
+       /* Measure the battery temperature using ADC function.
+               Number of read equal to average filter size*/
+
+       for (count = 0; count < DA9052_FILTER_SIZE; count++)
+               if (da9052_adc_read_tbat(chg_device->da9052, &filterqueue[count]))
+                       return -EIO;
+
+       /* Apply Average filter */
+       filterqueue[0] = filter_sample(filterqueue);
+
+       chg_device->bat_temp = filterqueue[0];
+       *buffer = chg_device->bat_temp;
+
+       return SUCCESS;
+}
+
+static s32  da9052_bat_get_chg_current(struct da9052_charger_device
+       *chg_device, u16 *buffer)
+{
+       if (chg_device->status == POWER_SUPPLY_STATUS_DISCHARGING)
+               return -EIO;
+
+               /* Measure the Charger current using ADC function */
+       if (da9052_adc_read_ich(chg_device->da9052, buffer))
+               return -EIO;
+
+       /* Convert the raw value in terms of mA */
+       chg_device->chg_current = ichg_reg_to_mA(*buffer);
+       *buffer = chg_device->chg_current;
+
+       return 0;
+}
+
+
+s32  da9052_bat_get_battery_voltage(struct da9052_charger_device *chg_device,
+ u16 *buffer)
+{
+       u8 count;
+       u16 filterqueue[DA9052_FILTER_SIZE];
+
+       /* Measure the battery voltage using ADC function.
+               Number of read equal to average filter size*/
+       for (count = 0; count < DA9052_FILTER_SIZE; count++)
+               if (da9052_adc_read_vbat(chg_device->da9052, &filterqueue[count]))
+                       return -EIO;
+
+       /* Apply average filter */
+       filterqueue[0] = filter_sample(filterqueue);
+
+       /* Convert battery voltage raw value in terms of mV */
+       chg_device->bat_voltage = volt_reg_to_mV(filterqueue[0]);
+       *buffer = chg_device->bat_voltage;
+       return 0;
+}
+
+static void da9052_bat_status_update(struct da9052_charger_device
+       *chg_device)
+{
+       struct da9052_ssc_msg msg;
+       u16 current_value = 0;
+       u16 buffer =0;
+       u8 regvalue = 0;
+       u8 old_status = chg_device->status;
+       
+       DA9052_DEBUG("FUNCTION = %s \n", __func__);
+
+       /* Read Status A register */
+       msg.addr = DA9052_STATUSA_REG;
+       msg.data = 0;
+       da9052_lock(chg_device->da9052);
+
+       if (chg_device->da9052->read(chg_device->da9052, &msg)) {
+               DA9052_DEBUG("%s : failed\n", __func__);
+               da9052_unlock(chg_device->da9052);
+               return;
+       }
+       regvalue = msg.data;
+
+       /* Read Status B register */
+       msg.addr = DA9052_STATUSB_REG;
+       msg.data = 0;
+       if (chg_device->da9052->read(chg_device->da9052, &msg)) {
+               DA9052_DEBUG("%s : failed\n", __func__);
+               da9052_unlock(chg_device->da9052);
+               return;
+       }
+       da9052_unlock(chg_device->da9052);
+
+       /* If DCINDET and DCINSEL are set then connected charger is
+                                               WALL Charger unit */
+       if( (regvalue & DA9052_STATUSA_DCINSEL) 
+                               && (regvalue & DA9052_STATUSA_DCINDET) ) {
+
+               chg_device->charger_type = DA9052_WALL_CHARGER;
+       }
+       /* If VBUS_DET and VBUSEL are set then connected charger is
+               USB Type */
+       else if((regvalue & DA9052_STATUSA_VBUSSEL) 
+                               && (regvalue & DA9052_STATUSA_VBUSDET)) {
+               if (regvalue & DA9052_STATUSA_VDATDET) {
+                       chg_device->charger_type = DA9052_USB_CHARGER;
+               }
+               else {
+                       /* Else it has to be USB Host charger */
+                       chg_device->charger_type = DA9052_USB_HUB;
+               }
+       }
+       /* Battery is discharging since charging device is not present */
+       else
+       {
+               chg_device->charger_type = DA9052_NOCHARGER;
+               /* Eqv to DISCHARGING_WITHOUT_CHARGER state */
+               chg_device->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
+       
+       if( chg_device->charger_type != DA9052_NOCHARGER ) {
+               /* if Charging end flag is set and Charging current is greater
+                       than charging end limit then battery is charging */
+               if ((msg.data & DA9052_STATUSB_CHGEND) != 0)  {
+                               
+                       if(da9052_bat_get_chg_current(chg_device,&current_value)) {
+                                       return;
+                       }
+                               
+                       if( current_value >= chg_device->chg_end_current ) {
+                               chg_device->status = POWER_SUPPLY_STATUS_CHARGING;
+                       }
+                       else {
+                               /* Eqv to DISCHARGING_WITH_CHARGER state*/
+                               chg_device->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       }
+               }
+               /* if Charging end flag is cleared then battery is charging */
+               else {
+                       chg_device->status = POWER_SUPPLY_STATUS_CHARGING;
+               }
+               
+               if( POWER_SUPPLY_STATUS_CHARGING == chg_device->status){
+                       if(msg.data != DA9052_STATUSB_CHGPRE) {
+                               /* Measure battery voltage. if battery voltage is greater than
+                               (VCHG_BAT - VCHG_DROP) then battery is in the termintation mode.
+                               */
+                               if(da9052_bat_get_battery_voltage(chg_device,&buffer)) {
+                                       DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+                                       return ;
+                               }
+                               if(buffer > (chg_device->bat_target_voltage -
+                                       chg_device->charger_voltage_drop) &&
+                                       ( chg_device->cal_capacity >= 99 ) ){
+                                       chg_device->status = POWER_SUPPLY_STATUS_FULL;
+                               }
+                               
+                       }
+               }
+       }
+       
+       if(chg_device->illegal)
+               chg_device->health = POWER_SUPPLY_HEALTH_UNKNOWN;
+       else if (chg_device->cal_capacity < chg_device->bat_capacity_limit_low)
+               chg_device->health = POWER_SUPPLY_HEALTH_DEAD;
+       else
+               chg_device->health = POWER_SUPPLY_HEALTH_GOOD;
+       
+       if ( chg_device->status != old_status)
+               power_supply_changed(&chg_device->psy);
+               
+       return;
+}
+
+static s32 da9052_bat_suspend_charging(struct da9052_charger_device *chg_device)
+{
+       struct da9052_ssc_msg msg;
+
+       if ((chg_device->status == POWER_SUPPLY_STATUS_DISCHARGING) ||
+               (chg_device->status == POWER_SUPPLY_STATUS_NOT_CHARGING))
+               return 0;
+
+       msg.addr = DA9052_INPUTCONT_REG;
+       msg.data = 0;
+       da9052_lock(chg_device->da9052);
+       /* Read Input condition register */
+       if (chg_device->da9052->read(chg_device->da9052, &msg)) {
+               da9052_unlock(chg_device->da9052);
+               return DA9052_SSC_FAIL;
+       }
+
+       /* set both Wall charger and USB charger suspend bit */
+       msg.data = set_bits(msg.data, DA9052_INPUTCONT_DCINSUSP);
+       msg.data = set_bits(msg.data, DA9052_INPUTCONT_VBUSSUSP);
+
+       /* Write to Input control register */
+       if (chg_device->da9052->write(chg_device->da9052, &msg)) {
+               da9052_unlock(chg_device->da9052);
+               DA9052_DEBUG("%s : failed\n", __func__);
+               return DA9052_SSC_FAIL;
+       }
+       da9052_unlock(chg_device->da9052);
+
+       DA9052_DEBUG("%s : Sucess\n", __func__);
+       return 0;
+}
+
+u32 interpolated(u32 vbat_lower, u32  vbat_upper, u32  level_lower,
+       u32  level_upper, u32 bat_voltage)
+{
+       s32 temp;
+       /*apply formula y= yk + (x - xk) * (yk+1 -yk)/(xk+1 -xk) */
+       temp = ((level_upper - level_lower) * 1000)/(vbat_upper - vbat_lower);
+       temp = level_lower + (((bat_voltage - vbat_lower) * temp)/1000);
+
+       return temp;
+}
+
+s32 capture_first_correct_vbat_sample(struct da9052_charger_device *chg_device,
+u16 *battery_voltage)
+{
+       static u8 count;
+       s32 ret = 0;
+       u32 temp_data = 0;
+
+       ret = da9052_bat_get_battery_voltage(chg_device,
+               &bat_volt_arr[count]);
+       if (ret)
+               return ret;
+       count++;
+
+       if (count < chg_device->vbat_first_valid_detect_iteration)
+               return FAILURE;
+       for (count = 0; count <
+               (chg_device->vbat_first_valid_detect_iteration - 1);
+               count++) {
+                       temp_data = (bat_volt_arr[count] *
+                       (chg_device->hysteresis_window_size))/100;
+               bat_hysteresis.upper_limit = bat_volt_arr[count] + temp_data;
+               bat_hysteresis.lower_limit = bat_volt_arr[count] - temp_data;
+
+               if ((bat_volt_arr[count + 1] < bat_hysteresis.upper_limit) &&
+                       (bat_volt_arr[count + 1] >
+                       bat_hysteresis.lower_limit)) {
+                               *battery_voltage = (bat_volt_arr[count] +
+                               bat_volt_arr[count+1]) / 2;
+                               hys_flag = TRUE;
+                       return 0;
+               }
+       }
+
+       for (count = 0; count <
+               (chg_device->vbat_first_valid_detect_iteration - 1);
+                       count++)
+               bat_volt_arr[count] = bat_volt_arr[count + 1];
+
+       return FAILURE;
+}
+
+
+s32 check_hystersis(struct da9052_charger_device *chg_device, u16 *bat_voltage)
+{
+       u8 ret = 0;
+       u32 offset = 0;
+
+       /* Measure battery voltage using BAT internal function*/
+       if (hys_flag == FALSE) {
+               ret = capture_first_correct_vbat_sample
+                       (chg_device, &array_hys_batvoltage[0]);
+               if (ret)
+                       return ret;
+       }
+
+       ret = da9052_bat_get_battery_voltage
+               (chg_device, &array_hys_batvoltage[1]);
+       if (ret)
+               return ret;
+       *bat_voltage = array_hys_batvoltage[1];
+
+#if DA9052_BAT_FILTER_HYS
+       printk(KERN_CRIT "\nBAT_LOG: Previous Battery Voltage = %d mV\n",
+                               array_hys_batvoltage[0]);
+       printk(KERN_CRIT "\nBAT_LOG:Battery Voltage Before Filter = %d mV\n",
+                               array_hys_batvoltage[1]);
+#endif
+       /* Check if measured battery voltage value is within the hysteresis
+               window limit using measured battey votlage value */
+       if ((bat_hysteresis.upper_limit < *bat_voltage) ||
+                       (bat_hysteresis.lower_limit > *bat_voltage)) {
+
+               bat_hysteresis.index++;
+               if (bat_hysteresis.index ==
+                       chg_device->hysteresis_no_of_reading) {
+                       /* Hysteresis Window is set to +- of
+                       HYSTERESIS_WINDOW_SIZE percentage of current VBAT */
+                       bat_hysteresis.index = 0;
+                       offset = ((*bat_voltage) *
+                               chg_device->hysteresis_window_size)/
+                               100;
+                       bat_hysteresis.upper_limit = (*bat_voltage) + offset;
+                       bat_hysteresis.lower_limit = (*bat_voltage) - offset;
+               } else {
+#if DA9052_BAT_FILTER_HYS
+                       printk(KERN_CRIT "CheckHystersis: Failed\n");
+#endif
+                       return -EIO;
+               }
+       } else {
+               bat_hysteresis.index = 0;
+               offset = ((*bat_voltage) *
+                       chg_device->hysteresis_window_size)/100;
+               bat_hysteresis.upper_limit = (*bat_voltage) + offset;
+               bat_hysteresis.lower_limit = (*bat_voltage) - offset;
+       }
+
+       /* Digital C Filter, formula Yn = k Yn-1 + (1-k) Xn */
+       *bat_voltage = ((chg_device->chg_hysteresis_const *
+               array_hys_batvoltage[0])/100) +
+               (((100 - chg_device->chg_hysteresis_const) *
+               array_hys_batvoltage[1])/100);
+
+       if ((chg_device->status == POWER_SUPPLY_STATUS_DISCHARGING) &&
+               (*bat_voltage > array_hys_batvoltage[0])) {
+                       *bat_voltage = array_hys_batvoltage[0];
+       }
+
+       array_hys_batvoltage[0] = *bat_voltage;
+
+#if DA9052_BAT_FILTER_HYS
+       printk(KERN_CRIT "\nBAT_LOG:Battery Voltage After Filter = %d mV\n",\
+               *bat_voltage);
+       
+#endif
+       return 0;
+}
+
+u8 select_temperature(u8 temp_index, u16 bat_temperature)
+{
+       u16 temp_temperature = 0;
+       temp_temperature = (temperature_lookup_ref[temp_index] +
+                               temperature_lookup_ref[temp_index+1]) / 2;
+
+       if (bat_temperature >= temp_temperature) {
+               temp_index += 1;
+               return temp_index;
+       } else
+               return temp_index;
+}
+
+s32 da9052_bat_level_update(struct da9052_charger_device *chg_device)
+{
+       u16 bat_temperature;
+       u16 bat_voltage;
+       u32 vbat_lower, vbat_upper, level_upper, level_lower, level;
+       u8 access_index = 0;
+       u8 index = 0, ret;
+       u8 flag = FALSE;
+
+       ret = 0;
+       vbat_lower = 0;
+       vbat_upper = 0;
+       level_upper = 0;
+       level_lower = 0;
+
+       ret = check_hystersis(chg_device, &bat_voltage);
+       if (ret)
+               return ret;
+
+       ret = da9052_bat_get_battery_temperature(chg_device,
+               &bat_temperature);
+       if (ret)
+               return ret;
+
+       for (index = 0; index < (DA9052_NO_OF_LOOKUP_TABLE-1); index++) {
+               if (bat_temperature <= temperature_lookup_ref[0]) {
+                       access_index = 0;
+                       break;
+               } else if (bat_temperature >
+                       temperature_lookup_ref[DA9052_NO_OF_LOOKUP_TABLE]){
+                               access_index = DA9052_NO_OF_LOOKUP_TABLE - 1;
+                       break;
+               } else if ((bat_temperature >= temperature_lookup_ref[index]) &&
+                       (bat_temperature >= temperature_lookup_ref[index+1])) {
+                       access_index = select_temperature(index,
+                               bat_temperature);
+                       break;
+               }
+       }
+       if (bat_voltage >= vbat_vs_capacity_look_up[access_index][0][0]) {
+               chg_device->cal_capacity = 100;
+               return 0;
+       }
+       if (bat_voltage <= vbat_vs_capacity_look_up[access_index]
+               [DA9052_LOOK_UP_TABLE_SIZE-1][0]){
+                       chg_device->cal_capacity = 0;
+                       return 0;
+       }
+       flag = FALSE;
+
+       for (index = 0; index < (DA9052_LOOK_UP_TABLE_SIZE-1); index++) {
+               if ((bat_voltage <=
+               vbat_vs_capacity_look_up[access_index][index][0]) &&
+               (bat_voltage >=
+               vbat_vs_capacity_look_up[access_index][index+1][0])) {
+                       vbat_upper =
+                       vbat_vs_capacity_look_up[access_index][index][0];
+                       vbat_lower =
+                       vbat_vs_capacity_look_up[access_index][index+1][0];
+                       level_upper =
+                       vbat_vs_capacity_look_up[access_index][index][1];
+                       level_lower =
+                       vbat_vs_capacity_look_up[access_index][index+1][1];
+                       flag = TRUE;
+                       break;
+               }
+       }
+       if (!flag)
+               return -EIO;
+
+       level = interpolated(vbat_lower, vbat_upper, level_lower,
+               level_upper, bat_voltage);
+       chg_device->cal_capacity = level;
+       DA9052_DEBUG(" TOTAl_BAT_CAPACITY : %d\n", chg_device->cal_capacity);
+       return 0;
+}
+
+void da9052_bat_tbat_handler(struct da9052_eh_nb *eh_data, unsigned int event)
+{
+       struct da9052_charger_device *chg_device =
+       container_of(eh_data, struct da9052_charger_device, tbat_eh_data);
+       
+       chg_device->health = POWER_SUPPLY_HEALTH_OVERHEAT;
+       
+}
+
+static s32 da9052_bat_register_event(struct da9052_charger_device *chg_device)
+{
+       s32 ret;
+       
+       if (event_status.da9052_event_tbat == FALSE) {
+               chg_device->tbat_eh_data.eve_type = TBAT_EVE;
+               chg_device->tbat_eh_data.call_back =da9052_bat_tbat_handler;
+               DA9052_DEBUG("events = %d\n",TBAT_EVE);
+               ret = chg_device->da9052->register_event_notifier
+                       (chg_device->da9052, &chg_device->tbat_eh_data);
+               if (ret)
+                       return -EIO;
+               event_status.da9052_event_tbat = TRUE;
+       }
+       
+       return 0;
+}
+
+static s32 da9052_bat_unregister_event(struct da9052_charger_device *chg_device)
+{
+       s32 ret;
+       
+       if (event_status.da9052_event_tbat) {
+               ret =
+                       chg_device->da9052->unregister_event_notifier
+                               (chg_device->da9052, &chg_device->tbat_eh_data);
+               if (ret)
+                       return -EIO;
+               event_status.da9052_event_tbat = FALSE;
+       }
+       
+       return 0;
+}
+
+static int da9052_bat_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct da9052_charger_device *chg_device =
+       container_of(psy, struct da9052_charger_device, psy);
+
+       /* Validate battery presence */ 
+       if( chg_device->illegal &&  psp != POWER_SUPPLY_PROP_PRESENT  ) {
+               return -ENODEV;
+       }
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = chg_device->status;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = (chg_device->charger_type == DA9052_NOCHARGER) ? 0: 1;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = chg_device->illegal;
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = chg_device->health;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               val->intval = chg_device->bat_target_voltage * 1000;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = chg_device->bat_volt_cutoff * 1000;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+               val->intval = chg_device->bat_voltage * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               val->intval = chg_device->chg_current * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = chg_device->cal_capacity;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = bat_temp_reg_to_C(chg_device->bat_temp);
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = chg_device->technology;
+               break;
+       default:
+               return -EINVAL;
+       break;
+       }
+       return 0;
+}
+
+
+static u8 detect_illegal_battery(struct da9052_charger_device *chg_device)
+{
+       u16 buffer = 0;
+       s32  ret = 0;
+
+       /* Measure battery temeperature */
+       ret = da9052_bat_get_battery_temperature(chg_device, &buffer);
+       if (ret) {
+               DA9052_DEBUG("%s: Battery temperature measurement failed \n",
+               __func__);
+               return ret;
+       }
+
+       if (buffer > chg_device->bat_with_no_resistor)
+               chg_device->illegal = TRUE;
+       else
+               chg_device->illegal = FALSE;
+
+
+       /* suspend charging of battery if illegal battey is detected */
+       if (chg_device->illegal)
+               da9052_bat_suspend_charging(chg_device);
+
+       return chg_device->illegal;
+}
+
+void da9052_update_bat_properties(struct da9052_charger_device *chg_device)
+{
+       /* Get Bat status and type */
+       da9052_bat_status_update(chg_device);
+       da9052_bat_level_update(chg_device);
+}
+
+static void da9052_bat_external_power_changed(struct power_supply *psy)
+{
+       struct da9052_charger_device *chg_device =
+       container_of(psy, struct da9052_charger_device, psy);
+
+       cancel_delayed_work(&chg_device->monitor_work);
+       queue_delayed_work(chg_device->monitor_wqueue, &chg_device->monitor_work, HZ/10);
+}
+
+
+static void da9052_bat_work(struct work_struct *work) 
+{
+       struct da9052_charger_device *chg_device = container_of(work,
+               struct da9052_charger_device,monitor_work.work);
+               
+       da9052_update_bat_properties(chg_device);
+       queue_delayed_work(chg_device->monitor_wqueue, &chg_device->monitor_work, HZ * 8);
+}
+
+static enum power_supply_property da9052_bat_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_AVG,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       
+};
+
+static s32 __devinit da9052_bat_probe(struct platform_device *pdev)
+{
+       struct da9052_charger_device *chg_device;
+       u8 reg_data;
+       int ret;
+
+       chg_device = kzalloc(sizeof(*chg_device), GFP_KERNEL);
+       if (!chg_device)
+               return -ENOMEM;
+
+       chg_device->da9052 = dev_get_drvdata(pdev->dev.parent);
+       platform_set_drvdata(pdev, chg_device);
+       
+       chg_device->psy.name                    = DA9052_BAT_DEVICE_NAME;
+       chg_device->psy.type                    = POWER_SUPPLY_TYPE_BATTERY;
+       chg_device->psy.properties              = da9052_bat_props;
+       chg_device->psy.num_properties          = ARRAY_SIZE(da9052_bat_props);
+       chg_device->psy.get_property            = da9052_bat_get_property;
+       chg_device->psy.external_power_changed  = da9052_bat_external_power_changed;
+       chg_device->psy.use_for_apm             = 1;
+       chg_device->charger_type                = DA9052_NOCHARGER;
+       chg_device->status                      = POWER_SUPPLY_STATUS_UNKNOWN;
+       chg_device->health                      = POWER_SUPPLY_HEALTH_UNKNOWN;
+       chg_device->technology                  = POWER_SUPPLY_TECHNOLOGY_LION;
+       chg_device->bat_with_no_resistor        = 62;
+       chg_device->bat_capacity_limit_low      = 4;
+       chg_device->bat_capacity_limit_high     = 70;
+       chg_device->bat_capacity_full           = 100;
+       chg_device->bat_volt_cutoff             = 2800;
+       chg_device->vbat_first_valid_detect_iteration = 3;
+       chg_device->hysteresis_window_size      =1;
+       chg_device->chg_hysteresis_const        =89;
+       chg_device->hysteresis_reading_interval =1000;
+       chg_device->hysteresis_no_of_reading    =10;
+
+       ret = da9052_read(chg_device->da9052, DA9052_CHGCONT_REG, &reg_data);
+       if (ret)
+               goto err_charger_init;
+       chg_device->charger_voltage_drop = bat_drop_reg_to_mV(reg_data &&
+                                                       DA9052_CHGCONT_TCTR);
+       chg_device->bat_target_voltage =
+                       bat_reg_to_mV(reg_data && DA9052_CHGCONT_VCHGBAT);
+       
+       ret = da9052_read(chg_device->da9052, DA9052_ICHGEND_REG, &reg_data);
+       if (ret)
+               goto err_charger_init;
+       chg_device->chg_end_current = ichg_reg_to_mA(reg_data);
+       
+       bat_hysteresis.upper_limit      = 0;
+       bat_hysteresis.lower_limit      = 0;
+       bat_hysteresis.hys_flag         = 0;
+
+       chg_device->illegal             = FALSE;
+       detect_illegal_battery(chg_device);
+
+       da9052_bat_register_event(chg_device);
+       if (ret)
+               goto err_charger_init;
+       
+       ret = power_supply_register(&pdev->dev, &chg_device->psy);
+        if (ret)
+               goto err_charger_init;
+       
+       INIT_DELAYED_WORK(&chg_device->monitor_work, da9052_bat_work);
+       chg_device->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id);
+       if (!chg_device->monitor_wqueue) {
+               goto err_charger_init;
+       }
+       queue_delayed_work(chg_device->monitor_wqueue, &chg_device->monitor_work, HZ * 1);
+       
+       return 0;
+
+err_charger_init:
+       platform_set_drvdata(pdev, NULL);
+       kfree(chg_device);
+       return ret;
+}
+static int __devexit da9052_bat_remove(struct platform_device *dev)
+{
+       struct da9052_charger_device *chg_device = platform_get_drvdata(dev);
+       
+       /* unregister the events.*/
+       da9052_bat_unregister_event(chg_device);
+       
+       cancel_rearming_delayed_workqueue(chg_device->monitor_wqueue,
+                                         &chg_device->monitor_work);
+       destroy_workqueue(chg_device->monitor_wqueue);
+       
+       power_supply_unregister(&chg_device->psy);
+       
+       return 0;
+}
+
+static struct platform_driver da9052_bat_driver = {
+       .probe          = da9052_bat_probe,
+       .remove         = __devexit_p(da9052_bat_remove),
+       .driver.name    = DA9052_BAT_DEVICE_NAME,
+       .driver.owner   = THIS_MODULE,
+};
+
+static int __init da9052_bat_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&da9052_bat_driver);
+}
+
+static void __exit da9052_bat_exit(void)
+{
+       // To remove printk("DA9052: Unregistering BAT device.\n");
+       platform_driver_unregister(&da9052_bat_driver);
+}
+
+module_init(da9052_bat_init);
+module_exit(da9052_bat_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd");
+MODULE_DESCRIPTION("DA9052 BAT Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
new file mode 100644 (file)
index 0000000..780c824
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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.
+ *
+ * da9052-regulator.c: Regulator driver for DA9052
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/pm.h>
+
+static struct regulator_ops da9052_ldo_buck_ops;
+
+
+struct regulator {
+       struct device *dev;
+       struct list_head list;
+       int uA_load;
+       int min_uV;
+       int max_uV;
+       int enabled; /* client has called enabled */
+       char *supply_name;
+       struct device_attribute dev_attr;
+       struct regulator_dev *rdev;
+};
+
+
+
+
+#define DA9052_LDO(_id, max, min, step_v, reg, mbits, cbits) \
+{\
+               .reg_desc       = {\
+               .name           = #_id,\
+               .ops            = &da9052_ldo_buck_ops,\
+               .type           = REGULATOR_VOLTAGE,\
+               .id                     = _id,\
+               .owner          = THIS_MODULE,\
+       },\
+       .reg_const = {\
+               .max_uV         = (max) * 1000,\
+               .min_uV         = (min) * 1000,\
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\
+               | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\
+               .valid_modes_mask = REGULATOR_MODE_NORMAL,\
+       },\
+               .step_uV                = (step_v) * 1000,\
+               .reg_add                = (reg),\
+               .mask_bits              = (mbits),\
+               .en_bit_mask    = (cbits),\
+}
+
+struct regulator_info {
+       struct regulator_desc reg_desc;
+       struct regulation_constraints reg_const;
+       int step_uV;
+       unsigned char reg_add;
+       unsigned char mask_bits;
+       unsigned char en_bit_mask;
+};
+
+struct da9052_regulator_priv {
+       struct da9052 *da9052;
+       struct regulator_dev *regulators[];
+};
+
+struct regulator_info da9052_regulators[] = {
+       /* LD01 - LDO10*/
+       DA9052_LDO(DA9052_LDO1, DA9052_LDO1_VOLT_UPPER, DA9052_LDO1_VOLT_LOWER,
+                       DA9052_LDO1_VOLT_STEP, DA9052_LDO1_REG,
+                       DA9052_LDO1_VLDO1, DA9052_LDO1_LDO1EN),
+
+       DA9052_LDO(DA9052_LDO2,
+                       DA9052_LDO2_VOLT_UPPER, DA9052_LDO2_VOLT_LOWER,
+                       DA9052_LDO2_VOLT_STEP, DA9052_LDO2_REG,
+                       DA9052_LDO2_VLDO2,
+                       DA9052_LDO2_LDO2EN),
+
+       DA9052_LDO(DA9052_LDO3, DA9052_LDO34_VOLT_UPPER,
+                       DA9052_LDO34_VOLT_LOWER,
+                       DA9052_LDO34_VOLT_STEP, DA9052_LDO3_REG,
+                       DA9052_LDO3_VLDO3, DA9052_LDO3_LDO3EN),
+
+       DA9052_LDO(DA9052_LDO4, DA9052_LDO34_VOLT_UPPER,
+                       DA9052_LDO34_VOLT_LOWER,
+                       DA9052_LDO34_VOLT_STEP, DA9052_LDO4_REG,
+                       DA9052_LDO4_VLDO4, DA9052_LDO4_LDO4EN),
+
+       DA9052_LDO(DA9052_LDO5, DA9052_LDO567810_VOLT_UPPER,
+                       DA9052_LDO567810_VOLT_LOWER,
+                       DA9052_LDO567810_VOLT_STEP, DA9052_LDO5_REG,
+                       DA9052_LDO5_VLDO5, DA9052_LDO5_LDO5EN),
+
+       DA9052_LDO(DA9052_LDO6, DA9052_LDO567810_VOLT_UPPER,
+                       DA9052_LDO567810_VOLT_LOWER,
+                       DA9052_LDO567810_VOLT_STEP, DA9052_LDO6_REG,
+                       DA9052_LDO6_VLDO6, DA9052_LDO6_LDO6EN),
+
+       DA9052_LDO(DA9052_LDO7, DA9052_LDO567810_VOLT_UPPER,
+                       DA9052_LDO567810_VOLT_LOWER,
+                       DA9052_LDO567810_VOLT_STEP, DA9052_LDO7_REG,
+                       DA9052_LDO7_VLDO7, DA9052_LDO7_LDO7EN),
+
+       DA9052_LDO(DA9052_LDO8, DA9052_LDO567810_VOLT_UPPER,
+                       DA9052_LDO567810_VOLT_LOWER,
+                       DA9052_LDO567810_VOLT_STEP, DA9052_LDO8_REG,
+                       DA9052_LDO8_VLDO8, DA9052_LDO8_LDO8EN),
+
+       DA9052_LDO(DA9052_LDO9, DA9052_LDO9_VOLT_UPPER,
+                       DA9052_LDO9_VOLT_LOWER,
+                       DA9052_LDO9_VOLT_STEP,
+                       DA9052_LDO9_REG, DA9052_LDO9_VLDO9,
+                       DA9052_LDO9_LDO9EN),
+
+       DA9052_LDO(DA9052_LDO10, DA9052_LDO567810_VOLT_UPPER,
+                       DA9052_LDO567810_VOLT_LOWER,
+                       DA9052_LDO567810_VOLT_STEP, DA9052_LDO10_REG,
+                       DA9052_LDO10_VLDO10, DA9052_LDO10_LDO10EN),
+
+       /* BUCKS */
+       DA9052_LDO(DA9052_BUCK_CORE, DA9052_BUCK_CORE_PRO_VOLT_UPPER,
+                       DA9052_BUCK_CORE_PRO_VOLT_LOWER,
+                       DA9052_BUCK_CORE_PRO_STEP, DA9052_BUCKCORE_REG,
+                       DA9052_BUCKCORE_VBCORE, DA9052_BUCKCORE_BCOREEN),
+
+       DA9052_LDO(DA9052_BUCK_PRO, DA9052_BUCK_CORE_PRO_VOLT_UPPER,
+                       DA9052_BUCK_CORE_PRO_VOLT_LOWER,
+                       DA9052_BUCK_CORE_PRO_STEP, DA9052_BUCKPRO_REG,
+                       DA9052_BUCKPRO_VBPRO, DA9052_BUCKPRO_BPROEN),
+
+       DA9052_LDO(DA9052_BUCK_MEM, DA9052_BUCK_MEM_VOLT_UPPER,
+                       DA9052_BUCK_MEM_VOLT_LOWER,
+                       DA9052_BUCK_MEM_STEP, DA9052_BUCKMEM_REG,
+                       DA9052_BUCKMEM_VBMEM, DA9052_BUCKMEM_BMEMEN),
+#if defined (CONFIG_PMIC_DA9052)
+       DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER,
+                       DA9052_BUCK_PERI_VOLT_LOWER,
+                       DA9052_BUCK_PERI_STEP_BELOW_3000, DA9052_BUCKPERI_REG,
+                       DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN),
+#elif defined (CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx)
+       DA9052_LDO(DA9052_BUCK_PERI, DA9052_BUCK_PERI_VOLT_UPPER,
+                       DA9052_BUCK_PERI_VOLT_LOWER,
+                       DA9052_BUCK_PERI_STEP, DA9052_BUCKPERI_REG,
+                       DA9052_BUCKPERI_VBPERI, DA9052_BUCKPERI_BPERIEN),
+#endif
+};
+
+int da9052_ldo_buck_enable(struct regulator_dev *rdev)
+{
+       struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int ret = 0;
+       struct da9052_ssc_msg ssc_msg;
+
+       ssc_msg.addr = da9052_regulators[id].reg_add;
+       ssc_msg.data = 0;
+
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+
+       ssc_msg.data = (ssc_msg.data | da9052_regulators[id].en_bit_mask);
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(da9052_ldo_buck_enable);
+/* Code added to support additional attribure in sysfs - changestate */
+
+
+
+int da9052_ldo_buck_disable(struct regulator_dev *rdev)
+{
+       struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int ret;
+       struct da9052_ssc_msg ssc_msg;
+
+       ssc_msg.addr = da9052_regulators[id].reg_add;
+       ssc_msg.data = 0;
+
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+
+       ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].en_bit_mask));
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(da9052_ldo_buck_disable);
+/* Code added to support additional attribure in sysfs - changestate */
+
+static int da9052_ldo_buck_is_enabled(struct regulator_dev *rdev)
+{
+       struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int ret;
+       struct da9052_ssc_msg ssc_msg;
+       ssc_msg.addr = da9052_regulators[id].reg_add;
+       ssc_msg.data = 0;
+
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+       da9052_unlock(priv->da9052);
+       return (ssc_msg.data & da9052_regulators[id].en_bit_mask) != 0;
+}
+
+int da9052_ldo_buck_set_voltage(struct regulator_dev *rdev,
+                                       int min_uV, int max_uV)
+{
+       struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev);
+       struct da9052_ssc_msg ssc_msg;
+       int id = rdev_get_id(rdev);
+       int ret;
+       int ldo_volt = 0;
+
+       /* Below if condition is there for added setvoltage attribute
+       in sysfs */
+       if (0 == max_uV)
+               max_uV = da9052_regulators[id].reg_const.max_uV;
+
+       /* Compare voltage range */
+       if (min_uV > max_uV)
+               return -EINVAL;
+
+       /* Check Minimum/ Maximum voltage range */
+       if (min_uV < da9052_regulators[id].reg_const.min_uV ||
+               min_uV > da9052_regulators[id].reg_const.max_uV)
+               return -EINVAL;
+       if (max_uV < da9052_regulators[id].reg_const.min_uV ||
+               max_uV > da9052_regulators[id].reg_const.max_uV)
+               return -EINVAL;
+#if defined (CONFIG_PMIC_DA9052)
+       /* Get the ldo register value */
+       /* Varying step size for BUCK PERI */
+       if ((da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) &&
+                       (min_uV >= DA9052_BUCK_PERI_VALUES_3000)) {
+               ldo_volt = (DA9052_BUCK_PERI_VALUES_3000 -
+                       da9052_regulators[id].reg_const.min_uV)/
+                       (da9052_regulators[id].step_uV);
+               ldo_volt += (min_uV - DA9052_BUCK_PERI_VALUES_3000)/
+                       (DA9052_BUCK_PERI_STEP_ABOVE_3000);
+       } else{
+               ldo_volt = (min_uV - da9052_regulators[id].reg_const.min_uV)/
+                       (da9052_regulators[id].step_uV);
+               /* Check for maximum value */
+               if ((ldo_volt * da9052_regulators[id].step_uV) +
+                       da9052_regulators[id].reg_const.min_uV > max_uV)
+                       return -EINVAL;
+       }
+#elif defined (CONFIG_PMIC_DA9053AA) ||(CONFIG_PMIC_DA9053Bx)
+       ldo_volt = (min_uV - da9052_regulators[id].reg_const.min_uV)/
+               (da9052_regulators[id].step_uV);
+       /* Check for maximum value */
+       if ((ldo_volt * da9052_regulators[id].step_uV) +
+               da9052_regulators[id].reg_const.min_uV > max_uV)
+               return -EINVAL;
+#endif
+       /* Configure LDO Voltage, CONF bits */
+       ssc_msg.addr = da9052_regulators[id].reg_add;
+       ssc_msg.data = 0;
+
+       /* Read register */
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+
+       ssc_msg.data = (ssc_msg.data & ~(da9052_regulators[id].mask_bits));
+       ssc_msg.data |= ldo_volt;
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+
+       /* Set the GO LDO/BUCk bits so that the voltage changes */
+       ssc_msg.addr = DA9052_SUPPLY_REG;
+       ssc_msg.data = 0;
+
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+
+       switch (id) {
+       case DA9052_LDO2:
+               ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VLDO2GO);
+       break;
+       case DA9052_LDO3:
+               ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VLDO3GO);
+       break;
+       case DA9052_BUCK_CORE:
+               ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBCOREGO);
+       break;
+       case DA9052_BUCK_PRO:
+               ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBPROGO);
+       break;
+       case DA9052_BUCK_MEM:
+               ssc_msg.data = (ssc_msg.data | DA9052_SUPPLY_VBMEMGO);
+       break;
+       default:
+               da9052_unlock(priv->da9052);
+               return -EINVAL;
+       }
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+
+       da9052_unlock(priv->da9052);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(da9052_ldo_buck_set_voltage);
+/* Code added to support additional attributes in sysfs - setvoltage */
+
+
+int da9052_ldo_buck_get_voltage(struct regulator_dev *rdev)
+{
+       struct da9052_regulator_priv *priv = rdev_get_drvdata(rdev);
+       struct da9052_ssc_msg ssc_msg;
+       int id = rdev_get_id(rdev);
+       int ldo_volt = 0;
+       int ldo_volt_uV = 0;
+       int ret;
+
+       ssc_msg.addr = da9052_regulators[id].reg_add;
+       ssc_msg.data = 0;
+       /* Read register */
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret) {
+               da9052_unlock(priv->da9052);
+               return -EIO;
+       }
+       da9052_unlock(priv->da9052);
+
+       ldo_volt = ssc_msg.data & da9052_regulators[id].mask_bits;
+#if defined (CONFIG_PMIC_DA9052)
+       if (da9052_regulators[id].reg_desc.id == DA9052_BUCK_PERI) {
+               if (ldo_volt >= DA9052_BUCK_PERI_VALUES_UPTO_3000) {
+                       ldo_volt_uV = ((DA9052_BUCK_PERI_VALUES_UPTO_3000 *
+                               da9052_regulators[id].step_uV)
+                               + da9052_regulators[id].reg_const.min_uV);
+                       ldo_volt_uV = (ldo_volt_uV +
+                               (ldo_volt - DA9052_BUCK_PERI_VALUES_UPTO_3000)
+                               * (DA9052_BUCK_PERI_STEP_ABOVE_3000));
+               } else {
+                       ldo_volt_uV =
+                               (ldo_volt * da9052_regulators[id].step_uV)
+                               + da9052_regulators[id].reg_const.min_uV;
+               }
+       } else {
+               ldo_volt_uV = (ldo_volt * da9052_regulators[id].step_uV) +
+                               da9052_regulators[id].reg_const.min_uV;
+       }
+#elif defined (CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx)
+       ldo_volt_uV = (ldo_volt * da9052_regulators[id].step_uV) +
+                       da9052_regulators[id].reg_const.min_uV;
+#endif
+       return ldo_volt_uV;
+}
+EXPORT_SYMBOL_GPL(da9052_ldo_buck_get_voltage);
+/* Code added to support additional attributes in sysfs - setvoltage */
+
+
+static struct regulator_ops da9052_ldo_buck_ops = {
+       .is_enabled = da9052_ldo_buck_is_enabled,
+       .enable = da9052_ldo_buck_enable,
+       .disable = da9052_ldo_buck_disable,
+       .get_voltage = da9052_ldo_buck_get_voltage,
+       .set_voltage = da9052_ldo_buck_set_voltage,
+};
+
+static int __devinit da9052_regulator_probe(struct platform_device *pdev)
+{
+       struct da9052_regulator_priv *priv;
+       struct da9052_regulator_platform_data *pdata =
+                               (pdev->dev.platform_data);
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_init_data  *init_data;
+       int i, ret = 0;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       priv->da9052 = da9052;
+       for (i = 0; i < 14; i++) {
+
+               init_data = &pdata->regulators[i];
+               init_data->driver_data = da9052;
+               pdev->dev.platform_data = init_data;
+               priv->regulators[i] = regulator_register(
+                               &da9052_regulators[i].reg_desc,
+                               &pdev->dev, priv);
+               if (IS_ERR(priv->regulators[i])) {
+                       ret = PTR_ERR(priv->regulators[i]);
+                       goto err;
+               }
+       }
+       platform_set_drvdata(pdev, priv);
+       return 0;
+err:
+       while (--i >= 0)
+               regulator_unregister(priv->regulators[i]);
+       kfree(priv);
+       return ret;
+}
+
+static int __devexit da9052_regulator_remove(struct platform_device *pdev)
+{
+       struct da9052_regulator_priv *priv = platform_get_drvdata(pdev);
+       struct da9052_platform_data *pdata = pdev->dev.platform_data;
+       int i;
+
+       for (i = 0; i < pdata->num_regulators; i++)
+               regulator_unregister(priv->regulators[i]);
+
+       return 0;
+}
+
+static struct platform_driver da9052_regulator_driver = {
+       .probe          = da9052_regulator_probe,
+       .remove         = __devexit_p(da9052_regulator_remove),
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init da9052_regulator_init(void)
+{
+       return platform_driver_register(&da9052_regulator_driver);
+}
+subsys_initcall(da9052_regulator_init);
+
+static void __exit da9052_regulator_exit(void)
+{
+       platform_driver_unregister(&da9052_regulator_driver);
+}
+module_exit(da9052_regulator_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
new file mode 100644 (file)
index 0000000..be80c22
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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.
+ *
+ * rtc-da9052.c: RTC driver for DA9052
+ */
+
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/rtc.h>
+
+#define DRIVER_NAME "da9052-rtc"
+#define ENABLE         1
+#define DISABLE                0
+
+struct da9052_rtc {
+       struct rtc_device *rtc;
+       struct da9052 *da9052;
+       struct da9052_eh_nb eh_data;
+       unsigned char is_min_alarm;
+       unsigned char enable_tick_alarm;
+       unsigned char enable_clk_buffer;
+       unsigned char set_osc_trim_freq;
+};
+
+static int da9052_rtc_enable_alarm(struct da9052 *da9052, unsigned char flag);
+
+void da9052_rtc_notifier(struct da9052_eh_nb *eh_data, unsigned int event)
+{
+       struct da9052_rtc *rtc =
+               container_of(eh_data, struct da9052_rtc, eh_data);
+       struct da9052_ssc_msg msg;
+       unsigned int ret;
+
+       /* Check the alarm type - TIMER or TICK */
+       msg.addr = DA9052_ALARMMI_REG;
+
+       da9052_lock(rtc->da9052);
+       ret = rtc->da9052->read(rtc->da9052, &msg);
+       if (ret != 0) {
+               da9052_unlock(rtc->da9052);
+               return;
+       }
+
+       da9052_unlock(rtc->da9052);
+
+
+       if (msg.data & DA9052_ALARMMI_ALARMTYPE) {
+               da9052_rtc_enable_alarm(rtc->da9052, 0);
+               printk(KERN_INFO "RTC: TIMER ALARM\n");
+       } else {
+               kobject_uevent(&rtc->rtc->dev.kobj, KOBJ_CHANGE);
+               printk(KERN_INFO "RTC: TICK ALARM\n");
+       }
+}
+
+static int da9052_rtc_validate_parameters(struct rtc_time *rtc_tm)
+{
+
+       if (rtc_tm->tm_sec > DA9052_RTC_SECONDS_LIMIT)
+               return DA9052_RTC_INVALID_SECONDS;
+
+       if (rtc_tm->tm_min > DA9052_RTC_MINUTES_LIMIT)
+               return DA9052_RTC_INVALID_MINUTES;
+
+       if (rtc_tm->tm_hour > DA9052_RTC_HOURS_LIMIT)
+               return DA9052_RTC_INVALID_HOURS;
+
+       if (rtc_tm->tm_mday == 0)
+               return DA9052_RTC_INVALID_DAYS;
+
+       if ((rtc_tm->tm_mon > DA9052_RTC_MONTHS_LIMIT) ||
+       (rtc_tm->tm_mon == 0))
+               return DA9052_RTC_INVALID_MONTHS;
+
+       if (rtc_tm->tm_year > DA9052_RTC_YEARS_LIMIT)
+               return DA9052_RTC_INVALID_YEARS;
+
+       if ((rtc_tm->tm_mon == FEBRUARY)) {
+               if (((rtc_tm->tm_year % 4 == 0) &&
+                       (rtc_tm->tm_year % 100 != 0)) ||
+                       (rtc_tm->tm_year % 400 == 0)) {
+                       if (rtc_tm->tm_mday > 29)
+                               return DA9052_RTC_INVALID_DAYS;
+               } else if (rtc_tm->tm_mday > 28) {
+                       return DA9052_RTC_INVALID_DAYS;
+               }
+       }
+
+       if (((rtc_tm->tm_mon == APRIL) || (rtc_tm->tm_mon == JUNE) ||
+               (rtc_tm->tm_mon == SEPTEMBER) || (rtc_tm->tm_mon == NOVEMBER))
+               && (rtc_tm->tm_mday == 31)) {
+               return DA9052_RTC_INVALID_DAYS;
+       }
+
+
+       return 0;
+}
+
+static int da9052_rtc_settime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+
+       struct da9052_ssc_msg msg_arr[6];
+       int validate_param = 0;
+       unsigned char loop_index = 0;
+       int ret = 0;
+
+
+       /* System compatability */
+       rtc_tm->tm_year -= 100;
+       rtc_tm->tm_mon += 1;
+
+       validate_param = da9052_rtc_validate_parameters(rtc_tm);
+       if (validate_param)
+               return validate_param;
+
+       msg_arr[loop_index].addr = DA9052_COUNTS_REG;
+       msg_arr[loop_index++].data = DA9052_COUNTS_MONITOR | rtc_tm->tm_sec;
+
+       msg_arr[loop_index].addr = DA9052_COUNTMI_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_min;
+
+       msg_arr[loop_index].addr = DA9052_COUNTH_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_hour;
+
+       msg_arr[loop_index].addr = DA9052_COUNTD_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_mday;
+
+       msg_arr[loop_index].addr = DA9052_COUNTMO_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_mon;
+
+       msg_arr[loop_index].addr = DA9052_COUNTY_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_year;
+
+       da9052_lock(da9052);
+       ret = da9052->write_many(da9052, msg_arr, loop_index);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       da9052_unlock(da9052);
+       return 0;
+}
+
+static int da9052_rtc_gettime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+
+       struct da9052_ssc_msg msg[6];
+       unsigned char loop_index = 0;
+       int validate_param = 0;
+       int ret = 0;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_COUNTS_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_COUNTMI_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_COUNTH_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_COUNTD_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_COUNTMO_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_COUNTY_REG;
+
+       da9052_lock(da9052);
+       ret = da9052->read_many(da9052, msg, loop_index);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+       da9052_unlock(da9052);
+
+       rtc_tm->tm_year = msg[--loop_index].data & DA9052_COUNTY_COUNTYEAR;
+       rtc_tm->tm_mon = msg[--loop_index].data & DA9052_COUNTMO_COUNTMONTH;
+       rtc_tm->tm_mday = msg[--loop_index].data & DA9052_COUNTD_COUNTDAY;
+       rtc_tm->tm_hour = msg[--loop_index].data & DA9052_COUNTH_COUNTHOUR;
+       rtc_tm->tm_min = msg[--loop_index].data & DA9052_COUNTMI_COUNTMIN;
+       rtc_tm->tm_sec = msg[--loop_index].data & DA9052_COUNTS_COUNTSEC;
+
+       validate_param = da9052_rtc_validate_parameters(rtc_tm);
+       if (validate_param)
+               return validate_param;
+
+       /* System compatability */
+       rtc_tm->tm_year += 100;
+       rtc_tm->tm_mon -= 1;
+       return 0;
+}
+
+static int da9052_alarm_gettime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+       struct da9052_ssc_msg msg[5];
+       unsigned char loop_index = 0;
+       int validate_param = 0;
+       int ret = 0;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_ALARMMI_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_ALARMH_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_ALARMD_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_ALARMMO_REG;
+
+       msg[loop_index].data = 0;
+       msg[loop_index++].addr = DA9052_ALARMY_REG;
+
+       da9052_lock(da9052);
+       ret = da9052->read_many(da9052, msg, loop_index);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+       da9052_unlock(da9052);
+
+       rtc_tm->tm_year = msg[--loop_index].data & DA9052_ALARMY_ALARMYEAR;
+       rtc_tm->tm_mon = msg[--loop_index].data & DA9052_ALARMMO_ALARMMONTH;
+       rtc_tm->tm_mday = msg[--loop_index].data & DA9052_ALARMD_ALARMDAY;
+       rtc_tm->tm_hour = msg[--loop_index].data & DA9052_ALARMH_ALARMHOUR;
+       rtc_tm->tm_min = msg[--loop_index].data & DA9052_ALARMMI_ALARMMIN;
+
+       validate_param = da9052_rtc_validate_parameters(rtc_tm);
+       if (validate_param)
+               return validate_param;
+
+       /* System compatability */
+       rtc_tm->tm_year += 100;
+       rtc_tm->tm_mon -= 1;
+
+       return 0;
+}
+
+static int da9052_alarm_settime(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+
+       struct da9052_ssc_msg msg_arr[5];
+       struct da9052_ssc_msg msg;
+       int validate_param = 0;
+       unsigned char loop_index = 0;
+       int ret = 0;
+
+       rtc_tm->tm_sec = 0;
+
+       /* System compatability */
+       rtc_tm->tm_year -= 100;
+       rtc_tm->tm_mon += 1;
+
+       validate_param = da9052_rtc_validate_parameters(rtc_tm);
+       if (validate_param)
+               return validate_param;
+
+       msg.addr = DA9052_ALARMMI_REG;
+       msg.data = 0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       msg.data = msg.data & ~(DA9052_ALARMMI_ALARMMIN);
+       msg.data |= rtc_tm->tm_min;
+
+       msg_arr[loop_index].addr = DA9052_ALARMMI_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = msg.data;
+
+       msg_arr[loop_index].addr = DA9052_ALARMH_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_hour;
+
+       msg_arr[loop_index].addr = DA9052_ALARMD_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_mday;
+
+       msg_arr[loop_index].addr = DA9052_ALARMMO_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = rtc_tm->tm_mon;
+
+       msg.addr = DA9052_ALARMY_REG;
+       msg.data = 0;
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       msg.data = msg.data & ~(DA9052_ALARMY_ALARMYEAR);
+
+
+       msg.data |= rtc_tm->tm_year;
+       msg_arr[loop_index].addr = DA9052_ALARMY_REG;
+       msg_arr[loop_index].data = 0;
+       msg_arr[loop_index++].data = msg.data;
+
+       ret = da9052->write_many(da9052, msg_arr, loop_index);
+       if (ret) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       da9052_unlock(da9052);
+       return 0;
+}
+
+static int da9052_rtc_get_alarm_status(struct da9052 *da9052)
+{
+       struct da9052_ssc_msg msg;
+       int ret = 0;
+
+       msg.addr = DA9052_ALARMY_REG;
+       msg.data = 0;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0) {
+                       da9052_unlock(da9052);
+       return ret;
+       }
+
+       da9052_unlock(da9052);
+       msg.data &= DA9052_ALARMY_ALARMON;
+
+       return (msg.data > 0) ? 1 : 0;
+}
+
+
+static int da9052_rtc_enable_alarm(struct da9052 *da9052, unsigned char flag)
+{
+       struct da9052_ssc_msg msg;
+       int ret = 0;
+
+       msg.addr = DA9052_ALARMY_REG;
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       if (flag)
+               msg.data = msg.data | DA9052_ALARMY_ALARMON;
+       else
+               msg.data = msg.data & ~(DA9052_ALARMY_ALARMON);
+
+       ret = da9052->write(da9052, &msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+       da9052_unlock(da9052);
+
+       return 0;
+}
+
+
+static ssize_t da9052_rtc_mask_irq(struct da9052 *da9052)
+ {
+       unsigned char data = 0;
+       ssize_t ret = 0;
+       struct da9052_ssc_msg ssc_msg;
+
+       ssc_msg.addr = DA9052_IRQMASKA_REG;
+       ssc_msg.data = 0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       data = ret;
+       ssc_msg.data = data |= DA9052_IRQMASKA_MALRAM;
+
+       ret = da9052->write(da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       da9052_unlock(da9052);
+       return 0;
+}
+
+
+static ssize_t da9052_rtc_unmask_irq(struct da9052 *da9052)
+{
+       unsigned char data = 0;
+       ssize_t ret = 0;
+       struct da9052_ssc_msg ssc_msg;
+
+       ssc_msg.addr =  DA9052_IRQMASKA_REG;
+       ssc_msg.data =  0;
+
+       da9052_lock(da9052);
+       ret = da9052->read(da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       data = ret;
+       ssc_msg.data = data &= ~DA9052_IRQMASKA_MALRAM;
+
+       ret = da9052->write(da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(da9052);
+               return ret;
+       }
+
+       da9052_unlock(da9052);
+       return 0;
+
+}
+
+static int da9052_rtc_class_ops_gettime
+                       (struct device *dev, struct rtc_time *rtc_tm)
+{
+       int ret;
+       struct da9052 *da9052 = dev->parent->driver_data;
+       ret = da9052_rtc_gettime(da9052, rtc_tm);
+       if (ret)
+               return ret;
+       return 0;
+}
+
+
+static int da9052_rtc_class_ops_settime(struct device *dev, struct rtc_time *tm)
+{
+       int ret;
+       struct da9052 *da9052 = dev->parent->driver_data;
+       ret = da9052_rtc_settime(da9052, tm);
+
+       return ret;
+}
+
+static int da9052_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       int ret;
+       struct rtc_time *tm = &alrm->time;
+       struct da9052 *da9052 = dev->parent->driver_data;
+       ret = da9052_alarm_gettime(da9052, tm);
+
+       if (ret)
+               return ret;
+
+       alrm->enabled = da9052_rtc_get_alarm_status(da9052);
+
+       return 0;
+
+}
+
+static int da9052_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       int ret = 0;
+       struct rtc_time *tm = &alrm->time;
+       struct da9052 *da9052 = dev->parent->driver_data;
+
+       ret = da9052_alarm_settime(da9052, tm);
+
+       if (ret)
+               return ret;
+
+       ret = da9052_rtc_enable_alarm(da9052, 1);
+
+       return ret;
+}
+
+static int da9052_rtc_update_irq_enable(struct device *dev,
+               unsigned int enabled)
+{
+       struct da9052_rtc *priv = dev_get_drvdata(dev);
+       int ret = -ENODATA;
+
+       da9052_lock(priv->da9052);
+
+       ret = (enabled ? da9052_rtc_unmask_irq : da9052_rtc_mask_irq)
+                                               (priv->da9052);
+
+       da9052_unlock(priv->da9052);
+
+       return ret;
+}
+
+static int da9052_rtc_alarm_irq_enable(struct device *dev,
+                       unsigned int enabled)
+{
+       struct da9052_rtc *priv = dev_get_drvdata(dev);
+
+       if (enabled)
+               return da9052_rtc_enable_alarm(priv->da9052, enabled);
+       else
+               return da9052_rtc_enable_alarm(priv->da9052, enabled);
+}
+
+static const struct rtc_class_ops da9052_rtc_ops = {
+       .read_time      = da9052_rtc_class_ops_gettime,
+       .set_time       = da9052_rtc_class_ops_settime,
+       .read_alarm     = da9052_rtc_readalarm,
+       .set_alarm      = da9052_rtc_setalarm,
+#if 0
+       .update_irq_enable = da9052_rtc_update_irq_enable,
+       .alarm_irq_enable = da9052_rtc_alarm_irq_enable,
+#endif
+};
+
+
+static int __devinit da9052_rtc_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct da9052_rtc *priv;
+       struct da9052_ssc_msg ssc_msg;
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->da9052 = dev_get_drvdata(pdev->dev.parent);
+       platform_set_drvdata(pdev, priv);
+
+       /* Added to support sysfs wakealarm attribute */
+       pdev->dev.power.can_wakeup = 1;
+       /* Added to support sysfs wakealarm attribute */
+
+       /* Set the EH structure */
+       priv->eh_data.eve_type = ALARM_EVE;
+       priv->eh_data.call_back = &da9052_rtc_notifier;
+       ret = priv->da9052->register_event_notifier(priv->da9052,
+               &priv->eh_data);
+       if (ret)
+               goto err_register_alarm;
+
+       priv->is_min_alarm = 1;
+       priv->enable_tick_alarm = 1;
+       priv->enable_clk_buffer = 1;
+       priv->set_osc_trim_freq = 5;
+       /* Enable/Disable TICK Alarm */
+       /* Read ALARM YEAR register */
+       ssc_msg.addr = DA9052_ALARMY_REG;
+       ssc_msg.data = 0;
+
+       da9052_lock(priv->da9052);
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+
+       if (priv->enable_tick_alarm)
+               ssc_msg.data = (ssc_msg.data | DA9052_ALARMY_TICKON);
+       else
+               ssc_msg.data =
+               ((ssc_msg.data & ~(DA9052_ALARMY_TICKON)));
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+
+       /* Set TICK Alarm to 1 minute or 1 sec */
+       /* Read ALARM MINUTES register */
+       ssc_msg.addr = DA9052_ALARMMI_REG;
+       ssc_msg.data = 0;
+
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+
+       if (priv->is_min_alarm)
+               /* Set 1 minute tick type */
+               ssc_msg.data = (ssc_msg.data | DA9052_ALARMMI_TICKTYPE);
+       else
+               /* Set 1 sec tick type */
+               ssc_msg.data = (ssc_msg.data & ~(DA9052_ALARMMI_TICKTYPE));
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+
+       /* Enable/Disable Clock buffer in Power Down Mode */
+       ssc_msg.addr = DA9052_PDDIS_REG;
+       ssc_msg.data = 0;
+
+       ret = priv->da9052->read(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+
+       if (priv->enable_clk_buffer)
+               ssc_msg.data = (ssc_msg.data | DA9052_PDDIS_OUT32KPD);
+       else
+               ssc_msg.data = (ssc_msg.data & ~(DA9052_PDDIS_OUT32KPD));
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+
+       /* Set clock trim frequency value */
+       ssc_msg.addr = DA9052_OSCTRIM_REG;
+       ssc_msg.data = priv->set_osc_trim_freq;
+
+       ret = priv->da9052->write(priv->da9052, &ssc_msg);
+       if (ret != 0) {
+               da9052_unlock(priv->da9052);
+               goto err_ssc_comm;
+       }
+       da9052_unlock(priv->da9052);
+
+       priv->rtc = rtc_device_register(pdev->name,
+                       &pdev->dev, &da9052_rtc_ops, THIS_MODULE);
+       if (IS_ERR(priv->rtc)) {
+               ret = PTR_ERR(priv->rtc);
+               goto err_ssc_comm;
+       }
+       return 0;
+
+err_ssc_comm:
+               priv->da9052->unregister_event_notifier
+                       (priv->da9052, &priv->eh_data);
+err_register_alarm:
+               platform_set_drvdata(pdev, NULL);
+               kfree(priv);
+
+       return ret;
+}
+
+static int __devexit da9052_rtc_remove(struct platform_device *pdev)
+{
+       struct da9052_rtc *priv = platform_get_drvdata(pdev);
+       rtc_device_unregister(priv->rtc);
+       da9052_lock(priv->da9052);
+       priv->da9052->unregister_event_notifier(priv->da9052, &priv->eh_data);
+       da9052_unlock(priv->da9052);
+       platform_set_drvdata(pdev, NULL);
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver da9052_rtc_driver = {
+       .probe = da9052_rtc_probe,
+       .remove = __devexit_p(da9052_rtc_remove),
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+
+static int __init da9052_rtc_init(void)
+{
+       return platform_driver_register(&da9052_rtc_driver);
+}
+module_init(da9052_rtc_init);
+
+static void __exit da9052_rtc_exit(void)
+{
+       platform_driver_unregister(&da9052_rtc_driver);
+}
+module_exit(da9052_rtc_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi_sam.c b/drivers/spi/spi_sam.c
new file mode 100644 (file)
index 0000000..a67a013
--- /dev/null
@@ -0,0 +1,1161 @@
+/*
+ * spi_sam.c - Samsung SOC SPI controller driver.
+ * By -- Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * Copyright (C) 2009 Samsung Electronics Ltd.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <asm/gpio.h>
+#include <asm/dma.h>
+
+#include "spi_sam.h"
+
+//#define DEBUGSPI
+
+#ifdef DEBUGSPI
+
+#define dbg_printk(x...)       printk(x)
+
+static void dump_regs(struct samspi_bus *sspi)
+{
+       u32 val;
+
+       val = readl(sspi->regs + SAMSPI_CH_CFG);
+       printk("CHN-%x\t", val);
+       val = readl(sspi->regs + SAMSPI_CLK_CFG);
+       printk("CLK-%x\t", val);
+       val = readl(sspi->regs + SAMSPI_MODE_CFG);
+       printk("MOD-%x\t", val);
+       val = readl(sspi->regs + SAMSPI_SLAVE_SEL);
+       printk("SLVSEL-%x\t", val);
+       val = readl(sspi->regs + SAMSPI_SPI_STATUS);
+       if(val & SPI_STUS_TX_DONE)
+          printk("TX_done\t");
+       if(val & SPI_STUS_TRAILCNT_ZERO)
+          printk("TrailZ\t");
+       if(val & SPI_STUS_RX_OVERRUN_ERR)
+          printk("RX_Ovrn\t");
+       if(val & SPI_STUS_RX_UNDERRUN_ERR)
+          printk("Rx_Unrn\t");
+       if(val & SPI_STUS_TX_OVERRUN_ERR)
+          printk("Tx_Ovrn\t");
+       if(val & SPI_STUS_TX_UNDERRUN_ERR)
+          printk("Tx_Unrn\t");
+       if(val & SPI_STUS_RX_FIFORDY)
+          printk("Rx_Rdy\t");
+       if(val & SPI_STUS_TX_FIFORDY)
+          printk("Tx_Rdy\t");
+       printk("Rx/TxLvl=%d,%d\n", (val>>13)&0x7f, (val>>6)&0x7f);
+}
+
+static void dump_spidevice_info(struct spi_device *spi)
+{
+       dbg_printk("Modalias = %s\n", spi->modalias);
+       dbg_printk("Slave-%d on Bus-%d\n", spi->chip_select, spi->master->bus_num);
+       dbg_printk("max_speed_hz = %d\n", spi->max_speed_hz);
+       dbg_printk("bits_per_word = %d\n", spi->bits_per_word);
+       dbg_printk("irq = %d\n", spi->irq);
+       dbg_printk("Clk Phs = %d\n", spi->mode & SPI_CPHA);
+       dbg_printk("Clk Pol = %d\n", spi->mode & SPI_CPOL);
+       dbg_printk("ActiveCS = %s\n", (spi->mode & (1<<2)) ? "high" : "low" );
+       dbg_printk("Our Mode = %s\n", (spi->mode & SPI_SLAVE) ? "Slave" : "Master");
+}
+
+#else
+
+#define dbg_printk(x...)               /**/
+#define dump_regs(sspi)                /**/
+#define dump_spidevice_info(spi)       /**/
+
+#endif
+
+static void dump_spi_regs(struct samspi_bus *sspi)
+{
+       printk(KERN_CRIT "Reg Info \n");
+       printk(KERN_CRIT "CH_CFG      = 0x%8.8x\n", readl(sspi->regs + SAMSPI_CH_CFG));
+       printk(KERN_CRIT "CLK_CFG     = 0x%8.8x\n", readl(sspi->regs + SAMSPI_CLK_CFG));
+       printk(KERN_CRIT "MODE_CFG    = 0x%8.8x\n", readl(sspi->regs + SAMSPI_MODE_CFG));
+       printk(KERN_CRIT "CS_REG      = 0x%8.8x\n", readl(sspi->regs + SAMSPI_SLAVE_SEL));
+       printk(KERN_CRIT "SPI_INT_EN  = 0x%8.8x\n", readl(sspi->regs + SAMSPI_SPI_INT_EN));
+       printk(KERN_CRIT "SPI_STATUS  = 0x%8.8x\n", readl(sspi->regs + SAMSPI_SPI_STATUS));
+//     printk(KERN_CRIT "SAMSPI_SPI_RX_DATA  = 0x%8.8x\n", readl(sspi->regs + SAMSPI_SPI_RX_DATA));
+//     printk(KERN_CRIT "SAMSPI_SPI_TX_DATA  = 0x%8.8x\n", readl(sspi->regs + SAMSPI_SPI_TX_DATA));
+}
+
+static struct s3c2410_dma_client samspi_dma_client = {
+       .name = "samspi-dma",
+};
+
+static int sspi_getclcks(struct samspi_bus *sspi)
+{
+       struct clk *cspi, *cp, *cm, *cf;
+
+       cp = NULL;
+       cm = NULL;
+       cf = NULL;
+       cspi = sspi->clk;
+
+       if(cspi == NULL){
+               cspi = clk_get(&sspi->pdev->dev, "spi");
+               if(IS_ERR(cspi)){
+                       printk("Unable to get spi!\n");
+                       return -EBUSY;
+               }
+       }
+       dbg_printk("%s:%d Got clk=spi\n", __func__, __LINE__);
+
+#if defined(CONFIG_SPICLK_SRC_SCLK48M) || defined(CONFIG_SPICLK_SRC_EPLL) || defined(CONFIG_SPICLK_SRC_SPIEXT)
+       cp = clk_get(&sspi->pdev->dev, spiclk_src);
+       if(IS_ERR(cp)){
+               printk("Unable to get parent clock(%s)!\n", spiclk_src);
+               if(sspi->clk == NULL){
+                       clk_disable(cspi);
+                       clk_put(cspi);
+               }
+               return -EBUSY;
+       }
+       dbg_printk("%s:%d Got clk=%s\n", __func__, __LINE__, spiclk_src);
+
+#if defined(CONFIG_SPICLK_SRC_EPLL) || defined(CONFIG_SPICLK_SRC_SPIEXT)
+       cm = clk_get(&sspi->pdev->dev, spisclk_src);
+       if(IS_ERR(cm)){
+               printk("Unable to get %s\n", spisclk_src);
+               clk_put(cp);
+               return -EBUSY;
+       }
+       dbg_printk("%s:%d Got clk=%s\n", __func__, __LINE__, spisclk_src);
+       if(clk_set_parent(cp, cm)){
+               printk("failed to set %s as the parent of %s\n", spisclk_src, spiclk_src);
+               clk_put(cm);
+               clk_put(cp);
+               return -EBUSY;
+       }
+       dbg_printk("Set %s as the parent of %s\n", spisclk_src, spiclk_src);
+
+#if defined(CONFIG_SPICLK_EPLL_MOUTEPLL) /* MOUTepll through EPLL */
+       cf = clk_get(&sspi->pdev->dev, "fout_epll");
+       if(IS_ERR(cf)){
+               printk("Unable to get fout_epll\n");
+               clk_put(cm);
+               clk_put(cp);
+               return -EBUSY;
+       }
+       dbg_printk("Got fout_epll\n");
+       if(clk_set_parent(cm, cf)){
+               printk("failed to set FOUTepll as parent of %s\n", spisclk_src);
+               clk_put(cf);
+               clk_put(cm);
+               clk_put(cp);
+               return -EBUSY;
+       }
+       dbg_printk("Set FOUTepll as parent of %s\n", spisclk_src);
+       clk_put(cf);
+#endif
+       clk_put(cm);
+#endif
+
+       sspi->prnt_clk = cp;
+#endif
+
+       sspi->clk = cspi;
+       return 0;
+}
+
+static void sspi_putclcks(struct samspi_bus *sspi)
+{
+       if(sspi->prnt_clk != NULL)
+               clk_put(sspi->prnt_clk);
+
+       clk_put(sspi->clk);
+}
+
+static int sspi_enclcks(struct samspi_bus *sspi)
+{
+       if(sspi->prnt_clk != NULL)
+               clk_enable(sspi->prnt_clk);
+
+       return clk_enable(sspi->clk);
+}
+
+static void sspi_disclcks(struct samspi_bus *sspi)
+{
+       if(sspi->prnt_clk != NULL)
+               clk_disable(sspi->prnt_clk);
+
+       clk_disable(sspi->clk);
+}
+
+static unsigned long sspi_getrate(struct samspi_bus *sspi)
+{
+       if(sspi->prnt_clk != NULL)
+               return clk_get_rate(sspi->prnt_clk);
+       else
+               return clk_get_rate(sspi->clk);
+}
+
+static int sspi_setrate(struct samspi_bus *sspi, unsigned long r)
+{
+ /* We don't take charge of the Src Clock, yet */
+       return 0;
+}
+
+static inline void enable_spidma(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       u32 val;
+
+       val = readl(sspi->regs + SAMSPI_MODE_CFG);
+       val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
+       if(xfer->tx_buf != NULL)
+          val |= SPI_MODE_TXDMA_ON;
+       if(xfer->rx_buf != NULL)
+          val |= SPI_MODE_RXDMA_ON;
+       writel(val, sspi->regs + SAMSPI_MODE_CFG);
+}
+
+static inline void flush_dma(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       if(xfer->tx_buf != NULL)
+          s3c2410_dma_ctrl(sspi->tx_dmach, S3C2410_DMAOP_FLUSH);
+       if(xfer->rx_buf != NULL)
+          s3c2410_dma_ctrl(sspi->rx_dmach, S3C2410_DMAOP_FLUSH);
+}
+
+static inline void flush_spi(struct samspi_bus *sspi)
+{
+       u32 val;
+
+       val = readl(sspi->regs + SAMSPI_CH_CFG);
+       val |= SPI_CH_SW_RST;
+       val &= ~SPI_CH_HS_EN;
+       if((sspi->cur_speed > 30000000UL) && !(sspi->cur_mode & SPI_SLAVE)) /* TODO ??? */
+          val |= SPI_CH_HS_EN;
+       writel(val, sspi->regs + SAMSPI_CH_CFG);
+
+       /* Flush TxFIFO*/
+       do{
+          val = readl(sspi->regs + SAMSPI_SPI_STATUS);
+          val = (val>>6) & 0x7f;
+       }while(val);
+
+       /* Flush RxFIFO*/
+       val = readl(sspi->regs + SAMSPI_SPI_STATUS);
+       val = (val>>13) & 0x7f;
+       while(val){
+          readl(sspi->regs + SAMSPI_SPI_RX_DATA);
+          val = readl(sspi->regs + SAMSPI_SPI_STATUS);
+          val = (val>>13) & 0x7f;
+       }
+
+       val = readl(sspi->regs + SAMSPI_CH_CFG);
+       val &= ~SPI_CH_SW_RST;
+       writel(val, sspi->regs + SAMSPI_CH_CFG);
+}
+
+static inline void enable_spichan(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       u32 val;
+
+       //printk(KERN_CRIT "@@@@@@@@ enable_spichan() \n");
+       
+       val = readl(sspi->regs + SAMSPI_CH_CFG);
+       val &= ~(SPI_CH_RXCH_ON | SPI_CH_TXCH_ON);
+       if(xfer->tx_buf != NULL){
+          val |= SPI_CH_TXCH_ON;
+       }
+       if(xfer->rx_buf != NULL){
+          if(!(sspi->cur_mode & SPI_SLAVE)){
+             writel((xfer->len & 0xffff) | SPI_PACKET_CNT_EN, 
+                       sspi->regs + SAMSPI_PACKET_CNT); /* XXX TODO Bytes or number of SPI-Words? */
+          }
+          val |= SPI_CH_RXCH_ON;
+       }
+       writel(val, sspi->regs + SAMSPI_CH_CFG);
+}
+
+static inline void enable_spiintr(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       u32 val = 0;
+
+       if(xfer->tx_buf != NULL){
+          val |= SPI_INT_TX_OVERRUN_EN;
+          if(!(sspi->cur_mode & SPI_SLAVE))
+             val |= SPI_INT_TX_UNDERRUN_EN;
+       }
+       if(xfer->rx_buf != NULL){
+          val |= (SPI_INT_RX_UNDERRUN_EN | SPI_INT_RX_OVERRUN_EN | SPI_INT_TRAILING_EN);
+       }
+       writel(val, sspi->regs + SAMSPI_SPI_INT_EN);
+}
+
+static inline void enable_spienqueue(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       if(xfer->rx_buf != NULL){
+          sspi->rx_done = BUSY;
+          s3c2410_dma_config(sspi->rx_dmach, sspi->cur_bpw/8, 0);
+          s3c2410_dma_enqueue(sspi->rx_dmach, (void *)sspi, xfer->rx_dma, xfer->len);
+       }
+       if(xfer->tx_buf != NULL){
+          sspi->tx_done = BUSY;
+          s3c2410_dma_config(sspi->tx_dmach, sspi->cur_bpw/8, 0);
+          s3c2410_dma_enqueue(sspi->tx_dmach, (void *)sspi, xfer->tx_dma, xfer->len);
+       }
+}
+
+static inline void enable_cs(struct samspi_bus *sspi, struct spi_device *spi)
+{
+       u32 val;
+       struct sam_spi_pdata *spd = (struct sam_spi_pdata *)spi->controller_data;
+
+       val = readl(sspi->regs + SAMSPI_SLAVE_SEL);
+
+       if(sspi->cur_mode & SPI_SLAVE){
+          val |= SPI_SLAVE_AUTO; /* Auto Mode */
+          val |= SPI_SLAVE_SIG_INACT;
+       }else{ /* Master Mode */
+          val &= ~SPI_SLAVE_AUTO; /* Manual Mode */
+          val &= ~SPI_SLAVE_SIG_INACT; /* Activate CS */
+          if(spi->mode & SPI_CS_HIGH){ // spd->cs_act_high){
+             spd->cs_set(spd->cs_pin, CS_HIGH);
+             spd->cs_level = CS_HIGH;
+          }else{
+             spd->cs_set(spd->cs_pin, CS_LOW);
+             spd->cs_level = CS_LOW;
+          }
+       }
+
+       writel(val, sspi->regs + SAMSPI_SLAVE_SEL);
+}
+
+static inline void disable_cs(struct samspi_bus *sspi, struct spi_device *spi)
+{
+       u32 val;
+       struct sam_spi_pdata *spd = (struct sam_spi_pdata *)spi->controller_data;
+
+       if(!(spi->mode & SPI_CS_HIGH) && spd->cs_act_high){
+               dbg_printk("%s:%s:%d Slave supports SPI_CS_HIGH, but not requested by Master!\n", __FILE__, __func__, __LINE__);
+       }
+
+       val = readl(sspi->regs + SAMSPI_SLAVE_SEL);
+
+       if(sspi->cur_mode & SPI_SLAVE){
+          val |= SPI_SLAVE_AUTO; /* Auto Mode */
+       }else{ /* Master Mode */
+          val &= ~SPI_SLAVE_AUTO; /* Manual Mode */
+          val |= SPI_SLAVE_SIG_INACT; /* DeActivate CS */
+          if(spi->mode & SPI_CS_HIGH){ // spd->cs_act_high){
+             spd->cs_set(spd->cs_pin, CS_LOW);
+             spd->cs_level = CS_LOW;
+          }else{
+             spd->cs_set(spd->cs_pin, CS_HIGH);
+             spd->cs_level = CS_HIGH;
+          }
+       }
+
+       writel(val, sspi->regs + SAMSPI_SLAVE_SEL);
+}
+
+static inline void set_polarity(struct samspi_bus *sspi)
+{
+       u32 val;
+
+       val = readl(sspi->regs + SAMSPI_CH_CFG);
+       val &= ~(SPI_CH_SLAVE | SPI_CPOL_L | SPI_CPHA_B);
+       if(sspi->cur_mode & SPI_SLAVE)
+          val |= SPI_CH_SLAVE;
+       if(!(sspi->cur_mode & SPI_CPOL))
+          val |= SPI_CPOL_L;
+       if(sspi->cur_mode & SPI_CPHA)
+          val |= SPI_CPHA_B;
+       writel(val, sspi->regs + SAMSPI_CH_CFG);
+}
+
+static inline void set_clock(struct samspi_bus *sspi)
+{
+       u32 val;
+
+       val = readl(sspi->regs + SAMSPI_CLK_CFG);
+       val &= ~(SPI_CLKSEL_SRCMSK | SPI_ENCLK_ENABLE | 0xff);
+       val |= SPI_CLKSEL_SRC;
+       if(!(sspi->cur_mode & SPI_SLAVE)){
+          val |= ((sspi_getrate(sspi) / sspi->cur_speed / 2 - 1) << 0);        // PCLK and PSR
+          val |= SPI_ENCLK_ENABLE;
+       }
+       writel(val, sspi->regs + SAMSPI_CLK_CFG);
+}
+
+static inline void set_dmachan(struct samspi_bus *sspi)
+{
+       u32 val;
+
+       val = readl(sspi->regs + SAMSPI_MODE_CFG);
+       val &= ~((0x3<<17) | (0x3<<29));
+       if(sspi->cur_bpw == 8){
+          val |= SPI_MODE_CH_TSZ_BYTE;
+          val |= SPI_MODE_BUS_TSZ_BYTE;
+       }else if(sspi->cur_bpw == 16){
+          val |= SPI_MODE_CH_TSZ_HALFWORD;
+          val |= SPI_MODE_BUS_TSZ_HALFWORD;
+       }else if(sspi->cur_bpw == 32){
+          val |= SPI_MODE_CH_TSZ_WORD;
+          val |= SPI_MODE_BUS_TSZ_WORD;
+       }else{
+          printk("Invalid Bits/Word!\n");
+       }
+       val &= ~(SPI_MODE_4BURST | SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
+       writel(val, sspi->regs + SAMSPI_MODE_CFG);
+}
+
+static void config_sspi(struct samspi_bus *sspi)
+{
+       /* Set Polarity and Phase */
+       set_polarity(sspi);
+
+       /* Set Channel & DMA Mode */
+       set_dmachan(sspi);
+}
+
+static void samspi_hwinit(struct samspi_bus *sspi, int channel)
+{
+       unsigned int val;
+
+       writel(SPI_SLAVE_SIG_INACT, sspi->regs + SAMSPI_SLAVE_SEL);
+
+       /* Disable Interrupts */
+       writel(0, sspi->regs + SAMSPI_SPI_INT_EN);
+
+#ifdef CONFIG_CPU_S3C6410
+       writel((readl(S3C64XX_SPC_BASE) & ~(3<<28)) | (3<<28), S3C64XX_SPC_BASE);
+       writel((readl(S3C64XX_SPC_BASE) & ~(3<<18)) | (3<<18), S3C64XX_SPC_BASE);
+#elif defined (CONFIG_CPU_S5P6440)
+       writel((readl(S5P64XX_SPC_BASE) & ~(3<<28)) | (3<<28), S5P64XX_SPC_BASE);
+       writel((readl(S5P64XX_SPC_BASE) & ~(3<<18)) | (3<<18), S5P64XX_SPC_BASE);
+#elif defined (CONFIG_CPU_S5P6440)
+       /* How to control drive strength, if we must? */
+#endif
+
+       writel(SPI_CLKSEL_SRC, sspi->regs + SAMSPI_CLK_CFG);
+       writel(0, sspi->regs + SAMSPI_MODE_CFG);
+       writel(SPI_SLAVE_SIG_INACT, sspi->regs + SAMSPI_SLAVE_SEL);
+       writel(0, sspi->regs + SAMSPI_PACKET_CNT);
+       writel(readl(sspi->regs + SAMSPI_PENDING_CLR), sspi->regs + SAMSPI_PENDING_CLR);
+       writel(SPI_FBCLK_0NS, sspi->regs + SAMSPI_FB_CLK);
+
+       flush_spi(sspi);
+
+       writel(0, sspi->regs + SAMSPI_SWAP_CFG);
+       writel(SPI_FBCLK_9NS, sspi->regs + SAMSPI_FB_CLK);
+
+       val = readl(sspi->regs + SAMSPI_MODE_CFG);
+       val &= ~(SPI_MAX_TRAILCNT << SPI_TRAILCNT_OFF);
+       if(channel == 0)
+          SET_MODECFG(val, 0);
+       else 
+          SET_MODECFG(val, 1);
+       val |= (SPI_TRAILCNT << SPI_TRAILCNT_OFF);
+       writel(val, sspi->regs + SAMSPI_MODE_CFG);
+}
+
+static irqreturn_t samspi_interrupt(int irq, void *dev_id)
+{
+       u32 val;
+       struct samspi_bus *sspi = (struct samspi_bus *)dev_id;
+
+       dump_regs(sspi);
+       val = readl(sspi->regs + SAMSPI_PENDING_CLR);
+       dbg_printk("PENDING=%x\n", val);
+       writel(val, sspi->regs + SAMSPI_PENDING_CLR);
+
+       /* We get interrupted only for bad news */
+       if(sspi->tx_done != PASS){
+               printk(KERN_CRIT "TX FAILED \n");
+          sspi->tx_done = FAIL;
+       }
+       if(sspi->rx_done != PASS){
+               printk(KERN_CRIT "RX FAILED \n");
+          sspi->rx_done = FAIL;
+       }
+       sspi->state = STOPPED;
+       complete(&sspi->xfer_completion);
+
+       return IRQ_HANDLED;
+}
+
+void samspi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, int size, enum s3c2410_dma_buffresult res)
+{      
+       struct samspi_bus *sspi = (struct samspi_bus *)buf_id;
+
+       if(res == S3C2410_RES_OK){
+          sspi->rx_done = PASS;
+          dbg_printk("DmaRx-%d ", size);
+       }else{
+          sspi->rx_done = FAIL;
+          dbg_printk("DmaAbrtRx-%d ", size);
+       }
+
+       if(sspi->tx_done != BUSY && sspi->state != STOPPED) /* If other done and all OK */
+          complete(&sspi->xfer_completion);
+}
+
+void samspi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, int size, enum s3c2410_dma_buffresult res)
+{
+       struct samspi_bus *sspi = (struct samspi_bus *)buf_id;
+
+       if(res == S3C2410_RES_OK){
+          sspi->tx_done = PASS;
+          dbg_printk("DmaTx-%d ", size);
+       }else{
+          sspi->tx_done = FAIL;
+          dbg_printk("DmaAbrtTx-%d ", size);
+       }
+       
+       if(sspi->rx_done != BUSY && sspi->state != STOPPED) /* If other done and all OK */
+          complete(&sspi->xfer_completion);
+}
+
+static int wait_for_txshiftout(struct samspi_bus *sspi, unsigned long t)
+{
+       unsigned long timeout;
+
+       timeout = jiffies + t;
+       while((__raw_readl(sspi->regs + SAMSPI_SPI_STATUS) >> 6) & 0x7f){
+          if(time_after(jiffies, timeout))
+             return -1;
+          cpu_relax();
+       }
+       return 0;
+}
+
+static int wait_for_xfer(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       int status;
+       u32 val;
+
+       val = msecs_to_jiffies(xfer->len / (sspi->min_speed / 8 / 1000)); /* time to xfer data at min. speed */
+       if(sspi->cur_mode & SPI_SLAVE)
+          val += msecs_to_jiffies(5000); /* 5secs to switch on the Master */
+       else
+          val += msecs_to_jiffies(10); /* just some more */
+       status = wait_for_completion_interruptible_timeout(&sspi->xfer_completion, val);
+
+       //printk(KERN_CRIT "Return from waitforcompletion = %d \n", status);
+       
+       if(status == 0)
+          status = -ETIMEDOUT;
+       else if(status == -ERESTARTSYS)
+          status = -EINTR;
+       else if((sspi->tx_done != PASS) || (sspi->rx_done != PASS)) /* Some Xfer failed */
+          status = -EIO;
+       else
+          status = 0;  /* All OK */
+
+       /* When TxLen <= SPI-FifoLen in Slave mode, DMA returns naively */
+       if(!status && (sspi->cur_mode & SPI_SLAVE) && (xfer->tx_buf != NULL)){
+          val = msecs_to_jiffies(xfer->len / (sspi->min_speed / 8 / 1000)); /* Be lenient */
+          val += msecs_to_jiffies(5000); /* 5secs to switch on the Master */
+          status = wait_for_txshiftout(sspi, val);
+          if(status == -1)
+             status = -ETIMEDOUT;
+          else
+             status = 0;
+       }
+
+       return status;
+}
+
+#define INVALID_DMA_ADDRESS    0xffffffff
+/*  First, try to map buf onto phys addr as such.
+ *   If xfer->r/tx_buf was not on contiguous memory,
+ *   allocate from our preallocated DMA buffer.
+ */
+static int samspi_map_xfer(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       struct device *dev = &sspi->pdev->dev;
+
+       sspi->rx_tmp = NULL;
+       sspi->tx_tmp = NULL;
+
+       xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
+       if(xfer->tx_buf != NULL){
+               xfer->tx_dma = dma_map_single(dev,
+                               (void *) xfer->tx_buf, xfer->len,
+                               DMA_TO_DEVICE);
+               if(dma_mapping_error(dev, xfer->tx_dma))
+                       goto alloc_from_buffer;
+       }
+       if(xfer->rx_buf != NULL){
+               xfer->rx_dma = dma_map_single(dev,
+                               xfer->rx_buf, xfer->len,
+                               DMA_FROM_DEVICE);
+               if(dma_mapping_error(dev, xfer->rx_dma)){
+                       if(xfer->tx_buf)
+                               dma_unmap_single(dev,
+                                               xfer->tx_dma, xfer->len,
+                                               DMA_TO_DEVICE);
+                       goto alloc_from_buffer;
+               }
+       }
+       return 0;
+
+alloc_from_buffer: /* If the xfer->[r/t]x_buf was not on contiguous memory */
+
+       printk(KERN_CRIT "############ Allocating from buffer...\n");
+               
+       if(xfer->len <= SAMSPI_DMABUF_LEN){
+          if(xfer->rx_buf != NULL){
+             xfer->rx_dma = sspi->rx_dma_phys;
+             sspi->rx_tmp = (void *)sspi->rx_dma_cpu;
+          }
+          if(xfer->tx_buf != NULL){
+             xfer->tx_dma = sspi->tx_dma_phys;
+             sspi->tx_tmp = (void *)sspi->tx_dma_cpu;
+          }
+       }else{
+          dbg_printk("If you plan to use this Xfer size often, increase SAMSPI_DMABUF_LEN\n");
+          if(xfer->rx_buf != NULL){
+             sspi->rx_tmp = dma_alloc_coherent(&sspi->pdev->dev, SAMSPI_DMABUF_LEN, 
+                                                       &xfer->rx_dma, GFP_KERNEL | GFP_DMA);
+               if(sspi->rx_tmp == NULL)
+                  return -ENOMEM;
+          }
+          if(xfer->tx_buf != NULL){
+             sspi->tx_tmp = dma_alloc_coherent(&sspi->pdev->dev, 
+                                               SAMSPI_DMABUF_LEN, &xfer->tx_dma, GFP_KERNEL | GFP_DMA);
+               if(sspi->tx_tmp == NULL){
+                  if(xfer->rx_buf != NULL)
+                     dma_free_coherent(&sspi->pdev->dev, 
+                                               SAMSPI_DMABUF_LEN, sspi->rx_tmp, xfer->rx_dma);
+                  return -ENOMEM;
+               }
+          }
+       }
+
+       if(xfer->tx_buf != NULL)
+          memcpy(sspi->tx_tmp, xfer->tx_buf, xfer->len);
+
+       return 0;
+}
+
+static void samspi_unmap_xfer(struct samspi_bus *sspi, struct spi_transfer *xfer)
+{
+       if((sspi->rx_tmp == NULL) && (sspi->tx_tmp == NULL)) /* if map_single'd */
+          return;
+       
+       if((xfer->rx_buf != NULL) && (sspi->rx_tmp != NULL))
+          memcpy(xfer->rx_buf, sspi->rx_tmp, xfer->len);
+
+       if(xfer->len > SAMSPI_DMABUF_LEN){
+          if(xfer->rx_buf != NULL)
+             dma_free_coherent(&sspi->pdev->dev, SAMSPI_DMABUF_LEN, sspi->rx_tmp, xfer->rx_dma);
+          if(xfer->tx_buf != NULL)
+             dma_free_coherent(&sspi->pdev->dev, SAMSPI_DMABUF_LEN, sspi->tx_tmp, xfer->tx_dma);
+       }else{
+          sspi->rx_tmp = NULL;
+          sspi->tx_tmp = NULL;
+       }
+}
+
+static void handle_msg(struct samspi_bus *sspi, struct spi_message *msg)
+{
+       u8 bpw;
+       u32 speed, val;
+       int status = 0;
+       struct spi_transfer *xfer;
+       struct spi_device *spi = msg->spi;
+
+       config_sspi(sspi);
+
+       list_for_each_entry (xfer, &msg->transfers, transfer_list) {
+
+               if(!msg->is_dma_mapped && samspi_map_xfer(sspi, xfer)){
+                  dev_err(&spi->dev, "Xfer: Unable to allocate DMA buffer!\n");
+                  status = -ENOMEM;
+                  goto out;
+               }
+
+               INIT_COMPLETION(sspi->xfer_completion);
+
+               /* Only BPW and Speed may change across transfers */
+               bpw = xfer->bits_per_word ? : spi->bits_per_word;
+               speed = xfer->speed_hz ? : spi->max_speed_hz;
+
+               if(sspi->cur_bpw != bpw || sspi->cur_speed != speed){
+                       sspi->cur_bpw = bpw;
+                       sspi->cur_speed = speed;
+                       config_sspi(sspi);
+               }
+
+               /* Pending only which is to be done */
+               sspi->rx_done = PASS;
+               sspi->tx_done = PASS;
+               sspi->state = RUNNING;
+
+               /* Configure Clock */
+               set_clock(sspi);
+
+               /* Enable Interrupts */
+               enable_spiintr(sspi, xfer);
+
+               if(!(sspi->cur_mode & SPI_SLAVE))
+                  flush_spi(sspi);
+
+               /* Enqueue data on DMA */
+               enable_spienqueue(sspi, xfer);
+
+               /* Enable DMA */
+               enable_spidma(sspi, xfer);
+
+               /* Enable TX/RX */
+               enable_spichan(sspi, xfer);
+
+               /* Slave Select */
+               enable_cs(sspi, spi);
+               
+               status = wait_for_xfer(sspi, xfer);
+               
+               /**************
+                * Block Here *
+                **************/
+
+               if(status == -ETIMEDOUT){
+                  dev_err(&spi->dev, "Xfer: Timeout!\n");
+                  dump_regs(sspi);
+                  sspi->state = STOPPED;
+                  /* DMA Disable*/
+                  val = readl(sspi->regs + SAMSPI_MODE_CFG);
+                  val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
+                  writel(val, sspi->regs + SAMSPI_MODE_CFG);
+                  flush_dma(sspi, xfer);
+                  flush_spi(sspi);
+                  if(!msg->is_dma_mapped)
+                     samspi_unmap_xfer(sspi, xfer);
+                  goto out;
+               }
+               if(status == -EINTR){
+                  dev_err(&spi->dev, "Xfer: Interrupted!\n");
+                  dump_regs(sspi);
+                  sspi->state = STOPPED;
+                  /* DMA Disable*/
+                  val = readl(sspi->regs + SAMSPI_MODE_CFG);
+                  val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
+                  writel(val, sspi->regs + SAMSPI_MODE_CFG);
+                  flush_dma(sspi, xfer);
+                  flush_spi(sspi);
+                  if(!msg->is_dma_mapped)
+                     samspi_unmap_xfer(sspi, xfer);
+                  goto out;
+               }
+               if(status == -EIO){ /* Some Xfer failed */
+                  dev_err(&spi->dev, "Xfer: Failed!\n");
+                  dump_regs(sspi);
+                  sspi->state = STOPPED;
+                  /* DMA Disable*/
+                  val = readl(sspi->regs + SAMSPI_MODE_CFG);
+                  val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
+                  writel(val, sspi->regs + SAMSPI_MODE_CFG);
+                  flush_dma(sspi, xfer);
+                  flush_spi(sspi);
+                  if(!msg->is_dma_mapped)
+                     samspi_unmap_xfer(sspi, xfer);
+                  goto out;
+               }
+
+               if(xfer->delay_usecs){
+                  udelay(xfer->delay_usecs);
+                  dbg_printk("%s:%s:%d Unverified Control Flow Path!\n", __FILE__, __func__, __LINE__);
+               }
+
+               if(xfer->cs_change && !(sspi->cur_mode & SPI_SLAVE)){
+                  disable_cs(sspi, spi);
+                  dbg_printk("%s:%s:%d Unverified Control Flow Path!\n", __FILE__, __func__, __LINE__);
+               }
+
+               msg->actual_length += xfer->len;
+
+               if(!msg->is_dma_mapped)
+                  samspi_unmap_xfer(sspi, xfer);
+               
+       }
+
+out:
+       /* Slave Deselect */
+       if(!(sspi->cur_mode & SPI_SLAVE))
+          disable_cs(sspi, spi);
+
+       /* Disable Interrupts */
+       writel(0, sspi->regs + SAMSPI_SPI_INT_EN);
+
+       /* Tx/Rx Disable */
+       val = readl(sspi->regs + SAMSPI_CH_CFG);
+       val &= ~(SPI_CH_RXCH_ON | SPI_CH_TXCH_ON);
+       writel(val, sspi->regs + SAMSPI_CH_CFG);
+
+       /* DMA Disable*/
+       val = readl(sspi->regs + SAMSPI_MODE_CFG);
+       val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
+       writel(val, sspi->regs + SAMSPI_MODE_CFG);
+
+       msg->status = status;
+       if(msg->complete)
+          msg->complete(msg->context);
+}
+
+static void samspi_work(struct work_struct *work)
+{
+       struct samspi_bus *sspi = container_of(work, struct samspi_bus, work);
+       unsigned long flags;
+
+       spin_lock_irqsave(&sspi->lock, flags);
+       while (!list_empty(&sspi->queue)) {
+               struct spi_message *msg;
+
+               msg = container_of(sspi->queue.next, struct spi_message, queue);
+               list_del_init(&msg->queue);
+               spin_unlock_irqrestore(&sspi->lock, flags);
+
+               handle_msg(sspi, msg);
+
+               spin_lock_irqsave(&sspi->lock, flags);
+       }
+       spin_unlock_irqrestore(&sspi->lock, flags);
+}
+
+static void samspi_cleanup(struct spi_device *spi)
+{
+       dbg_printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
+}
+
+static int samspi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct spi_master *master = spi->master;
+       struct samspi_bus *sspi = spi_master_get_devdata(master);
+       unsigned long flags;
+       
+       spin_lock_irqsave(&sspi->lock, flags);
+       msg->actual_length = 0;
+       list_add_tail(&msg->queue, &sspi->queue);
+       queue_work(sspi->workqueue, &sspi->work);
+       spin_unlock_irqrestore(&sspi->lock, flags);
+       
+       return 0;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS       (SPI_CPOL | SPI_CPHA | SPI_SLAVE | (spd->cs_act_high ? SPI_CS_HIGH : 0) )
+/*
+ * Here we only check the validity of requested configuration and 
+ * save the configuration in a local data-structure.
+ * The controller is actually configured only just before
+ * we get a message to transfer _and_ if no other message is pending(already configured).
+ */
+static int samspi_setup(struct spi_device *spi)
+{
+       unsigned long flags;
+       unsigned int psr;
+       struct samspi_bus *sspi = spi_master_get_devdata(spi->master);
+       struct sam_spi_pdata *spd = (struct sam_spi_pdata *)spi->controller_data;
+
+       spin_lock_irqsave(&sspi->lock, flags);
+       if(!list_empty(&sspi->queue)){  /* Any pending message? */
+               spin_unlock_irqrestore(&sspi->lock, flags);
+               dev_dbg(&spi->dev, "setup: attempt while messages in queue!\n");
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&sspi->lock, flags);
+
+       if (spi->chip_select > spi->master->num_chipselect) {
+               dev_dbg(&spi->dev, "setup: invalid chipselect %u (%u defined)\n",
+                               spi->chip_select, spi->master->num_chipselect);
+               return -EINVAL;
+       }
+
+       spi->bits_per_word = spi->bits_per_word ? : 8;
+
+       if((spi->bits_per_word != 8) && 
+                       (spi->bits_per_word != 16) && 
+                       (spi->bits_per_word != 32)){
+               dev_err(&spi->dev, "setup: %dbits/wrd not supported!\n", spi->bits_per_word);
+               return -EINVAL;
+       }
+
+       spi->max_speed_hz = spi->max_speed_hz ? : sspi->max_speed;
+
+       /* Round-off max_speed_hz */
+       psr = sspi_getrate(sspi) / spi->max_speed_hz / 2 - 1;
+       psr &= 0xff;
+       if(spi->max_speed_hz < sspi_getrate(sspi) / 2 / (psr + 1))
+          psr = (psr+1) & 0xff;
+
+       spi->max_speed_hz = sspi_getrate(sspi) / 2 / (psr + 1);
+
+       if (spi->max_speed_hz > sspi->max_speed
+                       || spi->max_speed_hz < sspi->min_speed){
+               dev_err(&spi->dev, "setup: req speed(%u) out of range[%u-%u]\n", 
+                               spi->max_speed_hz, sspi->min_speed, sspi->max_speed);
+               return -EINVAL;
+       }
+
+       if (spi->mode & ~MODEBITS) {
+               dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", spi->mode & ~MODEBITS);
+               return -EINVAL;
+       }
+
+       if(!(spi->mode & SPI_SLAVE) && (spd->cs_level == CS_FLOAT)){
+          spd->cs_config(spd->cs_pin, spd->cs_mode, (spi->mode & SPI_CS_HIGH)/*spd->cs_act_high*/ ? CS_LOW : CS_HIGH);
+          disable_cs(sspi, spi);
+       }
+
+       if((sspi->cur_bpw == spi->bits_per_word) && 
+               (sspi->cur_speed == spi->max_speed_hz) && 
+               (sspi->cur_mode == spi->mode)) /* If no change in configuration, do nothing */
+           return 0;
+
+       sspi->cur_bpw = spi->bits_per_word;
+       sspi->cur_speed = spi->max_speed_hz;
+       sspi->cur_mode = spi->mode;
+
+       SAM_SETGPIOPULL(sspi);
+       return 0;
+}
+
+static int __init samspi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct samspi_bus *sspi;
+       int ret = -ENODEV;
+
+       dbg_printk("%s:%s:%d ID=%d\n", __FILE__, __func__, __LINE__, pdev->id);
+       master = spi_alloc_master(&pdev->dev, sizeof(struct samspi_bus)); /* Allocate contiguous SPI controller */
+       if (master == NULL)
+               return ret;
+       sspi = spi_master_get_devdata(master);
+       sspi->pdev = pdev;
+       sspi->spi_mstinfo = (struct sam_spi_mstr_info *)pdev->dev.platform_data;
+       sspi->master = master;
+       platform_set_drvdata(pdev, master);
+
+       INIT_WORK(&sspi->work, samspi_work);
+       spin_lock_init(&sspi->lock);
+       INIT_LIST_HEAD(&sspi->queue);
+       init_completion(&sspi->xfer_completion);
+
+       ret = sspi_getclcks(sspi);
+       if(ret){
+               dev_err(&pdev->dev, "cannot acquire clock \n");
+               ret = -EBUSY;
+               goto lb1;
+       }
+       ret = sspi_enclcks(sspi);
+       if(ret){
+               dev_err(&pdev->dev, "cannot enable clock \n");
+               ret = -EBUSY;
+               goto lb2;
+       }
+
+       sspi->max_speed = sspi_getrate(sspi) / 2 / (0x0 + 1);
+       sspi->min_speed = sspi_getrate(sspi) / 2 / (0xff + 1);
+
+       sspi->cur_bpw = 8;
+       sspi->cur_mode = SPI_SLAVE; /* Start in Slave mode */
+       sspi->cur_speed = sspi->min_speed;
+
+       /* Get and Map Resources */
+       sspi->iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (sspi->iores == NULL) {
+               dev_err(&pdev->dev, "cannot find IO resource\n");
+               ret = -ENOENT;
+               goto lb3;
+       }
+
+       sspi->ioarea = request_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1, pdev->name);
+       if (sspi->ioarea == NULL) {
+               dev_err(&pdev->dev, "cannot request IO\n");
+               ret = -ENXIO;
+               goto lb4;
+       }
+
+       sspi->regs = ioremap(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
+       if (sspi->regs == NULL) {
+               dev_err(&pdev->dev, "cannot map IO\n");
+               ret = -ENXIO;
+               goto lb5;
+       }
+
+       sspi->tx_dma_cpu = dma_alloc_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, &sspi->tx_dma_phys, GFP_KERNEL | GFP_DMA);
+       if(sspi->tx_dma_cpu == NULL){
+               dev_err(&pdev->dev, "Unable to allocate TX DMA buffers\n");
+               ret = -ENOMEM;
+               goto lb6;
+       }
+
+       sspi->rx_dma_cpu = dma_alloc_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, &sspi->rx_dma_phys, GFP_KERNEL | GFP_DMA);
+       if(sspi->rx_dma_cpu == NULL){
+               dev_err(&pdev->dev, "Unable to allocate RX DMA buffers\n");
+               ret = -ENOMEM;
+               goto lb7;
+       }
+
+       sspi->irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if(sspi->irqres == NULL){
+               dev_err(&pdev->dev, "cannot find IRQ\n");
+               ret = -ENOENT;
+               goto lb8;
+       }
+
+       ret = request_irq(sspi->irqres->start, samspi_interrupt, IRQF_DISABLED,
+                       pdev->name, sspi);
+       if(ret){
+               dev_err(&pdev->dev, "cannot acquire IRQ\n");
+               ret = -EBUSY;
+               goto lb9;
+       }
+
+       sspi->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
+       if(!sspi->workqueue){
+               dev_err(&pdev->dev, "cannot create workqueue\n");
+               ret = -EBUSY;
+               goto lb10;
+       }
+
+       master->bus_num = pdev->id;
+       master->setup = samspi_setup;
+       master->transfer = samspi_transfer;
+       master->cleanup = samspi_cleanup;
+       master->num_chipselect = sspi->spi_mstinfo->num_slaves;
+
+       if(spi_register_master(master)){
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               ret = -EBUSY;
+               goto lb11;
+       }
+
+       /* Configure GPIOs */
+       if(pdev->id == 0)
+               SETUP_SPI(sspi, 0);
+       else if(pdev->id == 1)
+               SETUP_SPI(sspi, 1);
+       SAM_SETGPIOPULL(sspi);
+
+       if(s3c2410_dma_request(sspi->rx_dmach, &samspi_dma_client, NULL)){
+               dev_err(&pdev->dev, "cannot get RxDMA\n");
+               ret = -EBUSY;
+               goto lb12;
+       }
+       s3c2410_dma_set_buffdone_fn(sspi->rx_dmach, samspi_dma_rxcb);
+       s3c2410_dma_devconfig(sspi->rx_dmach, S3C2410_DMASRC_HW, 0, sspi->sfr_phyaddr + SAMSPI_SPI_RX_DATA);
+       s3c2410_dma_config(sspi->rx_dmach, sspi->cur_bpw/8, 0);
+       s3c2410_dma_setflags(sspi->rx_dmach, S3C2410_DMAF_AUTOSTART);
+
+       if(s3c2410_dma_request(sspi->tx_dmach, &samspi_dma_client, NULL)){
+               dev_err(&pdev->dev, "cannot get TxDMA\n");
+               ret = -EBUSY;
+               goto lb13;
+       }
+       s3c2410_dma_set_buffdone_fn(sspi->tx_dmach, samspi_dma_txcb);
+       s3c2410_dma_devconfig(sspi->tx_dmach, S3C2410_DMASRC_MEM, 0, sspi->sfr_phyaddr + SAMSPI_SPI_TX_DATA);
+       s3c2410_dma_config(sspi->tx_dmach, sspi->cur_bpw/8, 0);
+       s3c2410_dma_setflags(sspi->tx_dmach, S3C2410_DMAF_AUTOSTART);
+
+       /* Setup Deufult Mode */
+       samspi_hwinit(sspi, pdev->id);
+
+       printk("Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n", pdev->id, master->num_chipselect);
+       printk("\tMax,Min-Speed [%d, %d]Hz\n", sspi->max_speed, sspi->min_speed);
+       printk("\tIrq=%d\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
+                       sspi->irqres->start,
+                       sspi->iores->end, sspi->iores->start,
+                       sspi->rx_dmach, sspi->tx_dmach);
+               
+       return 0;       
+       
+lb13:
+       s3c2410_dma_free(sspi->rx_dmach, &samspi_dma_client);
+lb12:
+       spi_unregister_master(master);
+lb11:
+       destroy_workqueue(sspi->workqueue);
+lb10:
+       free_irq(sspi->irqres->start, sspi);
+lb9:
+lb8:
+       dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->rx_dma_cpu, sspi->rx_dma_phys);
+lb7:
+       dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->tx_dma_cpu, sspi->tx_dma_phys);
+lb6:
+       iounmap((void *) sspi->regs);
+lb5:
+       release_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
+lb4:
+lb3:
+       sspi_disclcks(sspi);
+lb2:
+       sspi_putclcks(sspi);
+lb1:
+       platform_set_drvdata(pdev, NULL);
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int __exit samspi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+       struct samspi_bus *sspi = spi_master_get_devdata(master);
+
+       s3c2410_dma_free(sspi->tx_dmach, &samspi_dma_client);
+       s3c2410_dma_free(sspi->rx_dmach, &samspi_dma_client);
+       spi_unregister_master(master);
+       destroy_workqueue(sspi->workqueue);
+       free_irq(sspi->irqres->start, sspi);
+       dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->rx_dma_cpu, sspi->rx_dma_phys);
+       dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->tx_dma_cpu, sspi->tx_dma_phys);
+       iounmap((void *) sspi->regs);
+       release_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
+       sspi_disclcks(sspi);
+       sspi_putclcks(sspi);
+       platform_set_drvdata(pdev, NULL);
+       spi_master_put(master);
+
+       return 0;
+}
+
+static struct platform_driver sam_spi_driver = {
+       .driver = {
+               .name   = "sam-spi",
+               .owner = THIS_MODULE,
+               .bus    = &platform_bus_type,
+       },
+//     .remove = sam_spi_remove,
+//     .shutdown = sam_spi_shutdown,
+//     .suspend = sam_spi_suspend,
+//     .resume = sam_spi_resume,
+};
+
+static int __init sam_spi_init(void)
+{
+       dbg_printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
+       return platform_driver_probe(&sam_spi_driver, samspi_probe);
+}
+//module_init(sam_spi_init);
+subsys_initcall(sam_spi_init);
+
+static void __exit sam_spi_exit(void)
+{
+       platform_driver_unregister(&sam_spi_driver);
+}
+module_exit(sam_spi_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaswinder Singh Brar <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("Samsung SOC SPI Controller");
diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c
new file mode 100644 (file)
index 0000000..060cd89
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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.
+ *
+ * da9052_bl.c: Backlight driver for DA9052
+ */
+
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <linux/delay.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/bl.h>
+
+
+#define DRIVER_NAME            "da9052-backlight"
+#define DRIVER_NAME1           "WLED-1"
+#define DRIVER_NAME2           "WLED-2"
+#define DRIVER_NAME3           "WLED-3"
+
+/* These flags define if Backlight LEDs are present */
+/* Set the following macros to 1, if LEDs are present. Otherwise set to 0 */
+#define DA9052_LED1_PRESENT    1
+#define DA9052_LED2_PRESENT    1
+#define DA9052_LED3_PRESENT    1
+
+#define DA9052_MAX_BRIGHTNESS  0xFF
+
+struct da9052_backlight_data {
+       struct device *da9052_dev;
+       int current_brightness;
+       struct da9052 *da9052;
+
+       int is_led1_present;
+       int is_led2_present;
+       int is_led3_present;
+};
+
+enum da9052_led_number {
+       LED1 = 1,
+       LED2,
+       LED3,
+};
+
+static int da9052_backlight_brightness_set(struct da9052_backlight_data *data,
+                       int brightness, enum da9052_led_number led)
+{
+       /*
+        * Mechanism for brightness control:
+        * For brightness control, current is used.
+        * PWM feature is not used.
+        * To use PWM feature, a fixed value of current should be defined.
+        */
+
+       int ret = 0;
+       unsigned int led_ramp_bit;
+       unsigned int led_current_register;
+       unsigned int led_current_sink_bit;
+       unsigned int led_boost_en_bit;
+       struct da9052_ssc_msg msg;
+
+       switch (led) {
+       case LED1:
+               led_ramp_bit = DA9052_LEDCONT_LED1RAMP;
+               led_current_register = DA9052_LED1CONF_REG;
+               led_current_sink_bit = DA9052_LEDCONT_LED1EN;
+               led_boost_en_bit = DA9052_BOOST_LED1INEN;
+       break;
+       case LED2:
+               led_ramp_bit = DA9052_LEDCONT_LED2RAMP;
+               led_current_register = DA9052_LED2CONF_REG;
+               led_current_sink_bit = DA9052_LEDCONT_LED2EN;
+               led_boost_en_bit = DA9052_BOOST_LED2INEN;
+       break;
+       case LED3:
+               led_ramp_bit = DA9052_LEDCONT_LED3RAMP;
+               led_current_register = DA9052_LED3CONF_REG;
+               led_current_sink_bit = DA9052_LEDCONT_LED3EN;
+               led_boost_en_bit = DA9052_BOOST_LED3INEN;
+       break;
+       default:
+               return -EIO;
+       }
+
+       /*
+               1. Configure the boost register
+               2. Configure the LED _CONT register
+               3. Configure the LEDx_CONF registers to the brightness value.
+       */
+       msg.addr = DA9052_BOOST_REG;
+       msg.data = 0x3F;
+       if (brightness) {
+               da9052_lock(data->da9052);
+               ret = data->da9052->write(data->da9052, &msg);
+               if (ret) {
+                       da9052_unlock(data->da9052);
+                       return ret;
+               }
+               da9052_unlock(data->da9052);
+       }
+
+       msg.addr = DA9052_LEDCONT_REG;
+       msg.data = 0xFF;
+       if (brightness) {
+               da9052_lock(data->da9052);
+               ret = data->da9052->write(data->da9052, &msg);
+               if (ret) {
+                       da9052_unlock(data->da9052);
+                       return ret;
+               }
+               da9052_unlock(data->da9052);
+       }
+
+       msg.addr = led_current_register;
+       msg.data = 0;
+       /* Write to the DA9052 register */
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+       msleep(20);
+       msg.data = brightness;
+       /* Write to the DA9052 register */
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+
+       return 0;
+}
+
+static int da9052_backlight_set(struct backlight_device *bl, int brightness)
+{
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret = 0;
+       /* Check for LED1 */
+       if (1 == data->is_led1_present) {
+               ret = da9052_backlight_brightness_set(data, brightness, LED1);
+               if (ret)
+                       return ret;
+       }
+       /* Check for LED2 */
+       if (1 == data->is_led2_present) {
+               ret = da9052_backlight_brightness_set(data, brightness, LED2);
+               if (ret)
+                       return ret;
+       }
+       /* Check for LED3 */
+       if (1 == data->is_led3_present) {
+               ret = da9052_backlight_brightness_set(data, brightness, LED3);
+               if (ret)
+                       return ret;
+       }
+
+       data->current_brightness = brightness;
+       return 0;
+}
+
+static int da9052_init_WLED(struct da9052_backlight_data *data,
+                       enum da9052_led_number led)
+{
+       int ret = 0;
+       unsigned int led_current_register;
+       struct da9052_ssc_msg msg;
+
+       switch (led) {
+       case LED1:
+               led_current_register = DA9052_LED1CONF_REG;
+       break;
+       case LED2:
+               led_current_register = DA9052_LED2CONF_REG;
+       break;
+       case LED3:
+               led_current_register = DA9052_LED3CONF_REG;
+       break;
+       default:
+               return -EIO;
+       }
+
+       msg.addr = DA9052_BOOST_REG;
+       msg.data = 0x00;
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+
+       msg.addr = DA9052_LEDCONT_REG;
+       msg.data = 0x00;
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       if (ret) {
+               da9052_unlock(data->da9052);
+               return ret;
+       }
+       da9052_unlock(data->da9052);
+
+       msg.addr = led_current_register;
+       msg.data = 0;
+       da9052_lock(data->da9052);
+       ret = data->da9052->write(data->da9052, &msg);
+       da9052_unlock(data->da9052);
+       return ret;
+}
+
+static int da9052_backlight_update_status(struct backlight_device *bl)
+{
+       int brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+               brightness = 0;
+       return da9052_backlight_set(bl, brightness);
+}
+
+static int da9052_backlight_get_brightness(struct backlight_device *bl)
+{
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       return data->current_brightness;
+}
+
+struct backlight_ops da9052_backlight_ops = {
+       .update_status  = da9052_backlight_update_status,
+       .get_brightness = da9052_backlight_get_brightness,
+};
+
+static int da9052_backlight_probe1(struct platform_device *pdev)
+{
+       struct da9052_backlight_data *data;
+       struct backlight_device *bl;
+       int ret = 0;
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->da9052_dev = pdev->dev.parent;
+       data->da9052    = da9052;
+       data->current_brightness = 0;
+       data->is_led1_present = DA9052_LED1_PRESENT;
+
+       /* Init the WLED-1 bank */
+       ret = da9052_init_WLED(data, LED1);
+       if (ret)
+               return ret;
+
+       bl = backlight_device_register(pdev->name, data->da9052_dev,
+                       data, &da9052_backlight_ops);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
+               return PTR_ERR(bl);
+       }
+
+       bl->props.max_brightness = DA9052_MAX_BRIGHTNESS;
+       bl->props.brightness = 0;
+
+       platform_set_drvdata(pdev, bl);
+       backlight_update_status(bl);
+
+       return 0;
+}
+static int da9052_backlight_probe2(struct platform_device *pdev)
+{
+       struct da9052_backlight_data *data;
+       struct backlight_device *bl;
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+       int ret = 0;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->da9052_dev = pdev->dev.parent;
+       data->da9052    = da9052;
+       data->current_brightness = 0;
+       data->is_led2_present = DA9052_LED2_PRESENT;
+
+       /* Init the WLED-2 bank */
+       ret = da9052_init_WLED(data, LED2);
+       if (ret)
+               return ret;
+
+       bl = backlight_device_register(pdev->name, data->da9052_dev,
+                       data, &da9052_backlight_ops);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
+               return PTR_ERR(bl);
+       }
+
+       bl->props.max_brightness = DA9052_MAX_BRIGHTNESS;
+       bl->props.brightness = 0;
+
+       platform_set_drvdata(pdev, bl);
+       backlight_update_status(bl);
+
+       return 0;
+}
+static int da9052_backlight_probe3(struct platform_device *pdev)
+{
+       struct da9052_backlight_data *data;
+       struct backlight_device *bl;
+       struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
+       int ret = 0;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->da9052_dev = pdev->dev.parent;
+       data->da9052    = da9052;
+       data->current_brightness = 0;
+       data->is_led3_present = DA9052_LED3_PRESENT;
+
+       /* Init the WLED-2 bank */
+       ret = da9052_init_WLED(data, LED3);
+       if (ret)
+               return ret;
+
+       bl = backlight_device_register(pdev->name, data->da9052_dev,
+                       data, &da9052_backlight_ops);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               kfree(data);
+               return PTR_ERR(bl);
+       }
+
+       bl->props.max_brightness = DA9052_MAX_BRIGHTNESS;
+       bl->props.brightness = 0;
+
+       platform_set_drvdata(pdev, bl);
+
+       backlight_update_status(bl);
+       return 0;
+}
+
+static int da9052_backlight_remove1(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret = 0;
+
+       /* Switch off the WLED-1 */
+       ret = da9052_init_WLED(data, LED1);
+       if (ret)
+               return ret;
+
+       backlight_device_unregister(bl);
+       kfree(data);
+       return 0;
+}
+
+static int da9052_backlight_remove2(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret = 0;
+
+       /* Switch off the WLED-2 */
+       ret = da9052_init_WLED(data, LED2);
+       if (ret)
+               return ret;
+
+       backlight_device_unregister(bl);
+       kfree(data);
+       return 0;
+}
+static int da9052_backlight_remove3(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct da9052_backlight_data *data = bl_get_data(bl);
+       int ret;
+
+       /* Switch off the WLED-3 */
+       ret = da9052_init_WLED(data, LED3);
+       if (ret)
+               return ret;
+
+       backlight_device_unregister(bl);
+       kfree(data);
+       return 0;
+}
+
+static struct platform_driver da9052_backlight_driver1 = {
+       .driver         = {
+               .name   = DRIVER_NAME1,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_backlight_probe1,
+       .remove         = da9052_backlight_remove1,
+};
+static struct platform_driver da9052_backlight_driver2 = {
+       .driver         = {
+               .name   = DRIVER_NAME2,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_backlight_probe2,
+       .remove         = da9052_backlight_remove2,
+};
+static struct platform_driver da9052_backlight_driver3 = {
+       .driver         = {
+               .name   = DRIVER_NAME3,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9052_backlight_probe3,
+       .remove         = da9052_backlight_remove3,
+};
+
+static int __init da9052_backlight_init(void)
+{
+       s32 ret;
+       ret = platform_driver_register(&da9052_backlight_driver1);
+       if (ret)
+               return ret;
+       ret = platform_driver_register(&da9052_backlight_driver2);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&da9052_backlight_driver3);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+module_init(da9052_backlight_init);
+
+static void __exit da9052_backlight_exit(void)
+{
+       platform_driver_unregister(&da9052_backlight_driver1);
+       platform_driver_unregister(&da9052_backlight_driver2);
+       platform_driver_unregister(&da9052_backlight_driver3);
+}
+module_exit(da9052_backlight_exit);
+
+MODULE_AUTHOR("Dialog Semiconductor Ltd <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Backlight driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
new file mode 100644 (file)
index 0000000..11e1d75
--- /dev/null
@@ -0,0 +1,542 @@
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/watchdog.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/wdt.h>
+
+#define DRIVER_NAME "da9052-wdt"
+
+#define        DA9052_STROBING_FILTER_ENABLE           0x0001
+#define        DA9052_STROBING_FILTER_DISABLE          0x0002
+#define        DA9052_SET_STROBING_MODE_MANUAL         0x0004
+#define        DA9052_SET_STROBING_MODE_AUTO           0x0008
+
+#define KERNEL_MODULE                          0
+#define ENABLE                                 1
+#define DISABLE                                        0
+
+static u8 sm_strobe_filter_flag = DISABLE;
+static u8 sm_strobe_mode_flag = DA9052_STROBE_MANUAL;
+static u32 sm_mon_interval = DA9052_ADC_TWDMIN_TIME;
+static u8 sm_str_req = DISABLE;
+static u8 da9052_sm_scale = DA9052_WDT_DISABLE;
+module_param(sm_strobe_filter_flag,  byte, 0);
+MODULE_PARM_DESC(sm_strobe_filter_flag,
+               "DA9052 SM driver strobe filter flag default = DISABLE");
+
+module_param(sm_strobe_mode_flag, byte, 0);
+MODULE_PARM_DESC(sm_strobe_mode_flag,
+               "DA9052 SM driver watchdog strobing mode default\
+               = DA9052_STROBE_MANUAL");
+
+module_param(da9052_sm_scale, byte, 0);
+MODULE_PARM_DESC(da9052_sm_scale,
+               "DA9052 SM driver scaling value used to calculate the\
+               time for the strobing  filter default = 0");
+
+module_param(sm_str_req, byte, 0);
+MODULE_PARM_DESC(sm_str_req,
+               "DA9052 SM driver strobe request flag default = DISABLE");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+               "Watchdog cannot be stopped once started (default="
+               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static struct timer_list *monitoring_timer;
+
+struct da9052_wdt {
+       struct platform_device *pdev;
+       struct da9052 *da9052;
+};
+static struct miscdevice da9052_wdt_miscdev;
+static unsigned long da9052_wdt_users;
+static int da9052_wdt_expect_close;
+
+static struct da9052_wdt *get_wdt_da9052(void)
+{
+       /*return dev_get_drvdata(da9052_wdt_miscdev.parent);*/
+       return platform_get_drvdata
+                       (to_platform_device(da9052_wdt_miscdev.parent));
+}
+
+void start_strobing(struct work_struct *work)
+{
+       struct da9052_ssc_msg msg;
+       int ret;
+       struct da9052_wdt *wdt = get_wdt_da9052();
+
+
+       if (NULL == wdt) {
+               mod_timer(monitoring_timer, jiffies + sm_mon_interval);
+               return;
+       }
+       msg.addr = DA9052_CONTROLD_REG;
+       msg.data = 0;
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->read(wdt->da9052, &msg);
+       if (ret) {
+               da9052_unlock(wdt->da9052);
+               return;
+       }
+       da9052_unlock(wdt->da9052);
+
+       msg.data = (msg.data | DA9052_CONTROLD_WATCHDOG);
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->write(wdt->da9052, &msg);
+       if (ret) {
+               da9052_unlock(wdt->da9052);
+               return;
+       }
+       da9052_unlock(wdt->da9052);
+
+       sm_str_req = DISABLE;
+
+       mod_timer(monitoring_timer, jiffies + sm_mon_interval);
+       return;
+}
+
+
+void timer_callback(void)
+{
+       if (((sm_strobe_mode_flag) &&
+               (sm_strobe_mode_flag == DA9052_STROBE_MANUAL)) ||
+               (sm_strobe_mode_flag == DA9052_STROBE_AUTO)) {
+               schedule_work(&strobing_action);
+       } else {
+               if (sm_strobe_mode_flag == DA9052_STROBE_MANUAL) {
+                       mod_timer(monitoring_timer, jiffies +
+                       sm_mon_interval);
+               }
+       }
+}
+
+static int da9052_sm_hw_init(struct da9052_wdt *wdt)
+{
+       /* Create timer structure */
+       monitoring_timer = kzalloc(sizeof(struct timer_list), GFP_KERNEL);
+       if (!monitoring_timer)
+               return -ENOMEM;
+
+       init_timer(monitoring_timer);
+       monitoring_timer->expires = jiffies + sm_mon_interval;
+       monitoring_timer->function = (void *)&timer_callback;
+
+       sm_strobe_filter_flag = DA9052_SM_STROBE_CONF;
+       sm_strobe_mode_flag = DA9052_STROBE_MANUAL;
+
+       return 0;
+}
+
+static int da9052_sm_hw_deinit(struct da9052_wdt *wdt)
+{
+       struct da9052_ssc_msg msg;
+       int ret;
+
+       if (monitoring_timer != NULL)
+               del_timer(monitoring_timer);
+       kfree(monitoring_timer);
+
+       msg.addr = DA9052_CONTROLD_REG;
+       msg.data = 0;
+
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->read(wdt->da9052, &msg);
+       if (ret)
+               goto ssc_err;
+       da9052_unlock(wdt->da9052);
+
+       msg.data = (msg.data & ~(DA9052_CONTROLD_TWDSCALE));
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->write(wdt->da9052, &msg);
+       if (ret)
+               goto ssc_err;
+       da9052_unlock(wdt->da9052);
+
+       return 0;
+ssc_err:
+       da9052_unlock(wdt->da9052);
+       return -EIO;
+}
+
+ s32 da9052_sm_set_strobing_filter(struct da9052_wdt *wdt,
+                               u8 strobing_filter_state)
+ {
+       struct da9052_ssc_msg msg;
+       int ret = 0;
+
+       msg.addr = DA9052_CONTROLD_REG;
+       msg.data = 0;
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->read(wdt->da9052, &msg);
+       if (ret)
+               goto ssc_err;
+       da9052_unlock(wdt->da9052);
+
+       msg.data = (msg.data & DA9052_CONTROLD_TWDSCALE);
+
+       if (strobing_filter_state == ENABLE) {
+               sm_strobe_filter_flag = ENABLE;
+               if (DA9052_WDT_DISABLE == msg.data) {
+                       sm_str_req = DISABLE;
+                       del_timer(monitoring_timer);
+                       return 0;
+               }
+               if (DA9052_SCALE_64X == msg.data)
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X64_WINDOW);
+               else if (DA9052_SCALE_32X == msg.data)
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X32_WINDOW);
+               else if (DA9052_SCALE_16X == msg.data)
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X16_WINDOW);
+               else if (DA9052_SCALE_8X == msg.data)
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X8_WINDOW);
+               else if (DA9052_SCALE_4X == msg.data)
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X4_WINDOW);
+               else if (DA9052_SCALE_2X == msg.data)
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X2_WINDOW);
+               else
+                       sm_mon_interval = msecs_to_jiffies(DA9052_X1_WINDOW);
+
+       } else if (strobing_filter_state == DISABLE) {
+               sm_strobe_filter_flag = DISABLE;
+               sm_mon_interval = msecs_to_jiffies(DA9052_ADC_TWDMIN_TIME);
+               if (DA9052_WDT_DISABLE == msg.data) {
+                       sm_str_req = DISABLE;
+                       del_timer(monitoring_timer);
+                       return 0;
+               }
+       } else {
+               return STROBING_FILTER_ERROR;
+       }
+       mod_timer(monitoring_timer, jiffies + sm_mon_interval);
+
+       return 0;
+ssc_err:
+       da9052_unlock(wdt->da9052);
+       return -EIO;
+}
+
+int da9052_sm_set_strobing_mode(u8 strobing_mode_state)
+{
+       if (strobing_mode_state == DA9052_STROBE_AUTO)
+               sm_strobe_mode_flag = DA9052_STROBE_AUTO;
+       else if (strobing_mode_state == DA9052_STROBE_MANUAL)
+               sm_strobe_mode_flag = DA9052_STROBE_MANUAL;
+       else
+               return STROBING_MODE_ERROR;
+
+               return 0;
+}
+
+int da9052_sm_strobe_wdt(void)
+{
+       sm_str_req = ENABLE;
+       return 0;
+}
+
+ s32 da9052_sm_set_wdt(struct da9052_wdt *wdt, u8 wdt_scaling)
+{
+       struct da9052_ssc_msg msg;
+       int ret = 0;
+
+
+       if (wdt_scaling > DA9052_SCALE_64X)
+               return INVALID_SCALING_VALUE;
+
+       msg.addr = DA9052_CONTROLD_REG;
+       msg.data = 0;
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->read(wdt->da9052, &msg);
+       if (ret)
+               goto ssc_err;
+       da9052_unlock(wdt->da9052);
+
+       if (!((DA9052_WDT_DISABLE == (msg.data & DA9052_CONTROLD_TWDSCALE)) &&
+           (DA9052_WDT_DISABLE == wdt_scaling))) {
+               msg.data = (msg.data & ~(DA9052_CONTROLD_TWDSCALE));
+               msg.addr = DA9052_CONTROLD_REG;
+
+
+               da9052_lock(wdt->da9052);
+               ret = wdt->da9052->write(wdt->da9052, &msg);
+               if (ret)
+                       goto ssc_err;
+               da9052_unlock(wdt->da9052);
+
+               msleep(1);
+               da9052_lock(wdt->da9052);
+               ret = wdt->da9052->read(wdt->da9052, &msg);
+               if (ret)
+                       goto ssc_err;
+               da9052_unlock(wdt->da9052);
+
+
+               msg.data |= wdt_scaling;
+
+               da9052_lock(wdt->da9052);
+               ret = wdt->da9052->write(wdt->da9052, &msg);
+               if (ret)
+                       goto ssc_err;
+               da9052_unlock(wdt->da9052);
+
+               sm_str_req = DISABLE;
+               if (DA9052_WDT_DISABLE == wdt_scaling) {
+                       del_timer(monitoring_timer);
+                       return 0;
+               }
+               if (sm_strobe_filter_flag == ENABLE) {
+                       if (DA9052_SCALE_64X == wdt_scaling) {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X64_WINDOW);
+                       } else if (DA9052_SCALE_32X == wdt_scaling) {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X32_WINDOW);
+                       } else if (DA9052_SCALE_16X == wdt_scaling) {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X16_WINDOW);
+                       } else if (DA9052_SCALE_8X == wdt_scaling) {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X8_WINDOW);
+                       } else if (DA9052_SCALE_4X == wdt_scaling) {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X4_WINDOW);
+                       } else if (DA9052_SCALE_2X == wdt_scaling) {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X2_WINDOW);
+                       } else {
+                               sm_mon_interval =
+                                       msecs_to_jiffies(DA9052_X1_WINDOW);
+                       }
+               } else {
+                       sm_mon_interval = msecs_to_jiffies(
+                                               DA9052_ADC_TWDMIN_TIME);
+               }
+               mod_timer(monitoring_timer, jiffies + sm_mon_interval);
+       }
+
+       return 0;
+ssc_err:
+       da9052_unlock(wdt->da9052);
+       return -EIO;
+}
+
+static int da9052_wdt_open(struct inode *inode, struct file *file)
+{
+       struct da9052_wdt *wdt = get_wdt_da9052();
+       int ret;
+       printk(KERN_INFO"IN WDT OPEN \n");
+
+       if (!wdt) {
+               printk(KERN_INFO"Returning no device\n");
+               return -ENODEV;
+       }
+       printk(KERN_INFO"IN WDT OPEN 1\n");
+
+       if (test_and_set_bit(0, &da9052_wdt_users))
+               return -EBUSY;
+
+       ret = da9052_sm_hw_init(wdt);
+       if (ret != 0) {
+               printk(KERN_ERR "Watchdog hw init failed\n");
+               return ret;
+       }
+
+       return nonseekable_open(inode, file);
+}
+
+static int da9052_wdt_release(struct inode *inode, struct file *file)
+{
+       struct da9052_wdt *wdt = get_wdt_da9052();
+
+       if (da9052_wdt_expect_close == 42)
+               da9052_sm_hw_deinit(wdt);
+       else
+               da9052_sm_strobe_wdt();
+       da9052_wdt_expect_close = 0;
+       clear_bit(0, &da9052_wdt_users);
+       return 0;
+}
+
+static ssize_t da9052_wdt_write(struct file *file,
+                               const char __user *data, size_t count,
+                               loff_t *ppos)
+{
+       size_t i;
+
+       if (count) {
+               if (!nowayout) {
+                       /* In case it was set long ago */
+                       da9052_wdt_expect_close = 0;
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       da9052_wdt_expect_close = 42;
+                       }
+               }
+               da9052_sm_strobe_wdt();
+       }
+       return count;
+}
+
+static struct watchdog_info da9052_wdt_info = {
+       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity       = "DA9052_SM Watchdog",
+};
+
+static long da9052_wdt_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct da9052_wdt *wdt = get_wdt_da9052();
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       unsigned char new_value;
+
+       switch (cmd) {
+
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &da9052_wdt_info,
+                       sizeof(da9052_wdt_info)) ? -EFAULT : 0;
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+       case WDIOC_SETOPTIONS:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+               if (new_value & DA9052_STROBING_FILTER_ENABLE)
+                       da9052_sm_set_strobing_filter(wdt, ENABLE);
+               if (new_value & DA9052_STROBING_FILTER_DISABLE)
+                       da9052_sm_set_strobing_filter(wdt, DISABLE);
+               if (new_value & DA9052_SET_STROBING_MODE_MANUAL)
+                       da9052_sm_set_strobing_mode(DA9052_STROBE_MANUAL);
+               if (new_value & DA9052_SET_STROBING_MODE_AUTO)
+                       da9052_sm_set_strobing_mode(DA9052_STROBE_AUTO);
+               return 0;
+       case WDIOC_KEEPALIVE:
+               if (da9052_sm_strobe_wdt())
+                       return -EFAULT;
+               else
+                       return 0;
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+               da9052_sm_scale = new_value;
+               if (da9052_sm_set_wdt(wdt, da9052_sm_scale))
+                       return -EFAULT;
+       case WDIOC_GETTIMEOUT:
+               return put_user(sm_mon_interval, p);
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static const struct file_operations da9052_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .unlocked_ioctl = da9052_wdt_ioctl,
+       .write          = da9052_wdt_write,
+       .open           = da9052_wdt_open,
+       .release        = da9052_wdt_release,
+};
+
+static struct miscdevice da9052_wdt_miscdev = {
+       .minor          = 255,
+       .name           = "da9052-wdt",
+       .fops           = &da9052_wdt_fops,
+};
+
+static int __devinit da9052_sm_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct da9052_wdt *wdt;
+       struct da9052_ssc_msg msg;
+
+       wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       wdt->da9052 = dev_get_drvdata(pdev->dev.parent);
+       platform_set_drvdata(pdev, wdt);
+
+       msg.addr = DA9052_CONTROLD_REG;
+       msg.data = 0;
+
+       da9052_lock(wdt->da9052);
+       ret = wdt->da9052->read(wdt->da9052, &msg);
+       if (ret) {
+               da9052_unlock(wdt->da9052);
+               goto err_ssc_comm;
+       }
+       printk(KERN_INFO"DA9052 SM probe - 0 \n");
+
+       msg.data = (msg.data & ~(DA9052_CONTROLD_TWDSCALE));
+       ret = wdt->da9052->write(wdt->da9052, &msg);
+       if (ret) {
+               da9052_unlock(wdt->da9052);
+               goto err_ssc_comm;
+       }
+       da9052_unlock(wdt->da9052);
+
+       da9052_wdt_miscdev.parent = &pdev->dev;
+
+       ret = misc_register(&da9052_wdt_miscdev);
+       if (ret != 0) {
+               platform_set_drvdata(pdev, NULL);
+               kfree(wdt);
+               return -EFAULT;
+       }
+       return 0;
+err_ssc_comm:
+       platform_set_drvdata(pdev, NULL);
+       kfree(wdt);
+       return -EIO;
+}
+
+static int __devexit da9052_sm_remove(struct platform_device *dev)
+{
+       misc_deregister(&da9052_wdt_miscdev);
+
+       return 0;
+}
+
+static struct platform_driver da9052_sm_driver = {
+       .probe          = da9052_sm_probe,
+       .remove         = __devexit_p(da9052_sm_remove),
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init da9052_sm_init(void)
+{
+       return platform_driver_register(&da9052_sm_driver);
+}
+module_init(da9052_sm_init);
+
+static void __exit da9052_sm_exit(void)
+{
+       platform_driver_unregister(&da9052_sm_driver);
+}
+module_exit(da9052_sm_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>")
+MODULE_DESCRIPTION("DA9052 SM Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/include/linux/mfd/da9052/adc.h b/include/linux/mfd/da9052/adc.h
new file mode 100644 (file)
index 0000000..49c7d18
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * da9052 ADC module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_ADC_H
+#define __LINUX_MFD_DA9052_ADC_H
+
+#include "gpio.h"
+
+#define DA9052_ADC_DEVICE_NAME                         "da9052_adc"
+
+/* Channel Definations */
+#define DA9052_ADC_VDDOUT                              0
+#define DA9052_ADC_ICH                                 1
+#define DA9052_ADC_TBAT                                        2
+#define DA9052_ADC_VBAT                                        3
+#define DA9052_ADC_ADCIN4                              4
+#define DA9052_ADC_ADCIN5                              5
+#define DA9052_ADC_ADCIN6                              6
+#define DA9052_ADC_TSI                                 7
+#define DA9052_ADC_TJUNC                               8
+#define DA9052_ADC_VBBAT                               9
+
+#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG_ADC)
+#define DA9052_ADC_CONF_ADC4                           1
+#else
+#define DA9052_ADC_CONF_ADC4                           0
+#endif
+#if (DA9052_GPIO_PIN_1 == DA9052_GPIO_CONFIG_ADC)
+#define DA9052_ADC_CONF_ADC5                           1
+#else
+#define DA9052_ADC_CONF_ADC5                           0
+#endif
+#if (DA9052_GPIO_PIN_2 == DA9052_GPIO_CONFIG_ADC)
+#define DA9052_ADC_CONF_ADC6                           1
+#else
+#define DA9052_ADC_CONF_ADC6                           0
+#endif
+
+/* Maximum retry count to check manual conversion over */
+#define DA9052_ADC_MAX_MANCONV_RETRY_COUNT             8
+
+struct da9052_adc_priv {
+       struct da9052 *da9052;
+       struct device *hwmon_dev;
+       struct mutex manconv_lock;
+};
+
+#endif /* __LINUX_MFD_DA9052_ADC_H */
diff --git a/include/linux/mfd/da9052/bat.h b/include/linux/mfd/da9052/bat.h
new file mode 100644 (file)
index 0000000..ac2404f
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * da9052 BAT module declarations.
+  *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_BAT_H
+#define __LINUX_MFD_DA9052_BAT_H
+
+#include <linux/power_supply.h>
+
+/* STATIC CONFIGURATION */
+#define DA9052_LOOK_UP_TABLE_SIZE              68
+#define DA9052_NO_OF_LOOKUP_TABLE              3
+#define DA9052_FILTER_SIZE                     4
+#define DA9052_NUMBER_OF_STORE_CURENT_READING  4
+#define DA9052_BAT_FILTER_HYS                  0
+
+
+static const u16 temperature_lookup_ref
+                       [DA9052_NO_OF_LOOKUP_TABLE] = {10, 25, 40};
+static u32 const vbat_vs_capacity_look_up[DA9052_NO_OF_LOOKUP_TABLE]
+                                       [DA9052_LOOK_UP_TABLE_SIZE][2] = {
+       /* For temperature 10 degree celisus*/
+       {
+       {4082, 100}, {4036, 98},
+       {4020, 96}, {4008, 95},
+       {3997, 93}, {3983, 91},
+       {3964, 90}, {3943, 88},
+       {3926, 87}, {3912, 85},
+       {3900, 84}, {3890, 82},
+       {3881, 80}, {3873, 79},
+       {3865, 77}, {3857, 76},
+       {3848, 74}, {3839, 73},
+       {3829, 71}, {3820, 70},
+       {3811, 68}, {3802, 67},
+       {3794, 65}, {3785, 64},
+       {3778, 62}, {3770, 61},
+       {3763, 59}, {3756, 58},
+       {3750, 56}, {3744, 55},
+       {3738, 53}, {3732, 52},
+       {3727, 50}, {3722, 49},
+       {3717, 47}, {3712, 46},
+       {3708, 44}, {3703, 43},
+       {3700, 41}, {3696, 40},
+       {3693, 38}, {3691, 37},
+       {3688, 35}, {3686, 34},
+       {3683, 32}, {3681, 31},
+       {3678, 29}, {3675, 28},
+       {3672, 26}, {3669, 25},
+       {3665, 23}, {3661, 22},
+       {3656, 21}, {3651, 19},
+       {3645, 18}, {3639, 16},
+       {3631, 15}, {3622, 13},
+       {3611, 12}, {3600, 10},
+       {3587, 9}, {3572, 7},
+       {3548, 6}, {3503, 5},
+       {3420, 3}, {3268, 2},
+       {2992, 1}, {2746, 0}
+       },
+       /* For temperature 25 degree celisus */
+       {
+       {4102, 100}, {4065, 98},
+       {4048, 96}, {4034, 95},
+       {4021, 93}, {4011, 92},
+       {4001, 90}, {3986, 88},
+       {3968, 87}, {3952, 85},
+       {3938, 84}, {3926, 82},
+       {3916, 81}, {3908, 79},
+       {3900, 77}, {3892, 76},
+       {3883, 74}, {3874, 73},
+       {3864, 71}, {3855, 70},
+       {3846, 68}, {3836, 67},
+       {3827, 65}, {3819, 64},
+       {3810, 62}, {3801, 61},
+       {3793, 59}, {3786, 58},
+       {3778, 56}, {3772, 55},
+       {3765, 53}, {3759, 52},
+       {3754, 50}, {3748, 49},
+       {3743, 47}, {3738, 46},
+       {3733, 44}, {3728, 43},
+       {3724, 41}, {3720, 40},
+       {3716, 38}, {3712, 37},
+       {3709, 35}, {3706, 34},
+       {3703, 33}, {3701, 31},
+       {3698, 30}, {3696, 28},
+       {3693, 27}, {3690, 25},
+       {3687, 24}, {3683, 22},
+       {3680, 21}, {3675, 19},
+       {3671, 18}, {3666, 17},
+       {3660, 15}, {3654, 14},
+       {3647, 12}, {3639, 11},
+       {3630, 9}, {3621, 8},
+       {3613, 6}, {3606, 5},
+       {3597, 4}, {3582, 2},
+       {3546, 1}, {2747, 0}
+       },
+       /* For temperature 40 degree celisus*/
+       {
+       {4114, 100}, {4081, 98},
+       {4065, 96}, {4050, 95},
+       {4036, 93}, {4024, 92},
+       {4013, 90}, {4002, 88},
+       {3990, 87}, {3976, 85},
+       {3962, 84}, {3950, 82},
+       {3939, 81}, {3930, 79},
+       {3921, 77}, {3912, 76},
+       {3902, 74}, {3893, 73},
+       {3883, 71}, {3874, 70},
+       {3865, 68}, {3856, 67},
+       {3847, 65}, {3838, 64},
+       {3829, 62}, {3820, 61},
+       {3812, 59}, {3803, 58},
+       {3795, 56}, {3787, 55},
+       {3780, 53}, {3773, 52},
+       {3767, 50}, {3761, 49},
+       {3756, 47}, {3751, 46},
+       {3746, 44}, {3741, 43},
+       {3736, 41}, {3732, 40},
+       {3728, 38}, {3724, 37},
+       {3720, 35}, {3716, 34},
+       {3713, 33}, {3710, 31},
+       {3707, 30}, {3704, 28},
+       {3701, 27}, {3698, 25},
+       {3695, 24}, {3691, 22},
+       {3686, 21}, {3681, 19},
+       {3676, 18}, {3671, 17},
+       {3666, 15}, {3661, 14},
+       {3655, 12}, {3648, 11},
+       {3640, 9}, {3632, 8},
+       {3622, 6}, {3616, 5},
+       {3611, 4}, {3604, 2},
+       {3594, 1}, {2747, 0}
+       }
+};
+
+enum charger_type_enum {
+       DA9052_NOCHARGER = 1,
+       DA9052_USB_HUB,
+       DA9052_USB_CHARGER,
+       DA9052_WALL_CHARGER
+};
+
+struct da9052_bat_event_registration {
+       u8      da9052_event_tbat:1;
+};
+
+struct da9052_bat_hysteresis {
+       u16     bat_volt_arr[3];
+       u16     array_hys_batvoltage[2];
+       u16     upper_limit;
+       u16     lower_limit;
+       u8      index;
+       u8      hys_flag;
+};
+
+struct da9052_charger_device {
+       struct da9052                   *da9052;
+       struct workqueue_struct         *monitor_wqueue;
+       struct delayed_work             monitor_work;
+       struct power_supply             psy;
+       struct da9052_eh_nb             tbat_eh_data;
+       u8                              cal_capacity;
+       u8                              charger_type;
+       u8                              health;
+       u8                              status;
+       u8                              illegal;
+       u16                             technology;
+       u16                             chg_current;
+       u16                             bat_voltage;
+       u16                             bat_capacity_limit_low;
+       u16                             bat_capacity_full;
+       u16                             bat_capacity_limit_high;
+       u16                             bat_volt_cutoff;
+       u16                             bat_with_no_resistor;
+       u16                             bat_temp;
+       u8                              hys_flag;
+       u16                             charger_voltage_drop;
+       u16                             bat_target_voltage;
+       u16                             chg_end_current;
+       u16                             hysteresis_window_size;
+       u16                             chg_hysteresis_const;
+       u16                             hysteresis_reading_interval;
+       u16                             hysteresis_no_of_reading;
+       u16                             vbat_first_valid_detect_iteration;
+};
+       
+
+static inline  u8 bat_temp_reg_to_C(u16 value) { return (55 - value); }
+static inline  u8 bat_mV_to_reg(u16 value) { return (((value-4100)/100)<<4); }
+static inline  u8 bat_drop_mV_to_reg(u16 value)
+               { return (((value-100)/100)<<6); }
+static inline  u16 bat_reg_to_mV(u8 value) { return ((value*100) + 4100); }
+static inline  u16 bat_drop_reg_to_mV(u8 value) { return ((value*100)+100); }
+static inline  u8 vch_thr_mV_to_reg(u16 value) { return ((value-3700)/100); }
+static inline  u8 precharge_mA_to_reg(u8 value) { return ((value/20)<<6); }
+static inline  u8 vddout_mon_mV_to_reg(u16 value)
+               { return (((value-2500)*128)/1000); }
+static inline  u16 vddout_reg_to_mV(u8 value)
+               { return ((value*1000)/128)+2500; }
+static inline  u16 volt_reg_to_mV(u16 value)
+               { return ((value*1000)/512)+2500; }
+static inline  u8 ichg_mA_to_reg(u16 value) { return (value/4); }
+static inline  u16 ichg_reg_to_mA(u8 value) { return ((value*3900)/1000); }
+static inline u8 iset_mA_to_reg(u16 iset_value)
+               {\
+               if ((70 <= iset_value) && (iset_value <= 120)) \
+                       return (iset_value-70)/10; \
+               else if ((400 <= iset_value) && (iset_value <= 700)) \
+                       return ((iset_value-400)/50)+6; \
+               else if ((900 <= iset_value) && (iset_value <= 1300)) \
+                       return ((iset_value-900)/200)+13; else return 0;
+               }
+
+#define DA9052_BAT_DEBUG               0
+
+#define DA9052_BAT_PROFILE             0
+#define SUCCESS                                0
+#define FAILURE                                1
+
+#define TRUE                           1
+#define FALSE                          0
+
+#define set_bits(value, mask)          (value | mask)
+#define clear_bits(value, mask)                (value & ~(mask))
+
+#undef DA9052_DEBUG
+#if DA9052_BAT_DEBUG
+#define DA9052_DEBUG(fmt, args...) printk(KERN_CRIT "" fmt, ##args)
+#else
+#define DA9052_DEBUG(fmt, args...)
+#endif
+
+
+/* SSC Read or Write Error */
+#define DA9052_SSC_FAIL                        150
+
+/* To enable debug output for your module, set this to 1 */
+#define                DA9052_SSC_DEBUG        0
+
+#undef DA9052_DEBUG
+#if DA9052_SSC_DEBUG
+#define DA9052_DEBUG(fmt, args...) printk(KERN_CRIT "" fmt, ##args)
+#else
+#define DA9052_DEBUG(fmt, args...)
+#endif
+
+
+#endif /* __LINUX_MFD_DA9052_BAT_H */
diff --git a/include/linux/mfd/da9052/bl.h b/include/linux/mfd/da9052/bl.h
new file mode 100644 (file)
index 0000000..9217eb9
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * da9052 Backlight module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_BL_H
+#define __LINUX_MFD_DA9052_BL_H
+
+/*
+ * enum da9052_bl_current_value - Enum for current values of LED
+ * DA9052_BL_CURRENT_50_0UA: represents 50.0 uA current value
+ */
+enum da9052_bl_current_value {
+/* Current Value for LEDMIN, LED1_CONF, LED2_CONF, LED3_CONF Registers */
+       DA9052_BL_CURRENT_50_0UA = 0,
+       DA9052_BL_CURRENT_51_2UA,
+       DA9052_BL_CURRENT_52_5UA,
+       DA9052_BL_CURRENT_53_7UA,
+       DA9052_BL_CURRENT_55_1UA,
+       DA9052_BL_CURRENT_56_4UA,
+       DA9052_BL_CURRENT_57_8UA,
+       DA9052_BL_CURRENT_59_3UA,
+       DA9052_BL_CURRENT_60_7UA,
+       DA9052_BL_CURRENT_62_2UA,
+       DA9052_BL_CURRENT_63_8UA,
+       DA9052_BL_CURRENT_65_3UA,
+       DA9052_BL_CURRENT_67_0UA,
+       DA9052_BL_CURRENT_68_6UA,
+       DA9052_BL_CURRENT_70_3UA,
+       DA9052_BL_CURRENT_72_0UA,
+       DA9052_BL_CURRENT_73_8UA,
+       DA9052_BL_CURRENT_75_7UA,
+       DA9052_BL_CURRENT_77_5UA,
+       DA9052_BL_CURRENT_79_4UA,
+       DA9052_BL_CURRENT_81_4UA,
+       DA9052_BL_CURRENT_83_4UA,
+       DA9052_BL_CURRENT_85_5UA,
+       DA9052_BL_CURRENT_87_6UA,
+       DA9052_BL_CURRENT_89_8UA,
+       DA9052_BL_CURRENT_92_0UA,
+       DA9052_BL_CURRENT_94_2UA,
+       DA9052_BL_CURRENT_96_6UA,
+       DA9052_BL_CURRENT_99_0UA,
+       DA9052_BL_CURRENT_101_4UA,
+       DA9052_BL_CURRENT_103_9UA,
+       DA9052_BL_CURRENT_106_5UA,
+       DA9052_BL_CURRENT_109_1UA,
+       DA9052_BL_CURRENT_111_8UA,
+       DA9052_BL_CURRENT_114_6UA,
+       DA9052_BL_CURRENT_117_4UA,
+       DA9052_BL_CURRENT_120_6UA,
+       DA9052_BL_CURRENT_123_3UA,
+       DA9052_BL_CURRENT_126_3UA,
+       DA9052_BL_CURRENT_129_4UA,
+       DA9052_BL_CURRENT_132_6UA,
+       DA9052_BL_CURRENT_135_9UA,
+       DA9052_BL_CURRENT_139_3UA,
+       DA9052_BL_CURRENT_142_7UA,
+       DA9052_BL_CURRENT_146_2UA,
+       DA9052_BL_CURRENT_149_9UA,
+       DA9052_BL_CURRENT_153_6UA,
+       DA9052_BL_CURRENT_157_4UA,
+       DA9052_BL_CURRENT_161_2UA,
+       DA9052_BL_CURRENT_165_2UA,
+       DA9052_BL_CURRENT_169_3UA,
+       DA9052_BL_CURRENT_173_5UA,
+       DA9052_BL_CURRENT_177_8UA,
+       DA9052_BL_CURRENT_182_2UA,
+       DA9052_BL_CURRENT_186_7UA,
+       DA9052_BL_CURRENT_191_3UA,
+       DA9052_BL_CURRENT_196_0UA,
+       DA9052_BL_CURRENT_200_9UA,
+       DA9052_BL_CURRENT_205_8UA,
+       DA9052_BL_CURRENT_210_9UA,
+       DA9052_BL_CURRENT_216_1UA,
+       DA9052_BL_CURRENT_221_4UA,
+       DA9052_BL_CURRENT_226_9UA,
+       DA9052_BL_CURRENT_232_5UA,
+       DA9052_BL_CURRENT_238_3UA,
+       DA9052_BL_CURRENT_244_2UA,
+       DA9052_BL_CURRENT_250_2UA,
+       DA9052_BL_CURRENT_256_4UA,
+       DA9052_BL_CURRENT_262_7UA,
+       DA9052_BL_CURRENT_269_2UA,
+       DA9052_BL_CURRENT_275_8UA,
+       DA9052_BL_CURRENT_282_7UA,
+       DA9052_BL_CURRENT_289_6UA,
+       DA9052_BL_CURRENT_296_8UA,
+       DA9052_BL_CURRENT_304_1UA,
+       DA9052_BL_CURRENT_311_6UA,
+       DA9052_BL_CURRENT_319_3UA,
+       DA9052_BL_CURRENT_327_2UA,
+       DA9052_BL_CURRENT_335_3UA,
+       DA9052_BL_CURRENT_343_6UA,
+       DA9052_BL_CURRENT_352_1UA,
+       DA9052_BL_CURRENT_360_8UA,
+       DA9052_BL_CURRENT_369_7UA,
+       DA9052_BL_CURRENT_378_8UA,
+       DA9052_BL_CURRENT_388_2UA,
+       DA9052_BL_CURRENT_397_8UA,
+       DA9052_BL_CURRENT_407_6UA,
+       DA9052_BL_CURRENT_417_7UA,
+       DA9052_BL_CURRENT_428_0UA,
+       DA9052_BL_CURRENT_438_6UA,
+       DA9052_BL_CURRENT_449_4UA,
+       DA9052_BL_CURRENT_460_5UA,
+       DA9052_BL_CURRENT_471_9UA,
+       DA9052_BL_CURRENT_483_5UA,
+       DA9052_BL_CURRENT_495_5UA,
+       DA9052_BL_CURRENT_507_7UA,
+       DA9052_BL_CURRENT_520_3UA,
+       DA9052_BL_CURRENT_533_1UA,
+       DA9052_BL_CURRENT_546_3UA,
+       DA9052_BL_CURRENT_559_8UA,
+       DA9052_BL_CURRENT_573_6UA,
+       DA9052_BL_CURRENT_587_8UA,
+       DA9052_BL_CURRENT_602_3UA,
+       DA9052_BL_CURRENT_617_2UA,
+       DA9052_BL_CURRENT_632_4UA,
+       DA9052_BL_CURRENT_648_0UA,
+       DA9052_BL_CURRENT_664_0UA,
+       DA9052_BL_CURRENT_680_4UA,
+       DA9052_BL_CURRENT_697_2UA,
+       DA9052_BL_CURRENT_714_5UA,
+       DA9052_BL_CURRENT_732_1UA,
+       DA9052_BL_CURRENT_750_2UA,
+       DA9052_BL_CURRENT_768_7UA,
+       DA9052_BL_CURRENT_787_7UA,
+       DA9052_BL_CURRENT_807_2UA,
+       DA9052_BL_CURRENT_827_1UA,
+       DA9052_BL_CURRENT_847_6UA,
+       DA9052_BL_CURRENT_868_5UA,
+       DA9052_BL_CURRENT_889_9UA,
+       DA9052_BL_CURRENT_911_9UA,
+       DA9052_BL_CURRENT_934_4UA,
+       DA9052_BL_CURRENT_957_5UA,
+       DA9052_BL_CURRENT_981_2UA,
+       DA9052_BL_CURRENT_1005_4UA,
+       DA9052_BL_CURRENT_1030_3UA,
+       DA9052_BL_CURRENT_1055_7UA,
+       DA9052_BL_CURRENT_1081_8UA,
+       DA9052_BL_CURRENT_1108_5UA,
+       DA9052_BL_CURRENT_1135_9UA,
+       DA9052_BL_CURRENT_1163_9UA,
+       DA9052_BL_CURRENT_1192_7UA,
+       DA9052_BL_CURRENT_1222_2UA,
+       DA9052_BL_CURRENT_1252_3UA,
+       DA9052_BL_CURRENT_1283_3UA,
+       DA9052_BL_CURRENT_1315_0UA,
+       DA9052_BL_CURRENT_1347_5UA,
+       DA9052_BL_CURRENT_1380_7UA,
+       DA9052_BL_CURRENT_1414_8UA,
+       DA9052_BL_CURRENT_1449_8UA,
+       DA9052_BL_CURRENT_1485_6UA,
+       DA9052_BL_CURRENT_1522_3UA,
+       DA9052_BL_CURRENT_1559_9UA,
+       DA9052_BL_CURRENT_1598_4UA,
+       DA9052_BL_CURRENT_1637_9UA,
+       DA9052_BL_CURRENT_1678_4UA,
+       DA9052_BL_CURRENT_1719_8UA,
+       DA9052_BL_CURRENT_1762_3UA,
+       DA9052_BL_CURRENT_1805_8UA,
+       DA9052_BL_CURRENT_1850_4UA,
+       DA9052_BL_CURRENT_1896_1UA,
+       DA9052_BL_CURRENT_1943_0UA,
+       DA9052_BL_CURRENT_1991_0UA,
+       DA9052_BL_CURRENT_2040_2UA,
+       DA9052_BL_CURRENT_2090_5UA,
+       DA9052_BL_CURRENT_2142_2UA,
+       DA9052_BL_CURRENT_2195_1UA,
+       DA9052_BL_CURRENT_2249_3UA,
+       DA9052_BL_CURRENT_2304_9UA,
+       DA9052_BL_CURRENT_2361_8UA,
+       DA9052_BL_CURRENT_2420_1UA,
+       DA9052_BL_CURRENT_2479_9UA,
+       DA9052_BL_CURRENT_2541_2UA,
+       DA9052_BL_CURRENT_2604_0UA,
+       DA9052_BL_CURRENT_2668_3UA,
+       DA9052_BL_CURRENT_2734_2UA,
+       DA9052_BL_CURRENT_2801_7UA,
+       DA9052_BL_CURRENT_2870_9UA,
+       DA9052_BL_CURRENT_2941_8UA,
+       DA9052_BL_CURRENT_3014_5UA,
+       DA9052_BL_CURRENT_3089_0UA,
+       DA9052_BL_CURRENT_3165_3UA,
+       DA9052_BL_CURRENT_3243_4UA,
+       DA9052_BL_CURRENT_3323_5UA,
+       DA9052_BL_CURRENT_3405_6UA,
+       DA9052_BL_CURRENT_3489_8UA,
+       DA9052_BL_CURRENT_3576_0UA,
+       DA9052_BL_CURRENT_3664_3UA,
+       DA9052_BL_CURRENT_3754_8UA,
+       DA9052_BL_CURRENT_3847_5UA,
+       DA9052_BL_CURRENT_3942_6UA,
+       DA9052_BL_CURRENT_4040_0UA,
+       DA9052_BL_CURRENT_4139_7UA,
+       DA9052_BL_CURRENT_4242_0UA,
+       DA9052_BL_CURRENT_4346_8UA,
+       DA9052_BL_CURRENT_4454_1UA,
+       DA9052_BL_CURRENT_4564_2UA,
+       DA9052_BL_CURRENT_4676_9UA,
+       DA9052_BL_CURRENT_4792_4UA,
+       DA9052_BL_CURRENT_4910_8UA,
+       DA9052_BL_CURRENT_5032_1UA,
+       DA9052_BL_CURRENT_5156_4UA,
+       DA9052_BL_CURRENT_5283_7UA,
+       DA9052_BL_CURRENT_5414_3UA,
+       DA9052_BL_CURRENT_5548_0UA,
+       DA9052_BL_CURRENT_5685_0UA,
+       DA9052_BL_CURRENT_5825_5UA,
+       DA9052_BL_CURRENT_5969_3UA,
+       DA9052_BL_CURRENT_6116_8UA,
+       DA9052_BL_CURRENT_6267_9UA,
+       DA9052_BL_CURRENT_6422_7UA,
+       DA9052_BL_CURRENT_6581_3UA,
+       DA9052_BL_CURRENT_6743_9UA,
+       DA9052_BL_CURRENT_6910_5UA,
+       DA9052_BL_CURRENT_7081_2UA,
+       DA9052_BL_CURRENT_7256_1UA,
+       DA9052_BL_CURRENT_7435_3UA,
+       DA9052_BL_CURRENT_7618_9UA,
+       DA9052_BL_CURRENT_7807_1UA,
+       DA9052_BL_CURRENT_8000_0UA,
+       DA9052_BL_CURRENT_8197_6UA,
+       DA9052_BL_CURRENT_8400_0UA,
+       DA9052_BL_CURRENT_8607_5UA,
+       DA9052_BL_CURRENT_8820_1UA,
+       DA9052_BL_CURRENT_9038_0UA,
+       DA9052_BL_CURRENT_9261_2UA,
+       DA9052_BL_CURRENT_9490_0UA,
+       DA9052_BL_CURRENT_9724_4UA,
+       DA9052_BL_CURRENT_9964_6UA,
+       DA9052_BL_CURRENT_10210_7UA,
+       DA9052_BL_CURRENT_10462_9UA,
+       DA9052_BL_CURRENT_10721_4UA,
+       DA9052_BL_CURRENT_10986_4UA,
+       DA9052_BL_CURRENT_11257_5UA,
+       DA9052_BL_CURRENT_11535_6UA,
+       DA9052_BL_CURRENT_11820_5UA,
+       DA9052_BL_CURRENT_12112_5UA,
+       DA9052_BL_CURRENT_12411_7UA,
+       DA9052_BL_CURRENT_12718_2UA,
+       DA9052_BL_CURRENT_13032_4UA,
+       DA9052_BL_CURRENT_13354_3UA,
+       DA9052_BL_CURRENT_13684_1UA,
+       DA9052_BL_CURRENT_14022_1UA,
+       DA9052_BL_CURRENT_14368_5UA,
+       DA9052_BL_CURRENT_14723_4UA,
+       DA9052_BL_CURRENT_15087_1UA,
+       DA9052_BL_CURRENT_15459_7UA,
+       DA9052_BL_CURRENT_15841_6UA,
+       DA9052_BL_CURRENT_16232_9UA,
+       DA9052_BL_CURRENT_16633_8UA,
+       DA9052_BL_CURRENT_17044_7UA,
+       DA9052_BL_CURRENT_17465_7UA,
+       DA9052_BL_CURRENT_17897_1UA,
+       DA9052_BL_CURRENT_18339_1UA,
+       DA9052_BL_CURRENT_18792_1UA,
+       DA9052_BL_CURRENT_19256_3UA,
+       DA9052_BL_CURRENT_19731_9UA,
+       DA9052_BL_CURRENT_20219_3UA,
+       DA9052_BL_CURRENT_20718_7UA,
+       DA9052_BL_CURRENT_21230_5UA,
+       DA9052_BL_CURRENT_21754_8UA,
+       DA9052_BL_CURRENT_22292_2UA,
+       DA9052_BL_CURRENT_22842_8UA,
+       DA9052_BL_CURRENT_23407_0UA,
+       DA9052_BL_CURRENT_23985_2UA,
+       DA9052_BL_CURRENT_24577_6UA,
+       DA9052_BL_CURRENT_25000_0UA,
+};
+
+#endif /* __LINUX_MFD_DA9052_BL_H */
diff --git a/include/linux/mfd/da9052/da9052.h b/include/linux/mfd/da9052/da9052.h
new file mode 100644 (file)
index 0000000..7652d07
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * da9052 declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_DA9052_H
+#define __LINUX_MFD_DA9052_DA9052_H
+
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+
+#include <linux/mfd/da9052/eh.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/led.h>
+
+
+#define SPI 1
+#define I2C 2
+
+#define DA9052_SSC_DEVICE_NAME         "da9052_ssc"
+#define DA9052_EH_DEVICE_NAME          "da9052_eh"
+
+#define DA9052_IRQ                     S3C_EINT(9)
+
+/* Module specific error codes */
+#define INVALID_REGISTER               2
+#define INVALID_READ                   3
+#define INVALID_PAGE                   4
+
+/* Defines for Volatile and Non Volatile register types */
+#define VOLATILE                       0
+#define NON_VOLATILE                   1
+
+/* Defines for cache state */
+#define VALID                          0
+#define INVALID                                1
+
+/* Total number of registers in DA9057 */
+#define DA9052_REG_CNT                 DA9052_PAGE1_REG_END
+
+/* Maximum number of registers that can be read/written by a singe request */
+#define        MAX_READ_WRITE_CNT              16
+
+
+#define DA9052_SSC_SPI_DEVICE_NAME     "da9052_ssc_spi"
+#define PAGE_0_START                   1
+#define PAGE_0_END                     127
+#define PAGE_1_START                   128
+#define PAGE_1_END                     255
+#define ACTIVE_PAGE_0                  0
+#define ACTIVE_PAGE_1                  1
+#define PAGECON_0                      0
+#define PAGECON_128                    128
+#define RW_POL                         1
+
+#define DA9052_SSC_I2C_DEVICE_NAME             "da9052_ssc_i2c"
+#define        DA9052_I2C_ADDR                         0x90
+#define        DA9052_SSC_I2C_PAGE_WRITE_MODE          0
+#define DA9052_SSC_I2C_REPEAT_WRITE_MODE       1
+#define DA9052_SSC_I2C_WRITE_MODE              DA9052_SSC_I2C_REPEAT_WRITE_MODE
+
+struct da9052_ssc_msg {
+       unsigned char   data;
+       unsigned char   addr;
+};
+
+struct ssc_cache_entry{
+        unsigned char  val;
+        unsigned char  type:4;
+        unsigned char  status:4;
+};
+
+struct da9052_eh_nb{
+       struct list_head nb_list;
+       unsigned char   eve_type;
+       void (*call_back)(struct da9052_eh_nb *, unsigned int);
+};
+
+struct da9052_regulator_init_data {
+       struct regulator_init_data *init_data;
+};
+
+struct da9052_regulator_platform_data {
+       struct regulator_init_data *regulators;
+};
+
+struct da9052_tsi_platform_data {
+       u32     pen_up_interval;
+       u16     tsi_delay_bit_shift;
+       u16     tsi_skip_bit_shift;
+       u16     num_gpio_tsi_register;
+       u16     tsi_supply_voltage;
+       u16     tsi_ref_source;
+       u16     max_tsi_delay;
+       u16     max_tsi_skip_slot;
+};
+
+
+struct da9052 {
+       struct mutex ssc_lock;
+       struct mutex eve_nb_lock;
+       struct mutex manconv_lock;
+       struct work_struct eh_isr_work;
+       struct ssc_cache_entry ssc_cache[DA9052_REG_CNT];
+       int (*read) (struct da9052 *da9052, struct da9052_ssc_msg *sscmsg);
+       int (*write) (struct da9052 *da9052, struct da9052_ssc_msg *sscmsg);
+       int (*read_many) (struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg, int cnt);
+       int (*write_many)(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg, int cnt);
+       int (*register_event_notifier)(struct da9052 *da9052,
+               struct da9052_eh_nb *nb);
+       int (*unregister_event_notifier)(struct da9052 *da9052,
+               struct da9052_eh_nb *nb);
+       int num_regulators;
+       int connecting_device;
+       struct          spi_device *spi_dev;
+       unsigned int    spi_active_page;
+       unsigned char   rw_pol;
+       unsigned char   *spi_rx_buf;
+       unsigned char   *spi_tx_buf;
+
+       struct i2c_client *i2c_client;
+       struct device *dev;
+       struct i2c_adapter *adapter;
+       unsigned char   slave_addr;
+};
+
+
+struct da9052_platform_data {
+       int (*init)(struct da9052 *da9052);
+       int     irq_high;
+       int     irq_base;
+       int     gpio_base;
+       int     num_regulators;
+       struct da9052 *da9052;
+       struct regulator_init_data *regulators;
+       struct da9052_leds_platform_data *led_data;
+       struct da9052_tsi_platform_data *tsi_data;
+};
+
+struct da9052_ssc_ops {
+       int (*write)(struct da9052 *da9052, struct da9052_ssc_msg *msg);
+       int (*read)(struct da9052 *da9052, struct da9052_ssc_msg *msg);
+       int (*write_many)(struct da9052 *da9052,
+       struct da9052_ssc_msg *sscmsg, int msg_no);
+       int (*read_many)(struct da9052 *da9052,
+       struct da9052_ssc_msg *sscmsg, int msg_no);
+       int (*device_register)(struct da9052 *da9052);
+       void (*device_unregister)(void);
+};
+
+int da9052_ssc_write(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg);
+int da9052_ssc_read(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg);
+int da9052_ssc_write_many(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg, int cnt);
+int da9052_ssc_read_many(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg, int cnt);
+
+int da9052_spi_write(struct da9052 *da9052,
+               struct da9052_ssc_msg *msg);
+int da9052_spi_read(struct da9052 *da9052,
+               struct da9052_ssc_msg *msg);
+
+int da9052_spi_write_many(struct da9052 *da9052, struct da9052_ssc_msg *sscmsg,
+               int msg_no);
+int da9052_spi_read_many(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg,
+               int msg_no);
+
+void da9052_ssc_exit(struct da9052 *da9052);
+int da9052_ssc_init(struct da9052 *da9052);
+
+/* I2C specific Functions */
+int da9052_i2c_write(struct da9052 *da9052, struct da9052_ssc_msg *msg);
+int da9052_i2c_read(struct da9052 *da9052, struct da9052_ssc_msg *msg);
+int da9052_i2c_write_many(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg, int msg_no);
+int da9052_i2c_read_many(struct da9052 *da9052,
+               struct da9052_ssc_msg *sscmsg, int msg_no);
+
+void da9052_lock(struct da9052 *da9052);
+void da9052_unlock(struct da9052 *da9052);
+int eh_register_nb(struct da9052 *da9052, struct da9052_eh_nb *nb);
+int eh_unregister_nb(struct da9052 *da9052, struct da9052_eh_nb *nb);
+int da9052_manual_read(struct da9052 *da9052,
+               unsigned char channel);
+#endif /* __LINUX_MFD_DA9052_DA9052_H */
diff --git a/include/linux/mfd/da9052/eh.h b/include/linux/mfd/da9052/eh.h
new file mode 100644 (file)
index 0000000..c46df5d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * da9052 Event Handler module declarations.
+  *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_EH_H
+#define __LINUX_MFD_DA9052_EH_H
+
+#define DA9052_EVE_REGISTERS           4
+#define DA9052_EVE_REGISTER_SIZE       8
+
+/* Define for all possible events */
+#define DCIN_DET_EVE                   0
+#define VBUS_DET_EVE                   1
+#define DCIN_REM_EVE                   2
+#define VBUS_REM_EVE                   3
+#define VDD_LOW_EVE                    4
+#define ALARM_EVE                      5
+#define SEQ_RDY_EVE                    6
+#define COMP_1V2                       7
+#define ONKEY_EVE                      8
+#define ID_FLOAT_EVE                   9
+#define ID_GND_EVE                     10
+#define CHG_END_EVE                    11
+#define TBAT_EVE                       12
+#define ADC_EOM_EVE                    13
+#define PEN_DOWN_EVE                   14
+#define TSI_READY_EVE                  15
+#define GPI0_EVE                       16
+#define GPI1_EVE                       17
+#define GPI2_EVE                       18
+#define GPI3_EVE                       19
+#define GPI4_EVE                       20
+#define GPI5_EVE                       21
+#define GPI6_EVE                       22
+#define GPI7_EVE                       23
+#define GPI8_EVE                       24
+#define GPI9_EVE                       25
+#define GPI10_EVE                      26
+#define GPI11_EVE                      27
+#define GPI12_EVE                      28
+#define GPI13_EVE                      29
+#define GPI14_EVE                      30
+#define GPI15_EVE                      31
+
+/* Total number of events */
+#define EVE_CNT                                (GPI15_EVE+1)
+
+/* Error code for register/unregister functions */
+#define INVALID_NB                     2
+#define INVALID_EVE                    3
+
+/* State for EH thread */
+#define ACTIVE                         0
+#define INACTIVE                       1
+
+/* Status of nIRQ line */
+#define IRQ_HIGH                       0
+#define IRQ_LOW                                1
+
+#endif /* __LINUX_MFD_DA9052_EH_H */
diff --git a/include/linux/mfd/da9052/gpio.h b/include/linux/mfd/da9052/gpio.h
new file mode 100644 (file)
index 0000000..68a24ad
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * da9052 GPIO module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_GPIO_H
+#define __LINUX_MFD_DA9052_GPIO_H
+
+#include <linux/gpio.h>
+#define DA9052_GPIO_DEVICE_NAME                        "da9052_gpio"
+
+#define DA9052_GPIO_INVALID_TYPE               1
+#define DA9052_GPIO_INVALID_MODE               2
+#define DA9052_GPIO_INVALID_PORTNUMBER         3
+#define DA9052_GPIO_INVALID_FUNCTION           4
+
+#define DA9052_GPIO_CONFIG_ADC                 1
+#define DA9052_GPIO_CONFIG_TSI                 2
+#define DA9052_GPIO_CONFIG_PM                  3
+#define DA9052_GPIO_CONFIG_ACC_ID_DET          4
+#define DA9052_GPIO_CONFIG_GP_FB1              5
+#define DA9052_GPIO_CONFIG_VDD_FAULT           6
+#define DA9052_GPIO_CONFIG_I2C                 7
+#define DA9052_GPIO_CONFIG                     8
+
+/* Currently used defines for GPIO PINs  */
+#define DA9052_GPIO_PIN_0                      DA9052_GPIO_CONFIG_ADC
+#define DA9052_GPIO_PIN_1                      DA9052_GPIO_CONFIG_ADC
+#define DA9052_GPIO_PIN_2                      DA9052_GPIO_CONFIG_ADC
+
+#define DA9052_GPIO_PIN_3                      DA9052_GPIO_CONFIG_TSI
+#define DA9052_GPIO_PIN_4                      DA9052_GPIO_CONFIG_TSI
+#define DA9052_GPIO_PIN_5                      DA9052_GPIO_CONFIG_TSI
+#define DA9052_GPIO_PIN_6                      DA9052_GPIO_CONFIG_TSI
+#define DA9052_GPIO_PIN_7                      DA9052_GPIO_CONFIG_TSI
+
+#define DA9052_GPIO_PIN_8                      DA9052_GPIO_CONFIG
+#define DA9052_GPIO_PIN_9                      DA9052_GPIO_CONFIG
+#define DA9052_GPIO_PIN_10                     DA9052_GPIO_CONFIG
+#define DA9052_GPIO_PIN_11                     DA9052_GPIO_CONFIG
+
+#define DA9052_GPIO_PIN_12                     DA9052_GPIO_CONFIG
+#define DA9052_GPIO_PIN_13                     DA9052_GPIO_CONFIG
+
+#define DA9052_GPIO_PIN_14                     DA9052_GPIO_CONFIG
+#define DA9052_GPIO_PIN_15                     DA9052_GPIO_CONFIG
+
+enum ip_op_type {
+       ALTERNATE_FUNCTIONALITY = 0,
+       INPUT,
+       OUTPUT_OPENDRAIN,
+       OUTPUT_PUSHPULL
+};
+
+enum ip_type {
+       ACTIVE_LOW = 0,
+       ACTIVE_HIGH
+};
+
+enum op_type {
+       SUPPLY_VDD_IO1 = 0,
+       SUPPLY_VDD_IO2
+};
+
+
+enum op_mode {
+       OUTPUT_LOWLEVEL = 0,
+       OUTPUT_HIGHLEVEL
+};
+
+
+enum ip_mode {
+       DEBOUNCING_OFF = 0,
+       DEBOUNCING_ON
+};
+
+/*DEFAULT CONFIG FOR GPIO 0*/
+#if (DA9052_GPIO_PIN_0 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO0_FUNCTION                 INPUT
+#define DEFAULT_GPIO0_TYPE                     ACTIVE_LOW
+#define DEFAULT_GPIO0_MODE                     DEBOUNCING_ON
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 1*/
+#if (DA9052_GPIO_PIN_1 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO1_FUNCTION                 INPUT
+#define DEFAULT_GPIO1_TYPE                     ACTIVE_LOW
+#define DEFAULT_GPIO1_MODE                     DEBOUNCING_ON
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 2*/
+#if (DA9052_GPIO_PIN_2 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO2_FUNCTION                 INPUT
+#define DEFAULT_GPIO2_TYPE                     ACTIVE_LOW
+#define DEFAULT_GPIO2_MODE                     DEBOUNCING_ON
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 3*/
+#if (DA9052_GPIO_PIN_3 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO3_FUNCTION                 INPUT
+#define DEFAULT_GPIO3_TYPE                     ACTIVE_LOW
+#define DEFAULT_GPIO3_MODE                     DEBOUNCING_ON
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 4*/
+#if (DA9052_GPIO_PIN_4 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO4_FUNCTION                 OUTPUT_PUSHPULL
+#define DEFAULT_GPIO4_TYPE                     SUPPLY_VDD_IO1
+#define DEFAULT_GPIO4_MODE                     OUTPUT_LOWLEVEL
+#endif
+/*DEFAULT CONFIG FOR GPIO 5*/
+#if (DA9052_GPIO_PIN_5 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO5_FUNCTION                 OUTPUT_PUSHPULL
+#define DEFAULT_GPIO5_TYPE                     SUPPLY_VDD_IO1
+#define DEFAULT_GPIO5_MODE                     OUTPUT_LOWLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 6*/
+#if (DA9052_GPIO_PIN_6 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO6_FUNCTION                 OUTPUT_PUSHPULL
+#define DEFAULT_GPIO6_TYPE                     SUPPLY_VDD_IO1
+#define DEFAULT_GPIO6_MODE                     OUTPUT_LOWLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 7*/
+#if (DA9052_GPIO_PIN_7 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO7_FUNCTION                 OUTPUT_PUSHPULL
+#define DEFAULT_GPIO7_TYPE                     SUPPLY_VDD_IO1
+#define DEFAULT_GPIO7_MODE                     OUTPUT_LOWLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 8*/
+#if (DA9052_GPIO_PIN_8 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO8_FUNCTION                 INPUT
+#define DEFAULT_GPIO8_TYPE                     ACTIVE_LOW
+#define DEFAULT_GPIO8_MODE                     DEBOUNCING_ON
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 9*/
+#if (DA9052_GPIO_PIN_9 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO9_FUNCTION                 INPUT
+#define DEFAULT_GPIO9_TYPE                     ACTIVE_LOW
+#define DEFAULT_GPIO9_MODE                     DEBOUNCING_ON
+#endif
+
+#if (DA9052_GPIO_PIN_10 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO10_FUNCTION                        OUTPUT_PUSHPULL
+#define DEFAULT_GPIO10_TYPE                    SUPPLY_VDD_IO2
+#define DEFAULT_GPIO10_MODE                    OUTPUT_HIGHLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 11 - for RTC blinking LED */
+#if (DA9052_GPIO_PIN_11 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO11_FUNCTION                        OUTPUT_PUSHPULL
+#define DEFAULT_GPIO11_TYPE                    SUPPLY_VDD_IO2
+#define DEFAULT_GPIO11_MODE                    OUTPUT_HIGHLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 12*/
+#if (DA9052_GPIO_PIN_12 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO12_FUNCTION                        OUTPUT_PUSHPULL
+#define DEFAULT_GPIO12_TYPE                    SUPPLY_VDD_IO1
+#define DEFAULT_GPIO12_MODE                    OUTPUT_LOWLEVEL
+#endif
+/*DEFAULT CONFIG FOR GPIO 13*/
+#if (DA9052_GPIO_PIN_13 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO13_FUNCTION                        OUTPUT_PUSHPULL
+#define DEFAULT_GPIO13_TYPE                    SUPPLY_VDD_IO1
+#define DEFAULT_GPIO13_MODE                    OUTPUT_LOWLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 14 - for LED4 */
+#if (DA9052_GPIO_PIN_14 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO14_FUNCTION                        OUTPUT_OPENDRAIN
+#define DEFAULT_GPIO14_TYPE                    SUPPLY_VDD_IO1
+#define DEFAULT_GPIO14_MODE                    OUTPUT_HIGHLEVEL
+#endif
+
+/*DEFAULT CONFIG FOR GPIO 15 - for LED5 */
+#if (DA9052_GPIO_PIN_15 == DA9052_GPIO_CONFIG)
+#define DEFAULT_GPIO15_FUNCTION                        OUTPUT_OPENDRAIN
+#define DEFAULT_GPIO15_TYPE                    SUPPLY_VDD_IO1
+#define DEFAULT_GPIO15_MODE                    OUTPUT_HIGHLEVEL
+#endif
+
+#define DA9052_GPIO_MAX_PORTNUMBER                     16
+#define DA9052_GPIO_MAX_PORTS_PER_REGISTER             8
+#define DA9052_GPIO_SHIFT_COUNT(no)                    ((no)%8)
+#define DA9052_GPIO_EVEN_PORT_FUNCTIONALITY            0x03
+#define DA9052_GPIO_ODD_PORT_FUNCTIONALITY             0x30
+#define DA9052_GPIO_MASK_UPPER_NIBBLE                  0xF0
+#define DA9052_GPIO_MASK_LOWER_NIBBLE                  0x0F
+#define DA9052_GPIO_NIBBLE_SHIFT                       4
+#define DA9052_GPIO_EVEN_PORT_WRITE_MODE               (1 << 3)
+#define DA9052_GPIO_ODD_PORT_WRITE_MODE                        (1 << 7)
+
+
+struct da9052_gpio_read_write {
+       u8 port_number:4;
+       u8 read_write_value:1;
+} ;
+
+struct da9052_gpio_multiple_read {
+       u8 signal_value[16];
+};
+
+struct da9052_gpi_config {
+       enum ip_type type;
+       enum ip_mode mode;
+};
+
+struct da9052_gpo_config {
+       enum op_type type;
+       enum op_mode mode;
+} ;
+
+union da9052_gpio_config {
+       struct da9052_gpi_config input;
+       struct da9052_gpo_config output;
+};
+
+struct da9052_gpio {
+       union da9052_gpio_config gpio_config;
+       enum ip_op_type gpio_function;
+       u8 port_number:4;
+};
+
+struct da9052_gpio_chip {
+       struct da9052_gpio gpio;
+       struct da9052_gpio_read_write read_write;
+       struct da9052 *da9052;
+       /* For testing*/
+       struct da9052_eh_nb eh_data;
+       struct gpio_chip gp;
+};
+
+#endif /* __LINUX_MFD_DA9052_GPIO_H */
diff --git a/include/linux/mfd/da9052/led.h b/include/linux/mfd/da9052/led.h
new file mode 100644 (file)
index 0000000..b4145cd
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * da9052 LED module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_LED_H
+#define __LINUX_MFD_DA9052_LED_H
+
+struct da9052_led_platform_data {
+#define DA9052_LED_4                   4
+#define DA9052_LED_5                   5
+#define DA9052_LED_MAX                 2
+       int id;
+       const char *name;
+       const char *default_trigger;
+};
+
+struct da9052_leds_platform_data {
+       int num_leds;
+       struct da9052_led_platform_data *led;
+};
+
+#endif /* __LINUX_MFD_DA9052_LED_H */
diff --git a/include/linux/mfd/da9052/pm.h b/include/linux/mfd/da9052/pm.h
new file mode 100644 (file)
index 0000000..9a1c4f8
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * da9052 Power Management module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_PM_H
+#define __LINUX_MFD_DA9052_PM_H
+
+/* PM Device name and static Major number macros */
+#define DRIVER_NAME                            "da9052-regulator"
+
+/* PM Device Macros */
+#define DA9052_LDO1                            0
+#define DA9052_LDO2                            1
+#define DA9052_LDO3                            2
+#define DA9052_LDO4                            3
+#define DA9052_LDO5                            4
+#define DA9052_LDO6                            5
+#define DA9052_LDO7                            6
+#define DA9052_LDO8                            7
+#define DA9052_LDO9                            8
+#define DA9052_LDO10                           9
+#define DA9052_BUCK_CORE                       10
+#define DA9052_BUCK_PRO                                11
+#define DA9052_BUCK_MEM                                12
+#define DA9052_BUCK_PERI                       13
+
+/* PM Device Error Codes */
+
+/* Buck Config Validation Macros */
+#define DA9052_BUCK_CORE_PRO_VOLT_UPPER                2075
+#define DA9052_BUCK_CORE_PRO_VOLT_LOWER                500
+#define DA9052_BUCK_CORE_PRO_STEP              25
+#define DA9052_BUCK_MEM_VOLT_UPPER             2500
+#define DA9052_BUCK_MEM_VOLT_LOWER             925
+#define DA9052_BUCK_MEM_STEP                   25
+#if defined (CONFIG_PMIC_DA9052)
+#define DA9052_BUCK_PERI_VOLT_UPPER            3600
+#define DA9052_BUCK_PERI_VOLT_LOWER            1800
+#define DA9052_BUCK_PERI_STEP_BELOW_3000       50
+#define DA9052_BUCK_PERI_STEP_ABOVE_3000       100000
+#define DA9052_BUCK_PERI_VALUES_UPTO_3000      24
+#define DA9052_BUCK_PERI_VALUES_3000           3000000
+#elif defined (CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx)
+#define DA9052_BUCK_PERI_VOLT_UPPER            2500
+#define DA9052_BUCK_PERI_VOLT_LOWER            925
+#define DA9052_BUCK_PERI_STEP                  25
+#endif
+#define DA9052_LDO1_VOLT_UPPER                 1800
+#define DA9052_LDO1_VOLT_LOWER                 600
+#define DA9052_LDO1_VOLT_STEP                  50
+#define DA9052_LDO2_VOLT_UPPER                 1800
+#define DA9052_LDO2_VOLT_LOWER                 600
+#define DA9052_LDO2_VOLT_STEP                  25
+#define DA9052_LDO34_VOLT_UPPER                        3300
+#define DA9052_LDO34_VOLT_LOWER                        1725
+#define DA9052_LDO34_VOLT_STEP                 25
+#define DA9052_LDO567810_VOLT_UPPER            3600
+#define DA9052_LDO567810_VOLT_LOWER            1200
+#define DA9052_LDO567810_VOLT_STEP             50
+#define DA9052_LDO9_VOLT_STEP                  50
+#define DA9052_LDO9_VOLT_LOWER                 1250
+#define DA9052_LDO9_VOLT_UPPER                 3650
+
+#endif /* __LINUX_MFD_DA9052_PM_H */
diff --git a/include/linux/mfd/da9052/reg.h b/include/linux/mfd/da9052/reg.h
new file mode 100644 (file)
index 0000000..9daaa02
--- /dev/null
@@ -0,0 +1,929 @@
+/*
+ * da9052 register declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_REG_H
+#define __LINUX_MFD_DA9052_REG_H
+
+#define DA9052_PAGECON0_REG                    0
+#define DA9052_STATUSA_REG                     1
+#define DA9052_STATUSB_REG                     2
+#define DA9052_STATUSC_REG                     3
+#define DA9052_STATUSD_REG                     4
+#define DA9052_EVENTA_REG                      5
+#define DA9052_EVENTB_REG                      6
+#define DA9052_EVENTC_REG                      7
+#define DA9052_EVENTD_REG                      8
+#define DA9052_FAULTLOG_REG                    9
+#define DA9052_IRQMASKA_REG                    10
+#define DA9052_IRQMASKB_REG                    11
+#define DA9052_IRQMASKC_REG                    12
+#define DA9052_IRQMASKD_REG                    13
+#define DA9052_CONTROLA_REG                    14
+#define DA9052_CONTROLB_REG                    15
+#define DA9052_CONTROLC_REG                    16
+#define DA9052_CONTROLD_REG                    17
+#define DA9052_PDDIS_REG                       18
+#define DA9052_INTERFACE_REG                   19
+#define DA9052_RESET_REG                       20
+#define DA9052_GPIO0001_REG                    21
+#define DA9052_GPIO0203_REG                    22
+#define DA9052_GPIO0405_REG                    23
+#define DA9052_GPIO0607_REG                    24
+#define DA9052_GPIO0809_REG                    25
+#define DA9052_GPIO1011_REG                    26
+#define DA9052_GPIO1213_REG                    27
+#define DA9052_GPIO1415_REG                    28
+#define DA9052_ID01_REG                                29
+#define DA9052_ID23_REG                                30
+#define DA9052_ID45_REG                                31
+#define DA9052_ID67_REG                                32
+#define DA9052_ID89_REG                                33
+#define DA9052_ID1011_REG                      34
+#define DA9052_ID1213_REG                      35
+#define DA9052_ID1415_REG                      36
+#define DA9052_ID1617_REG                      37
+#define DA9052_ID1819_REG                      38
+#define DA9052_ID2021_REG                      39
+#define DA9052_SEQSTATUS_REG                   40
+#define DA9052_SEQA_REG                                41
+#define DA9052_SEQB_REG                                42
+#define DA9052_SEQTIMER_REG                    43
+#define DA9052_BUCKA_REG                       44
+#define DA9052_BUCKB_REG                       45
+#define DA9052_BUCKCORE_REG                    46
+#define DA9052_BUCKPRO_REG                     47
+#define DA9052_BUCKMEM_REG                     48
+#define DA9052_BUCKPERI_REG                    49
+#define DA9052_LDO1_REG                                50
+#define DA9052_LDO2_REG                                51
+#define DA9052_LDO3_REG                                52
+#define DA9052_LDO4_REG                                53
+#define DA9052_LDO5_REG                                54
+#define DA9052_LDO6_REG                                55
+#define DA9052_LDO7_REG                                56
+#define DA9052_LDO8_REG                                57
+#define DA9052_LDO9_REG                                58
+#define DA9052_LDO10_REG                       59
+#define DA9052_SUPPLY_REG                      60
+#define DA9052_PULLDOWN_REG                    61
+#define DA9052_CHGBUCK_REG                     62
+#define DA9052_WAITCONT_REG                    63
+#define DA9052_ISET_REG                                64
+#define DA9052_BATCHG_REG                      65
+#define DA9052_CHGCONT_REG                     66
+#define DA9052_INPUTCONT_REG                   67
+#define DA9052_CHGTIME_REG                     68
+#define DA9052_BBATCONT_REG                    69
+#define DA9052_BOOST_REG                       70
+#define DA9052_LEDCONT_REG                     71
+#define DA9052_LEDMIN123_REG                   72
+#define DA9052_LED1CONF_REG                    73
+#define DA9052_LED2CONF_REG                    74
+#define DA9052_LED3CONF_REG                    75
+#define DA9052_LED1CONT_REG                    76
+#define DA9052_LED2CONT_REG                    77
+#define DA9052_LED3CONT_REG                    78
+#define DA9052_LED4CONT_REG                    79
+#define DA9052_LED5CONT_REG                    80
+#define DA9052_ADCMAN_REG                      81
+#define DA9052_ADCCONT_REG                     82
+#define DA9052_ADCRESL_REG                     83
+#define DA9052_ADCRESH_REG                     84
+#define DA9052_VDDRES_REG                      85
+#define DA9052_VDDMON_REG                      86
+#define DA9052_ICHGAV_REG                      87
+#define DA9052_ICHGTHD_REG                     88
+#define DA9052_ICHGEND_REG                     89
+#define DA9052_TBATRES_REG                     90
+#define DA9052_TBATHIGHP_REG                   91
+#define DA9052_TBATHIGHIN_REG                  92
+#define DA9052_TBATLOW_REG                     93
+#define DA9052_TOFFSET_REG                     94
+#define DA9052_ADCIN4RES_REG                   95
+#define DA9052_AUTO4HIGH_REG                   96
+#define DA9052_AUTO4LOW_REG                    97
+#define DA9052_ADCIN5RES_REG                   98
+#define DA9052_AUTO5HIGH_REG                   99
+#define DA9052_AUTO5LOW_REG                    100
+#define DA9052_ADCIN6RES_REG                   101
+#define DA9052_AUTO6HIGH_REG                   102
+#define DA9052_AUTO6LOW_REG                    103
+#define DA9052_TJUNCRES_REG                    104
+#define DA9052_TSICONTA_REG                    105
+#define DA9052_TSICONTB_REG                    106
+#define DA9052_TSIXMSB_REG                     107
+#define DA9052_TSIYMSB_REG                     108
+#define DA9052_TSILSB_REG                      109
+#define DA9052_TSIZMSB_REG                     110
+#define DA9052_COUNTS_REG                      111
+#define DA9052_COUNTMI_REG                     112
+#define DA9052_COUNTH_REG                      113
+#define DA9052_COUNTD_REG                      114
+#define DA9052_COUNTMO_REG                     115
+#define DA9052_COUNTY_REG                      116
+#define DA9052_ALARMMI_REG                     117
+#define DA9052_ALARMH_REG                      118
+#define DA9052_ALARMD_REG                      119
+#define DA9052_ALARMMO_REG                     120
+#define DA9052_ALARMY_REG                      121
+#define DA9052_SECONDA_REG                     122
+#define DA9052_SECONDB_REG                     123
+#define DA9052_SECONDC_REG                     124
+#define DA9052_SECONDD_REG                     125
+#define DA9052_PAGECON128_REG                  128
+#define DA9052_CHIPID_REG                      129
+#define DA9052_CONFIGID_REG                    130
+#define DA9052_OTPCONT_REG                     131
+#define DA9052_OSCTRIM_REG                     132
+#define DA9052_GPID0_REG                       133
+#define DA9052_GPID1_REG                       134
+#define DA9052_GPID2_REG                       135
+#define DA9052_GPID3_REG                       136
+#define DA9052_GPID4_REG                       137
+#define DA9052_GPID5_REG                       138
+#define DA9052_GPID6_REG                       139
+#define DA9052_GPID7_REG                       140
+#define DA9052_GPID8_REG                       141
+#define DA9052_GPID9_REG                       142
+
+#define DA9052_PAGE0_REG_START                 (DA9052_STATUSA_REG)
+#define DA9052_PAGE0_REG_END                   (DA9052_SECONDD_REG)
+
+#define DA9052_PAGE1_REG_START                 (DA9052_CHIPID_REG)
+#define DA9052_PAGE1_REG_END                   (DA9052_GPID9_REG)
+
+/* PAGE CONFIGURATION */
+
+/* Reg Page Configuration */
+#define DA9052_PAGECON0_REGPAGE                        (1<<7)
+
+/* PAGE CONFIGURATION 128 REGISTER */
+#define DA9052_PAGECON128_REGPAGE              (1<<7)
+
+/* SYSTEM REGISTER */
+
+/* STATUS REGISTER A */
+#define DA9052_STATUSA_VDATDET                 (1<<7)
+#define DA9052_STATUSA_VBUSSEL                 (1<<6)
+#define DA9052_STATUSA_DCINSEL                 (1<<5)
+#define DA9052_STATUSA_VBUSDET                 (1<<4)
+#define DA9052_STATUSA_DCINDET                 (1<<3)
+#define DA9052_STATUSA_IDGND                   (1<<2)
+#define DA9052_STATUSA_IDFLOAT                 (1<<1)
+#define DA9052_STATUSA_NONKEY                  (1<<0)
+
+
+/* STATUS REGISTER B */
+#define DA9052_STATUSB_COMPDET                 (1<<7)
+#define DA9052_STATUSB_SEQUENCING              (1<<6)
+#define DA9052_STATUSB_GPFB2                   (1<<5)
+#define DA9052_STATUSB_CHGTO                   (1<<4)
+#define DA9052_STATUSB_CHGEND                  (1<<3)
+#define DA9052_STATUSB_CHGLIM                  (1<<2)
+#define DA9052_STATUSB_CHGPRE                  (1<<1)
+#define DA9052_STATUSB_CHGATT                  (1<<0)
+
+
+/* STATUS REGISTER C */
+#define DA9052_STATUSC_GPI7                    (1<<7)
+#define DA9052_STATUSC_GPI6                    (1<<6)
+#define DA9052_STATUSC_GPI5                    (1<<5)
+#define DA9052_STATUSC_GPI4                    (1<<4)
+#define DA9052_STATUSC_GPI3                    (1<<3)
+#define DA9052_STATUSC_GPI2                    (1<<2)
+#define DA9052_STATUSC_GPI1                    (1<<1)
+#define DA9052_STATUSC_GPI0                    (1<<0)
+
+
+/* STATUS REGISTER D */
+#define DA9052_STATUSD_GPI15                   (1<<7)
+#define DA9052_STATUSD_GPI14                   (1<<6)
+#define DA9052_STATUSD_GPI13                   (1<<5)
+#define DA9052_STATUSD_GPI12                   (1<<4)
+#define DA9052_STATUSD_GPI11                   (1<<3)
+#define DA9052_STATUSD_GPI10                   (1<<2)
+#define DA9052_STATUSD_GPI9                    (1<<1)
+#define DA9052_STATUSD_GPI8                    (1<<0)
+
+
+/* EVENT REGISTER A */
+#define DA9052_EVENTA_ECOMP1V2                 (1<<7)
+#define DA9052_EVENTA_ESEQRDY                  (1<<6)
+#define DA9052_EVENTA_EALRAM                   (1<<5)
+#define DA9052_EVENTA_EVDDLOW                  (1<<4)
+#define DA9052_EVENTA_EVBUSREM                 (1<<3)
+#define DA9052_EVENTA_EDCINREM                 (1<<2)
+#define DA9052_EVENTA_EVBUSDET                 (1<<1)
+#define DA9052_EVENTA_EDCINDET                 (1<<0)
+
+/* EVENT REGISTER B */
+#define DA9052_EVENTB_ETSIREADY                        (1<<7)
+#define DA9052_EVENTB_EPENDOWN                 (1<<6)
+#define DA9052_EVENTB_EADCEOM                  (1<<5)
+#define DA9052_EVENTB_ETBAT                    (1<<4)
+#define DA9052_EVENTB_ECHGEND                  (1<<3)
+#define DA9052_EVENTB_EIDGND                   (1<<2)
+#define DA9052_EVENTB_EIDFLOAT                 (1<<1)
+#define DA9052_EVENTB_ENONKEY                  (1<<0)
+
+/* EVENT REGISTER C */
+#define DA9052_EVENTC_EGPI7                    (1<<7)
+#define DA9052_EVENTC_EGPI6                    (1<<6)
+#define DA9052_EVENTC_EGPI5                    (1<<5)
+#define DA9052_EVENTC_EGPI4                    (1<<4)
+#define DA9052_EVENTC_EGPI3                    (1<<3)
+#define DA9052_EVENTC_EGPI2                    (1<<2)
+#define DA9052_EVENTC_EGPI1                    (1<<1)
+#define DA9052_EVENTC_EGPI0                    (1<<0)
+
+/* EVENT REGISTER D */
+#define DA9052_EVENTC_EGPI15                   (1<<7)
+#define DA9052_EVENTC_EGPI14                   (1<<6)
+#define DA9052_EVENTC_EGPI13                   (1<<5)
+#define DA9052_EVENTC_EGPI12                   (1<<4)
+#define DA9052_EVENTC_EGPI11                   (1<<3)
+#define DA9052_EVENTC_EGPI10                   (1<<2)
+#define DA9052_EVENTC_EGPI9                    (1<<1)
+#define DA9052_EVENTC_EGPI8                    (1<<0)
+
+
+/* FAULT LOG REGISTER */
+#define DA9052_FAULTLOG_WAITSET                        (1<<7)
+#define DA9052_FAULTLOG_NSDSET                 (1<<6)
+#define DA9052_FAULTLOG_KEYSHUT                        (1<<5)
+#define DA9052_FAULTLOG_TEMPOVER               (1<<3)
+#define DA9052_FAULTLOG_VDDSTART               (1<<2)
+#define DA9052_FAULTLOG_VDDFAULT               (1<<1)
+#define DA9052_FAULTLOG_TWDERROR               (1<<0)
+
+/* IRQ_MASK REGISTER A */
+#define DA9052_IRQMASKA_MCOMP1V2               (1<<7)
+#define DA9052_IRQMASKA_MSEQRDY                        (1<<6)
+#define DA9052_IRQMASKA_MALRAM                 (1<<5)
+#define DA9052_IRQMASKA_MVDDLOW                        (1<<4)
+#define DA9052_IRQMASKA_MVBUSREM               (1<<3)
+#define DA9052_IRQMASKA_MDCINREM               (1<<2)
+#define DA9052_IRQMASKA_MVBUSVLD               (1<<1)
+#define DA9052_IRQMASKA_MDCINVLD               (1<<0)
+
+/* IRQ_MASK REGISTER B */
+#define DA9052_IRQMASKB_MTSIREADY              (1<<7)
+#define DA9052_IRQMASKB_MPENDOWN               (1<<6)
+#define DA9052_IRQMASKB_MADCEOM                        (1<<5)
+#define DA9052_IRQMASKB_MTBAT                  (1<<4)
+#define DA9052_IRQMASKB_MCHGEND                        (1<<3)
+#define DA9052_IRQMASKB_MIDGND                 (1<<2)
+#define DA9052_IRQMASKB_MIDFLOAT               (1<<1)
+#define DA9052_IRQMASKB_MNONKEY                        (1<<0)
+
+/* IRQ_MASK REGISTER C */
+#define DA9052_IRQMASKC_MGPI7                  (1<<7)
+#define DA9052_IRQMASKC_MGPI6                  (1<<6)
+#define DA9052_IRQMASKC_MGPI5                  (1<<5)
+#define DA9052_IRQMASKC_MGPI4                  (1<<4)
+#define DA9052_IRQMASKC_MGPI3                  (1<<3)
+#define DA9052_IRQMASKC_MGPI2                  (1<<2)
+#define DA9052_IRQMASKC_MGPI1                  (1<<1)
+#define DA9052_IRQMASKC_MGPI0                  (1<<0)
+
+/* IRQ_MASK REGISTER D */
+#define DA9052_IRQMASKD_MGPI15                 (1<<7)
+#define DA9052_IRQMASKD_MGPI14                 (1<<6)
+#define DA9052_IRQMASKD_MGPI13                 (1<<5)
+#define DA9052_IRQMASKD_MGPI12                 (1<<4)
+#define DA9052_IRQMASKD_MGPI11                 (1<<3)
+#define DA9052_IRQMASKD_MGPI10                 (1<<2)
+#define DA9052_IRQMASKD_MGPI9                  (1<<1)
+#define DA9052_IRQMASKD_MGPI8                  (1<<0)
+
+/* CONTROL REGISTER A */
+#define DA9052_CONTROLA_GPIV                   (1<<7)
+#define DA9052_CONTROLA_PMOTYPE                        (1<<5)
+#define DA9052_CONTROLA_PMOV                   (1<<4)
+#define DA9052_CONTROLA_PMIV                   (1<<3)
+#define DA9052_CONTROLA_PMIFV                  (1<<3)
+#define DA9052_CONTROLA_PWR1EN                 (1<<2)
+#define DA9052_CONTROLA_PWREN                  (1<<1)
+#define DA9052_CONTROLA_SYSEN                  (1<<0)
+
+/* CONTROL REGISTER B */
+#define DA9052_CONTROLB_SHUTDOWN               (1<<7)
+#define DA9052_CONTROLB_DEEPSLEEP              (1<<6)
+#define DA9052_CONTROLB_WRITEMODE              (1<<5)
+#define DA9052_CONTROLB_BBATEN                 (1<<4)
+#define DA9052_CONTROLB_OTPREADEN              (1<<3)
+#define DA9052_CONTROLB_AUTOBOOT               (1<<2)
+#define DA9052_CONTROLB_ACTDIODE               (1<<1)
+#define DA9052_CONTROLB_BUCKMERGE              (1<<0)
+
+/* CONTROL REGISTER C */
+#define DA9052_CONTROLC_BLINKDUR               (1<<7)
+#define DA9052_CONTROLC_BLINKFRQ               (3<<5)
+#define DA9052_CONTROLC_DEBOUNCING             (7<<2)
+#define DA9052_CONTROLC_PMFB2PIN               (1<<1)
+#define DA9052_CONTROLC_PMFB1PIN               (1<<0)
+
+/* CONTROL REGISTER D */
+#define DA9052_CONTROLD_WATCHDOG               (1<<7)
+#define DA9052_CONTROLD_ACCDETEN               (1<<6)
+#define DA9052_CONTROLD_GPI1415SD              (1<<5)
+#define DA9052_CONTROLD_NONKEYSD               (1<<4)
+#define DA9052_CONTROLD_KEEPACTEN              (1<<3)
+#define DA9052_CONTROLD_TWDSCALE               (7<<0)
+
+/* POWER DOWN DISABLE REGISTER */
+#define DA9052_PDDIS_PMCONTPD                  (1<<7)
+#define DA9052_PDDIS_OUT32KPD                  (1<<6)
+#define DA9052_PDDIS_CHGBBATPD                 (1<<5)
+#define DA9052_PDDIS_CHGPD                     (1<<4)
+#define DA9052_PDDIS_HS2WIREPD                 (1<<3)
+#define DA9052_PDDIS_PMIFPD                    (1<<2)
+#define DA9052_PDDIS_GPADCPD                   (1<<1)
+#define DA9052_PDDIS_GPIOPD                    (1<<0)
+
+/* CONTROL REGISTER D */
+#define DA9052_INTERFACE_IFBASEADDR            (7<<5)
+#define DA9052_INTERFACE_NCSPOL                        (1<<4)
+#define DA9052_INTERFACE_RWPOL                 (1<<3)
+#define DA9052_INTERFACE_CPHA                  (1<<2)
+#define DA9052_INTERFACE_CPOL                  (1<<1)
+#define DA9052_INTERFACE_IFTYPE                        (1<<0)
+
+/* CONTROL REGISTER D */
+#define DA9052_RESET_RESETEVENT                        (3<<6)
+#define DA9052_RESET_RESETTIMER                        (63<<0)
+
+/* GPIO REGISTERS */
+
+/* GPIO control register for PIN 0 and 1 */
+#define DA9052_GPIO0001_GPIO1MODE              (1<<7)
+#define DA9052_GPIO0001_GPIO1TYPE              (1<<6)
+#define DA9052_GPIO0001_GPIO1PIN               (3<<4)
+#define DA9052_GPIO0001_GPIO0MODE              (1<<3)
+#define DA9052_GPIO0001_GPIO0TYPE              (1<<2)
+#define DA9052_GPIO0001_GPIO0PIN               (3<<0)
+
+/* GPIO control register for PIN 2 and 3 */
+#define DA9052_GPIO0203_GPIO3MODE              (1<<7)
+#define DA9052_GPIO0203_GPIO3TYPE              (1<<6)
+#define DA9052_GPIO0203_GPIO3PIN               (3<<4)
+#define DA9052_GPIO0203_GPIO2MODE              (1<<3)
+#define DA9052_GPIO0203_GPIO2TYPE              (1<<2)
+#define DA9052_GPIO0203_GPIO2PIN               (3<<0)
+
+/* GPIO control register for PIN 4 and 5 */
+#define DA9052_GPIO0405_GPIO5MODE              (1<<7)
+#define DA9052_GPIO0405_GPIO5TYPE              (1<<6)
+#define DA9052_GPIO0405_GPIO5PIN               (3<<4)
+#define DA9052_GPIO0405_GPIO4MODE              (1<<3)
+#define DA9052_GPIO0405_GPIO4TYPE              (1<<2)
+#define DA9052_GPIO0405_GPIO4PIN               (3<<0)
+
+/* GPIO control register for PIN 6 and 7 */
+#define DA9052_GPIO0607_GPIO7MODE              (1<<7)
+#define DA9052_GPIO0607_GPIO7TYPE              (1<<6)
+#define DA9052_GPIO0607_GPIO7PIN               (3<<4)
+#define DA9052_GPIO0607_GPIO6MODE              (1<<3)
+#define DA9052_GPIO0607_GPIO6TYPE              (1<<2)
+#define DA9052_GPIO0607_GPIO6PIN               (3<<0)
+
+/* GPIO control register for PIN 8 and 9 */
+#define DA9052_GPIO0809_GPIO9MODE              (1<<7)
+#define DA9052_GPIO0809_GPIO9TYPE              (1<<6)
+#define DA9052_GPIO0809_GPIO9PIN               (3<<4)
+#define DA9052_GPIO0809_GPIO8MODE              (1<<3)
+#define DA9052_GPIO0809_GPIO8TYPE              (1<<2)
+#define DA9052_GPIO0809_GPIO8PIN               (3<<0)
+
+/* GPIO control register for PIN 10 and 11 */
+#define DA9052_GPIO1011_GPIO11MODE             (1<<7)
+#define DA9052_GPIO1011_GPIO11TYPE             (1<<6)
+#define DA9052_GPIO1011_GPIO11PIN              (3<<4)
+#define DA9052_GPIO1011_GPIO10MODE             (1<<3)
+#define DA9052_GPIO1011_GPIO10TYPE             (1<<2)
+#define DA9052_GPIO1011_GPIO10PIN              (3<<0)
+
+/* GPIO control register for PIN 12 and 13 */
+#define DA9052_GPIO1213_GPIO13MODE             (1<<7)
+#define DA9052_GPIO1213_GPIO13TYPE             (1<<6)
+#define DA9052_GPIO1213_GPIO13PIN              (3<<4)
+#define DA9052_GPIO1213_GPIO12MODE             (1<<3)
+#define DA9052_GPIO1213_GPIO12TYPE             (1<<2)
+#define DA9052_GPIO1213_GPIO12PIN              (3<<0)
+
+/* GPIO control register for PIN 14 and 15 */
+#define DA9052_GPIO1415_GPIO15MODE             (1<<7)
+#define DA9052_GPIO1415_GPIO15TYPE             (1<<6)
+#define DA9052_GPIO1415_GPIO15PIN              (3<<4)
+#define DA9052_GPIO1415_GPIO14MODE             (1<<3)
+#define DA9052_GPIO1415_GPIO14TYPE             (1<<2)
+#define DA9052_GPIO1415_GPIO14PIN              (3<<0)
+
+/*POWER SEQUENCER REGISTER*/
+
+/* SEQ control register for ID 0 and 1 */
+#define DA9052_ID01_LDO1STEP                   (15<<4)
+#define DA9052_ID01_SYSPRE                     (1<<2)
+#define DA9052_ID01_DEFSUPPLY                  (1<<1)
+#define DA9052_ID01_nRESMODE                   (1<<0)
+
+/* SEQ control register for ID 2 and 3 */
+#define DA9052_ID23_LDO3STEP                   (15<<4)
+#define DA9052_ID23_LDO2STEP                   (15<<0)
+
+/* SEQ control register for ID 4 and 5 */
+#define DA9052_ID45_LDO5STEP                   (15<<4)
+#define DA9052_ID45_LDO4STEP                   (15<<0)
+
+/* SEQ control register for ID 6 and 7 */
+#define DA9052_ID67_LDO7STEP                   (15<<4)
+#define DA9052_ID67_LDO6STEP                   (15<<0)
+
+/* SEQ control register for ID 8 and 9 */
+#define DA9052_ID89_LDO9STEP                   (15<<4)
+#define DA9052_ID89_LDO8STEP                   (15<<0)
+
+/* SEQ control register for ID 10 and 11 */
+#define DA9052_ID1011_PDDISSTEP                        (15<<4)
+#define DA9052_ID1011_LDO10STEP                        (15<<0)
+
+/* SEQ control register for ID 12 and 13 */
+#define DA9052_ID1213_VMEMSWSTEP               (15<<4)
+#define DA9052_ID1213_VPERISWSTEP              (15<<0)
+
+/* SEQ control register for ID 14 and 15 */
+#define DA9052_ID1415_BUCKPROSTEP              (15<<4)
+#define DA9052_ID1415_BUCKCORESTEP             (15<<0)
+
+/* SEQ control register for ID 16 and 17 */
+#define DA9052_ID1617_BUCKPERISTEP             (15<<4)
+#define DA9052_ID1617_BUCKMEMSTEP              (15<<0)
+
+/* SEQ control register for ID 18 and 19 */
+#define DA9052_ID1819_GPRISE2STEP              (15<<4)
+#define DA9052_ID1819_GPRISE1STEP              (15<<0)
+
+/* SEQ control register for ID 20 and 21 */
+#define DA9052_ID2021_GPFALL2STEP              (15<<4)
+#define DA9052_ID2021_GPFALL1STEP              (15<<0)
+
+/* Power SEQ Status register */
+#define DA9052_SEQSTATUS_SEQPOINTER            (15<<4)
+#define DA9052_SEQSTATUS_WAITSTEP              (15<<0)
+
+/* Power SEQ A register */
+#define DA9052_SEQA_POWEREND                   (15<<4)
+#define DA9052_SEQA_SYSTEMEND                  (15<<0)
+
+/* Power SEQ B register */
+#define DA9052_SEQB_PARTDOWN                   (15<<4)
+#define DA9052_SEQB_MAXCOUNT                   (15<<0)
+
+/* Power SEQ TIMER register */
+#define DA9052_SEQTIMER_SEQDUMMY               (15<<4)
+#define DA9052_SEQTIMER_SEQTIME                        (15<<0)
+
+/*POWER SUPPLY CONTROL REGISTER*/
+
+/* BUCK REGISTER A */
+#define DA9052_BUCKA_BPROILIM                  (3<<6)
+#define DA9052_BUCKA_BPROMODE                  (3<<4)
+#define DA9052_BUCKA_BCOREILIM                 (3<<2)
+#define DA9052_BUCKA_BCOREMODE                 (3<<0)
+
+/* BUCK REGISTER B */
+#define DA9052_BUCKB_BERIILIM                  (3<<6)
+#define DA9052_BUCKB_BPERIMODE                 (3<<4)
+#define DA9052_BUCKB_BMEMILIM                  (3<<2)
+#define DA9052_BUCKB_BMEMMODE                  (3<<0)
+
+/* BUCKCORE REGISTER */
+#define DA9052_BUCKCORE_BCORECONF              (1<<7)
+#define DA9052_BUCKCORE_BCOREEN                        (1<<6)
+#define DA9052_BUCKCORE_VBCORE                 (63<<0)
+
+/* BUCKPRO REGISTER */
+#define DA9052_BUCKPRO_BPROCONF                        (1<<7)
+#define DA9052_BUCKPRO_BPROEN                  (1<<6)
+#define DA9052_BUCKPRO_VBPRO                   (63<<0)
+
+/* BUCKMEM REGISTER */
+#define DA9052_BUCKMEM_BMEMCONF                        (1<<7)
+#define DA9052_BUCKMEM_BMEMEN                  (1<<6)
+#define DA9052_BUCKMEM_VBMEM                   (63<<0)
+
+/* BUCKPERI REGISTER */
+#define DA9052_BUCKPERI_BPERICONF              (1<<7)
+#define DA9052_BUCKPERI_BPERIEN                        (1<<6)
+#if defined (CONFIG_PMIC_DA9052)
+#define DA9052_BUCKPERI_BPERIHS                        (1<<5)
+#define DA9052_BUCKPERI_VBPERI                 (31<<0)
+#elif defined (CONFIG_PMIC_DA9053AA) || (CONFIG_PMIC_DA9053Bx)
+#define DA9052_BUCKPERI_VBPERI                 (63<<0)
+#endif
+
+/* LDO1 REGISTER */
+#define DA9052_LDO1_LDO1CONF                   (1<<7)
+#define DA9052_LDO1_LDO1EN                     (1<<6)
+#define DA9052_LDO1_VLDO1                      (31<<0)
+
+/* LDO2 REGISTER */
+#define DA9052_LDO2_LDO2CONF                   (1<<7)
+#define DA9052_LDO2_LDO2EN                     (1<<6)
+#define DA9052_LDO2_VLDO2                      (63<<0)
+
+/* LDO3 REGISTER */
+#define DA9052_LDO3_LDO3CONF                   (1<<7)
+#define DA9052_LDO3_LDO3EN                     (1<<6)
+#define DA9052_LDO3_VLDO3                      (63<<0)
+
+/* LDO4 REGISTER */
+#define DA9052_LDO4_LDO4CONF                   (1<<7)
+#define DA9052_LDO4_LDO4EN                     (1<<6)
+#define DA9052_LDO4_VLDO4                      (63<<0)
+
+/* LDO5 REGISTER */
+#define DA9052_LDO5_LDO5CONF                   (1<<7)
+#define DA9052_LDO5_LDO5EN                     (1<<6)
+#define DA9052_LDO5_VLDO5                      (63<<0)
+
+/* LDO6 REGISTER */
+#define DA9052_LDO6_LDO6CONF                   (1<<7)
+#define DA9052_LDO6_LDO6EN                     (1<<6)
+#define DA9052_LDO6_VLDO6                      (63<<0)
+
+/* LDO7 REGISTER */
+#define DA9052_LDO7_LDO7CONF                   (1<<7)
+#define DA9052_LDO7_LDO7EN                     (1<<6)
+#define DA9052_LDO7_VLDO7                      (63<<0)
+
+/* LDO8 REGISTER */
+#define DA9052_LDO8_LDO8CONF                   (1<<7)
+#define DA9052_LDO8_LDO8EN                     (1<<6)
+#define DA9052_LDO8_VLDO8                      (63<<0)
+
+/* LDO9 REGISTER */
+#define DA9052_LDO9_LDO9CONF                   (1<<7)
+#define DA9052_LDO9_LDO9EN                     (1<<6)
+#define DA9052_LDO9_VLDO9                      (63<<0)
+
+/* LDO10 REGISTER */
+#define DA9052_LDO10_LDO10CONF                 (1<<7)
+#define DA9052_LDO10_LDO10EN                   (1<<6)
+#define DA9052_LDO10_VLDO10                    (63<<0)
+
+/* SUPPLY REGISTER */
+#define DA9052_SUPPLY_VLOCK                    (1<<7)
+#define DA9052_SUPPLY_VMEMSWEN                 (1<<6)
+#define DA9052_SUPPLY_VPERISWEN                        (1<<5)
+#define DA9052_SUPPLY_VLDO3GO                  (1<<4)
+#define DA9052_SUPPLY_VLDO2GO                  (1<<3)
+#define DA9052_SUPPLY_VBMEMGO                  (1<<2)
+#define DA9052_SUPPLY_VBPROGO                  (1<<1)
+#define DA9052_SUPPLY_VBCOREGO                 (1<<0)
+
+/* PULLDOWN REGISTER */
+#define DA9052_PULLDOWN_LDO5PDDIS              (1<<5)
+#define DA9052_PULLDOWN_LDO2PDDIS              (1<<4)
+#define DA9052_PULLDOWN_LDO1PDDIS              (1<<3)
+#define DA9052_PULLDOWN_MEMPDDIS               (1<<2)
+#define DA9052_PULLDOWN_PROPDDIS               (1<<1)
+#define DA9052_PULLDOWN_COREPDDIS              (1<<0)
+
+/* BAT CHARGER REGISTER */
+
+/* CHARGER BUCK REGISTER */
+#define DA9052_CHGBUCK_CHGTEMP                 (1<<7)
+#define DA9052_CHGBUCK_CHGUSBILIM              (1<<6)
+#define DA9052_CHGBUCK_CHGBUCKLP               (1<<5)
+#define DA9052_CHGBUCK_CHGBUCKEN               (1<<4)
+#define DA9052_CHGBUCK_ISETBUCK                        (15<<0)
+
+/* WAIT COUNTER REGISTER */
+#define DA9052_WAITCONT_WAITDIR                        (1<<7)
+#define DA9052_WAITCONT_RTCCLOCK               (1<<6)
+#define DA9052_WAITCONT_WAITMODE               (1<<5)
+#define DA9052_WAITCONT_EN32KOUT               (1<<4)
+#define DA9052_WAITCONT_DELAYTIME              (15<<0)
+
+/* ISET CONTROL REGISTER */
+#define DA9052_ISET_ISETDCIN                   (15<<4)
+#define DA9052_ISET_ISETVBUS                   (15<<0)
+
+/* BATTERY CHARGER CONTROL REGISTER */
+#define DA9052_BATCHG_ICHGPRE                  (3<<6)
+#define DA9052_BATCHG_ICHGBAT                  (63<<0)
+
+/* CHARGER COUNTER REGISTER */
+#define DA9052_CHGCONT_VCHGBAT                 (31<<3)
+#define DA9052_CHGCONT_TCTR                    (7<<0)
+
+/* INPUT CONTROL REGISTER */
+#define DA9052_INPUTCONT_TCTRMODE              (1<<7)
+#define DA9052_INPUTCONT_ICHGLOW               (1<<5)
+#define DA9052_INPUTCONT_VBUSSUSP              (1<<4)
+#define DA9052_INPUTCONT_DCINSUSP              (1<<3)
+#define DA9052_INPUTCONT_VCHGTHR               (7<<0)
+
+/* CHARGING TIME REGISTER */
+#define DA9052_CHGTIME_CHGTIME                 (255<<0)
+
+/* BACKUP BATTERY CONTROL REGISTER */
+#define DA9052_BBATCONT_BCHARGERISET           (15<<4)
+#define DA9052_BBATCONT_BCHARGERVSET           (15<<0)
+
+/* LED REGISTERS */
+
+/* LED BOOST REGISTER */
+#define DA9052_BOOST_EBFAULT                   (1<<7)
+#define DA9052_BOOST_MBFAULT                   (1<<6)
+#define DA9052_BOOST_BOOSTFRQ                  (1<<5)
+#define DA9052_BOOST_BOOSTILIM                 (1<<4)
+#define DA9052_BOOST_LED3INEN                  (1<<3)
+#define DA9052_BOOST_LED2INEN                  (1<<2)
+#define DA9052_BOOST_LED1INEN                  (1<<1)
+#define DA9052_BOOST_BOOSTEN                   (1<<0)
+
+/* LED COUNT REGISTER */
+#if defined (CONFIG_PMIC_DA9053Bx)
+#define DA9052_LEDCONT_SELLEDMODE              (1<<7)
+#endif
+#define DA9052_LEDCONT_LED3ICONT               (1<<6)
+#define DA9052_LEDCONT_LED3RAMP                        (1<<5)
+#define DA9052_LEDCONT_LED3EN                  (1<<4)
+#define DA9052_LEDCONT_LED2RAMP                        (1<<3)
+#define DA9052_LEDCONT_LED2EN                  (1<<2)
+#define DA9052_LEDCONT_LED1RAMP                        (1<<1)
+#define DA9052_LEDCONT_LED1EN                  (1<<0)
+
+/* LEDMIN123  REGISTER */
+#define DA9052_LEDMIN123_LEDMINCURRENT         (255<<0)
+
+/* LED1CONF  REGISTER */
+#define DA9052_LED1CONF_LED1CURRENT            (255<<0)
+
+/* LED2CONF  REGISTER */
+#define DA9052_LED2CONF_LED2CURRENT            (255<<0)
+
+/* LED3CONF  REGISTER */
+#define DA9052_LED3CONF_LED3CURRENT            (255<<0)
+
+/* LED1 COUNT  REGISTER */
+#define DA9052_LED1CONT_LED1DIM                        (1<<7)
+#define DA9052_LED1CONT_LED1PWM                        (127<<0)
+
+/* LED2 COUNT  REGISTER */
+#define DA9052_LED2CONT_LED2DIM                        (1<<7)
+#define DA9052_LED2CONT_LED2PWM                        (127<<0)
+
+/* LED3 COUNT  REGISTER */
+#define DA9052_LED3CONT_LED3DIM                        (1<<7)
+#define DA9052_LED3CONT_LED3PWM                        (127<<0)
+
+/* LED4 COUNT  REGISTER */
+#define DA9052_LED4CONT_LED4DIM                        (1<<7)
+#define DA9052_LED4CONT_LED4PWM                        (127<<0)
+
+/* LED5 COUNT  REGISTER */
+#define DA9052_LED5CONT_LED5DIM                        (1<<7)
+#define DA9052_LED5CONT_LED5PWM                        (127<<0)
+
+/* ADC REGISTERS */
+
+/* ADC MAN registers */
+#define DA9052_ADCMAN_MANCONV                  (1<<4)
+#define DA9052_ADCMAN_MUXSEL                   (15<<0)
+
+/* ADC COUNT regsisters */
+#define DA9052_ADCCONT_COMP1V2EN               (1<<7)
+#define DA9052_ADCCONT_ADCMODE                 (1<<6)
+#define DA9052_ADCCONT_TBATISRCEN              (1<<5)
+#define DA9052_ADCCONT_AD4ISRCEN               (1<<4)
+#define DA9052_ADCCONT_AUTOAD6EN               (1<<3)
+#define DA9052_ADCCONT_AUTOAD5EN               (1<<2)
+#define DA9052_ADCCONT_AUTOAD4EN               (1<<1)
+#define DA9052_ADCCONT_AUTOVDDEN               (1<<0)
+
+/* ADC 10 BIT MANUAL CONVERSION RESULT LOW register */
+#define DA9052_ADCRESL_ADCRESLSB               (3<<0)
+
+/* ADC 10 BIT MANUAL CONVERSION RESULT HIGH register */
+#define DA9052_ADCRESH_ADCRESMSB               (255<<0)
+
+/* VDD RES regsister*/
+#define DA9052_VDDRES_VDDOUTRES                        (255<<0)
+
+/* VDD MON regsister*/
+#define DA9052_VDDMON_VDDOUTMON                        (255<<0)
+
+/* ICHG_AV regsister*/
+#define DA9052_ICHGAV_ICHGAV                   (255<<0)
+
+/* ICHG_THD regsister*/
+#define DA9052_ICHGTHD_ICHGTHD                 (255<<0)
+
+/* ICHG_END regsister*/
+#define DA9052_ICHGEND_ICHGEND                 (255<<0)
+
+/* TBAT_RES regsister*/
+#define DA9052_TBATRES_TBATRES                 (255<<0)
+
+/* TBAT_HIGHP regsister*/
+#define DA9052_TBATHIGHP_TBATHIGHP             (255<<0)
+
+/* TBAT_HIGHN regsister*/
+#define DA9052_TBATHIGHN_TBATHIGHN             (255<<0)
+
+/* TBAT_LOW regsister*/
+#define DA9052_TBATLOW_TBATLOW                 (255<<0)
+
+/* T_OFFSET regsister*/
+#define DA9052_TOFFSET_TOFFSET                 (255<<0)
+
+/* ADCIN4_RES regsister*/
+#define DA9052_ADCIN4RES_ADCIN4RES             (255<<0)
+
+/* ADCIN4_HIGH regsister*/
+#define DA9052_AUTO4HIGH_AUTO4HIGH             (255<<0)
+
+/* ADCIN4_LOW regsister*/
+#define DA9052_AUTO4LOW_AUTO4LOW               (255<<0)
+
+/* ADCIN5_RES regsister*/
+#define DA9052_ADCIN5RES_ADCIN5RES             (255<<0)
+
+/* ADCIN5_HIGH regsister*/
+#define DA9052_AUTO5HIGH_AUTOHIGH              (255<<0)
+
+/* ADCIN5_LOW regsister*/
+#define DA9052_AUTO5LOW_AUTO5LOW               (255<<0)
+
+/* ADCIN6_RES regsister*/
+#define DA9052_ADCIN6RES_ADCIN6RES             (255<<0)
+
+/* ADCIN6_HIGH regsister*/
+#define DA9052_AUTO6HIGH_AUTO6HIGH             (255<<0)
+
+/* ADCIN6_LOW regsister*/
+#define DA9052_AUTO6LOW_AUTO6LOW               (255<<0)
+
+/* TJUNC_RES regsister*/
+#define DA9052_TJUNCRES_TJUNCRES               (255<<0)
+
+/* TSI REGISTER */
+
+/* TSI Control Register A */
+#define DA9052_TSICONTA_TSIDELAY               (3<<6)
+#define DA9052_TSICONTA_TSISKIP                        (7<<3)
+#define DA9052_TSICONTA_TSIMODE                        (1<<2)
+#define DA9052_TSICONTA_PENDETEN               (1<<1)
+#define DA9052_TSICONTA_AUTOTSIEN              (1<<0)
+
+/* TSI Control Register B */
+#define DA9052_TSICONTB_ADCREF                 (1<<7)
+#define DA9052_TSICONTB_TSIMAN                 (1<<6)
+#define DA9052_TSICONTB_TSIMUX                 (3<<4)
+#define DA9052_TSICONTB_TSISEL3                        (1<<3)
+#define DA9052_TSICONTB_TSISEL2                        (1<<2)
+#define DA9052_TSICONTB_TSISEL1                        (1<<1)
+#define DA9052_TSICONTB_TSISEL0                        (1<<0)
+
+/* TSI X Co-ordinate MSB Result register */
+#define DA9052_TSIXMSB_TSIXM                   (255<<0)
+
+/* TSI Y Co-ordinate MSB Result register */
+#define DA9052_TSIYMSB_TSIYM                   (255<<0)
+
+/* TSI Co-ordinate LSB Result register */
+#define DA9052_TSILSB_PENDOWN                  (1<<6)
+#define DA9052_TSILSB_TSIZL                    (3<<4)
+#define DA9052_TSILSB_TSIYL                    (3<<2)
+#define DA9052_TSILSB_TSIXL                    (3<<0)
+
+/* TSI Z Measurement MSB Result register */
+#define DA9052_TSIZMSB_TSIZM                   (255<<0)
+
+/* RTC REGISTER */
+
+/* RTC TIMER SECONDS REGISTER */
+#define DA9052_COUNTS_MONITOR                  (1<<6)
+#define DA9052_COUNTS_COUNTSEC                 (63<<0)
+
+/* RTC TIMER MINUTES REGISTER */
+#define DA9052_COUNTMI_COUNTMIN                        (63<<0)
+
+/* RTC TIMER HOUR REGISTER */
+#define DA9052_COUNTH_COUNTHOUR                        (31<<0)
+
+/* RTC TIMER DAYS REGISTER */
+#define DA9052_COUNTD_COUNTDAY                 (31<<0)
+
+/* RTC TIMER MONTHS REGISTER */
+#define DA9052_COUNTMO_COUNTMONTH              (15<<0)
+
+/* RTC TIMER YEARS REGISTER */
+#define DA9052_COUNTY_COUNTYEAR                        (63<<0)
+
+/* RTC ALARM MINUTES REGISTER */
+#define DA9052_ALARMMI_TICKTYPE                        (1<<7)
+#define DA9052_ALARMMI_ALARMTYPE               (1<<6)
+#define DA9052_ALARMMI_ALARMMIN                        (63<<0)
+
+/* RTC ALARM HOURS REGISTER */
+#define DA9052_ALARMH_ALARMHOUR                        (31<<0)
+
+/* RTC ALARM DAYS REGISTER */
+#define DA9052_ALARMD_ALARMDAY                 (31<<0)
+
+/* RTC ALARM MONTHS REGISTER */
+#define DA9052_ALARMMO_ALARMMONTH              (15<<0)
+
+/* RTC ALARM YEARS REGISTER */
+#define DA9052_ALARMY_TICKON                   (1<<7)
+#define DA9052_ALARMY_ALARMON                  (1<<6)
+#define DA9052_ALARMY_ALARMYEAR                        (63<<0)
+
+/* RTC SECONDS REGISTER  A*/
+#define DA9052_SECONDA_SECONDSA                        (255<<0)
+
+/* RTC SECONDS REGISTER  B*/
+#define DA9052_SECONDB_SECONDSB                        (255<<0)
+
+/* RTC SECONDS REGISTER  C*/
+#define DA9052_SECONDC_SECONDSC                        (255<<0)
+
+/* RTC SECONDS REGISTER  D*/
+#define DA9052_SECONDD_SECONDSD                        (255<<0)
+
+/* OTP REGISTER */
+
+/* CHIP IDENTIFICATION REGISTER */
+#define DA9052_CHIPID_MRC                      (15<<4)
+#define DA9052_CHIPID_TRC                      (15<<0)
+
+/* CONFIGURATION IDENTIFICATION REGISTER */
+#define DA9052_CONFIGID_CUSTOMERID             (31<<3)
+#define DA9052_CONFIGID_CONFID                 (7<<0)
+
+/* OTP CONTROL REGISTER */
+#define DA9052_OTPCONT_GPWRITEDIS              (1<<7)
+#define DA9052_OTPCONT_OTPCONFLOCK             (1<<6)
+#define DA9052_OTPCONT_OTPGPLOCK               (1<<5)
+#define DA9052_OTPCONT_OTPCONFG                        (1<<3)
+#define DA9052_OTPCONT_OTPGP                   (1<<2)
+#define DA9052_OTPCONT_OTPRP                   (1<<1)
+#define DA9052_OTPCONT_OTPTRANSFER             (1<<0)
+
+/* RTC OSCILLATOR TRIM REGISTER */
+#define DA9052_OSCTRIM_TRIM32K                 (255<<0)
+
+/* GP ID REGISTER 0 */
+#define DA9052_GPID0_GP0                       (255<<0)
+
+/* GP ID REGISTER 1 */
+#define DA9052_GPID1_GP1                       (255<<0)
+
+/* GP ID REGISTER 2 */
+#define DA9052_GPID2_GP2                       (255<<0)
+
+/* GP ID REGISTER 3 */
+#define DA9052_GPID3_GP3                       (255<<0)
+
+/* GP ID REGISTER 4 */
+#define DA9052_GPID4_GP4                       (255<<0)
+
+/* GP ID REGISTER 5 */
+#define DA9052_GPID5_GP5                       (255<<0)
+
+/* GP ID REGISTER 6 */
+#define DA9052_GPID6_GP6                       (255<<0)
+
+/* GP ID REGISTER 7 */
+#define DA9052_GPID7_GP7                       (255<<0)
+
+/* GP ID REGISTER 8 */
+#define DA9052_GPID8_GP8                       (255<<0)
+
+/* GP ID REGISTER 9 */
+#define DA9052_GPID9_GP9                       (255<<0)
+
+#endif
+/* __LINUX_MFD_DA9052_REG_H */
diff --git a/include/linux/mfd/da9052/rtc.h b/include/linux/mfd/da9052/rtc.h
new file mode 100644 (file)
index 0000000..c7fc87d
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * da9052 RTC module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_RTC_H
+#define __LINUX_MFD_DA9052_RTC_H
+
+#define DA9052_RTC_DEVICE_NAME                         "da9052_rtc"
+
+/*  Limit values */
+#define DA9052_RTC_SECONDS_LIMIT                       59
+#define DA9052_RTC_MINUTES_LIMIT                       59
+#define DA9052_RTC_HOURS_LIMIT                         23
+#define DA9052_RTC_DAYS_LIMIT                          31
+#define DA9052_RTC_MONTHS_LIMIT                                12
+#define DA9052_RTC_YEARS_LIMIT                         63
+
+/* Months */
+#define FEBRUARY                                       2
+#define APRIL                                          4
+#define JUNE                                           6
+#define        SEPTEMBER                                       9
+#define NOVEMBER                                       11
+
+/* BYTE shifts */
+#define DA9052_RTC_FOURTH_BYTE                         24
+#define DA9052_RTC_THIRD_BYTE                          16
+#define DA9052_RTC_SECOND_BYTE                         8
+#define DA9052_RTC_FIRST_BYTE                          0
+
+/* Oscillator trim values */
+#define DA9052_RTC_OSC_FRQ_0_0ppm                      0
+#define DA9052_RTC_OSC_FRQ_1_9ppm                      1
+#define DA9052_RTC_OSC_FRQ_3_8ppm                      2
+#define DA9052_RTC_OSC_FRQ_5_7ppm                      3
+#define DA9052_RTC_OSC_FRQ_7_6ppm                      4
+#define DA9052_RTC_OSC_FRQ_9_5ppm                      5
+#define DA9052_RTC_OSC_FRQ_11_4ppm                     6
+#define DA9052_RTC_OSC_FRQ_13_3ppm                     7
+#define DA9052_RTC_OSC_FRQ_15_2ppm                     8
+#define DA9052_RTC_OSC_FRQ_17_1ppm                     9
+#define DA9052_RTC_OSC_FRQ_19_0ppm                     10
+#define DA9052_RTC_OSC_FRQ_20_9ppm                     11
+#define DA9052_RTC_OSC_FRQ_22_8ppm                     12
+#define DA9052_RTC_OSC_FRQ_24_7ppm                     13
+#define DA9052_RTC_OSC_FRQ_26_7ppm                     14
+#define DA9052_RTC_OSC_FRQ_28_6ppm                     15
+#define DA9052_RTC_OSC_FRQ_30_5ppm                     16
+#define DA9052_RTC_OSC_FRQ_32_4ppm                     17
+#define DA9052_RTC_OSC_FRQ_34_3ppm                     18
+#define DA9052_RTC_OSC_FRQ_36_2ppm                     19
+#define DA9052_RTC_OSC_FRQ_38_1ppm                     20
+#define DA9052_RTC_OSC_FRQ_40_0ppm                     21
+#define DA9052_RTC_OSC_FRQ_41_9ppm                     22
+#define DA9052_RTC_OSC_FRQ_43_8ppm                     23
+#define DA9052_RTC_OSC_FRQ_45_7ppm                     24
+#define DA9052_RTC_OSC_FRQ_47_6ppm                     25
+#define DA9052_RTC_OSC_FRQ_49_5ppm                     26
+#define DA9052_RTC_OSC_FRQ_51_4ppm                     27
+#define DA9052_RTC_OSC_FRQ_53_4ppm                     28
+#define DA9052_RTC_OSC_FRQ_55_3ppm                     29
+#define DA9052_RTC_OSC_FRQ_57_2ppm                     30
+#define DA9052_RTC_OSC_FRQ_59_1ppm                     31
+#define DA9052_RTC_OSC_FRQ_61_0ppm                     32
+#define DA9052_RTC_OSC_FRQ_62_9ppm                     33
+#define DA9052_RTC_OSC_FRQ_64_8ppm                     34
+#define DA9052_RTC_OSC_FRQ_66_7ppm                     35
+#define DA9052_RTC_OSC_FRQ_68_6ppm                     36
+#define DA9052_RTC_OSC_FRQ_70_5ppm                     37
+#define DA9052_RTC_OSC_FRQ_72_4ppm                     38
+#define DA9052_RTC_OSC_FRQ_74_3ppm                     39
+#define DA9052_RTC_OSC_FRQ_76_2ppm                     40
+#define DA9052_RTC_OSC_FRQ_78_2ppm                     41
+#define DA9052_RTC_OSC_FRQ_80_1ppm                     42
+#define DA9052_RTC_OSC_FRQ_82_0ppm                     43
+#define DA9052_RTC_OSC_FRQ_83_9ppm                     44
+#define DA9052_RTC_OSC_FRQ_85_8ppm                     45
+#define DA9052_RTC_OSC_FRQ_87_7ppm                     46
+#define DA9052_RTC_OSC_FRQ_89_6ppm                     47
+#define DA9052_RTC_OSC_FRQ_91_5ppm                     48
+#define DA9052_RTC_OSC_FRQ_93_4ppm                     49
+#define DA9052_RTC_OSC_FRQ_95_3ppm                     50
+#define DA9052_RTC_OSC_FRQ_97_2ppm                     51
+#define DA9052_RTC_OSC_FRQ_99_1ppm                     52
+#define DA9052_RTC_OSC_FRQ_101_0ppm                    53
+#define DA9052_RTC_OSC_FRQ_102_9ppm                    54
+#define DA9052_RTC_OSC_FRQ_104_9ppm                    55
+#define DA9052_RTC_OSC_FRQ_106_8ppm                    56
+#define DA9052_RTC_OSC_FRQ_108_7ppm                    57
+#define DA9052_RTC_OSC_FRQ_110_6ppm                    58
+#define DA9052_RTC_OSC_FRQ_112_5ppm                    59
+#define DA9052_RTC_OSC_FRQ_114_4ppm                    60
+#define DA9052_RTC_OSC_FRQ_116_3ppm                    61
+#define DA9052_RTC_OSC_FRQ_118_2ppm                    62
+#define DA9052_RTC_OSC_FRQ_120_1ppm                    63
+#define DA9052_RTC_OSC_FRQ_122_0ppm                    64
+#define DA9052_RTC_OSC_FRQ_123_9ppm                    65
+#define DA9052_RTC_OSC_FRQ_125_8ppm                    66
+#define DA9052_RTC_OSC_FRQ_127_7ppm                    67
+#define DA9052_RTC_OSC_FRQ_129_6ppm                    68
+#define DA9052_RTC_OSC_FRQ_131_6ppm                    69
+#define DA9052_RTC_OSC_FRQ_133_5ppm                    70
+#define DA9052_RTC_OSC_FRQ_135_4ppm                    71
+#define DA9052_RTC_OSC_FRQ_137_3ppm                    72
+#define DA9052_RTC_OSC_FRQ_139_2ppm                    73
+#define DA9052_RTC_OSC_FRQ_141_1ppm                    74
+#define DA9052_RTC_OSC_FRQ_143_0ppm                    75
+#define DA9052_RTC_OSC_FRQ_144_9ppm                    76
+#define DA9052_RTC_OSC_FRQ_146_8ppm                    77
+#define DA9052_RTC_OSC_FRQ_148_7ppm                    78
+#define DA9052_RTC_OSC_FRQ_150_6ppm                    79
+#define DA9052_RTC_OSC_FRQ_152_5ppm                    80
+#define DA9052_RTC_OSC_FRQ_154_4ppm                    81
+#define DA9052_RTC_OSC_FRQ_156_4ppm                    82
+#define DA9052_RTC_OSC_FRQ_158_3ppm                    83
+#define DA9052_RTC_OSC_FRQ_160_2ppm                    84
+#define DA9052_RTC_OSC_FRQ_162_1ppm                    85
+#define DA9052_RTC_OSC_FRQ_164_0ppm                    86
+#define DA9052_RTC_OSC_FRQ_165_9ppm                    87
+#define DA9052_RTC_OSC_FRQ_167_8ppm                    88
+#define DA9052_RTC_OSC_FRQ_169_7ppm                    89
+#define DA9052_RTC_OSC_FRQ_171_6ppm                    90
+#define DA9052_RTC_OSC_FRQ_173_5ppm                    91
+#define DA9052_RTC_OSC_FRQ_175_4ppm                    92
+#define DA9052_RTC_OSC_FRQ_177_3ppm                    93
+#define DA9052_RTC_OSC_FRQ_179_2ppm                    94
+#define DA9052_RTC_OSC_FRQ_181_1ppm                    95
+#define DA9052_RTC_OSC_FRQ_183_1ppm                    96
+#define DA9052_RTC_OSC_FRQ_185_0ppm                    97
+#define DA9052_RTC_OSC_FRQ_186_9ppm                    98
+#define DA9052_RTC_OSC_FRQ_188_8ppm                    99
+#define DA9052_RTC_OSC_FRQ_190_7ppm                    100
+#define DA9052_RTC_OSC_FRQ_192_6ppm                    101
+#define DA9052_RTC_OSC_FRQ_194_5ppm                    102
+#define DA9052_RTC_OSC_FRQ_196_4ppm                    103
+#define DA9052_RTC_OSC_FRQ_198_3ppm                    104
+#define DA9052_RTC_OSC_FRQ_200_2ppm                    105
+#define DA9052_RTC_OSC_FRQ_202_1ppm                    106
+#define DA9052_RTC_OSC_FRQ_204_0ppm                    107
+#define DA9052_RTC_OSC_FRQ_205_9ppm                    108
+#define DA9052_RTC_OSC_FRQ_207_9ppm                    109
+#define DA9052_RTC_OSC_FRQ_209_8ppm                    110
+#define DA9052_RTC_OSC_FRQ_211_7ppm                    111
+#define DA9052_RTC_OSC_FRQ_213_6ppm                    112
+#define DA9052_RTC_OSC_FRQ_215_5ppm                    113
+#define DA9052_RTC_OSC_FRQ_217_4ppm                    114
+#define DA9052_RTC_OSC_FRQ_219_3ppm                    115
+#define DA9052_RTC_OSC_FRQ_221_2ppm                    116
+#define DA9052_RTC_OSC_FRQ_223_1ppm                    117
+#define DA9052_RTC_OSC_FRQ_225_0ppm                    118
+#define DA9052_RTC_OSC_FRQ_226_9ppm                    119
+#define DA9052_RTC_OSC_FRQ_228_8ppm                    120
+#define DA9052_RTC_OSC_FRQ_230_7ppm                    121
+#define DA9052_RTC_OSC_FRQ_232_6ppm                    122
+#define DA9052_RTC_OSC_FRQ_234_6ppm                    123
+#define DA9052_RTC_OSC_FRQ_236_5ppm                    124
+#define DA9052_RTC_OSC_FRQ_238_4ppm                    125
+#define DA9052_RTC_OSC_FRQ_240_3ppm                    126
+#define DA9052_RTC_OSC_FRQ_242_2ppm                    127
+#define DA9052_RTC_OSC_FRQ_MINUS_244_1ppm              128
+#define DA9052_RTC_OSC_FRQ_MINUS_242_2ppm              129
+#define DA9052_RTC_OSC_FRQ_MINUS_240_3ppm              130
+#define DA9052_RTC_OSC_FRQ_MINUS_238_4ppm              131
+#define DA9052_RTC_OSC_FRQ_MINUS_236_5ppm              132
+#define DA9052_RTC_OSC_FRQ_MINUS_234_6ppm              133
+#define DA9052_RTC_OSC_FRQ_MINUS_232_6ppm              134
+#define DA9052_RTC_OSC_FRQ_MINUS_230_7ppm              135
+#define DA9052_RTC_OSC_FRQ_MINUS_228_8ppm              136
+#define DA9052_RTC_OSC_FRQ_MINUS_226_9ppm              137
+#define DA9052_RTC_OSC_FRQ_MINUS_225_0ppm              138
+#define DA9052_RTC_OSC_FRQ_MINUS_223_1ppm              139
+#define DA9052_RTC_OSC_FRQ_MINUS_221_2ppm              140
+#define DA9052_RTC_OSC_FRQ_MINUS_219_3ppm              141
+#define DA9052_RTC_OSC_FRQ_MINUS_217_4ppm              142
+#define DA9052_RTC_OSC_FRQ_MINUS_215_5ppm              143
+#define DA9052_RTC_OSC_FRQ_MINUS_213_6ppm              144
+#define DA9052_RTC_OSC_FRQ_MINUS_211_7ppm              145
+#define DA9052_RTC_OSC_FRQ_MINUS_209_8ppm              146
+#define DA9052_RTC_OSC_FRQ_MINUS_207_9ppm              147
+#define DA9052_RTC_OSC_FRQ_MINUS_205_9ppm              148
+#define DA9052_RTC_OSC_FRQ_MINUS_204_0ppm              149
+#define DA9052_RTC_OSC_FRQ_MINUS_202_1ppm              150
+#define DA9052_RTC_OSC_FRQ_MINUS_200_2ppm              151
+#define DA9052_RTC_OSC_FRQ_MINUS_198_3ppm              152
+#define DA9052_RTC_OSC_FRQ_MINUS_196_4ppm              153
+#define DA9052_RTC_OSC_FRQ_MINUS_194_5ppm              154
+#define DA9052_RTC_OSC_FRQ_MINUS_192_6ppm              155
+#define DA9052_RTC_OSC_FRQ_MINUS_190_7ppm              156
+#define DA9052_RTC_OSC_FRQ_MINUS_188_8ppm              157
+#define DA9052_RTC_OSC_FRQ_MINUS_186_9ppm              158
+#define DA9052_RTC_OSC_FRQ_MINUS_185_0ppm              159
+#define DA9052_RTC_OSC_FRQ_MINUS_183_1ppm              160
+#define DA9052_RTC_OSC_FRQ_MINUS_181_1ppm              161
+#define DA9052_RTC_OSC_FRQ_MINUS_179_2ppm              162
+#define DA9052_RTC_OSC_FRQ_MINUS_177_3ppm              163
+#define DA9052_RTC_OSC_FRQ_MINUS_175_4ppm              164
+#define DA9052_RTC_OSC_FRQ_MINUS_173_5ppm              165
+#define DA9052_RTC_OSC_FRQ_MINUS_171_6ppm              166
+#define DA9052_RTC_OSC_FRQ_MINUS_169_7ppm              167
+#define DA9052_RTC_OSC_FRQ_MINUS_167_8ppm              168
+#define DA9052_RTC_OSC_FRQ_MINUS_165_9ppm              169
+#define DA9052_RTC_OSC_FRQ_MINUS_164_0ppm              170
+#define DA9052_RTC_OSC_FRQ_MINUS_162_1ppm              171
+#define DA9052_RTC_OSC_FRQ_MINUS_160_2ppm              172
+#define DA9052_RTC_OSC_FRQ_MINUS_158_3ppm              173
+#define DA9052_RTC_OSC_FRQ_MINUS_156_4ppm              174
+#define DA9052_RTC_OSC_FRQ_MINUS_154_4ppm              175
+#define DA9052_RTC_OSC_FRQ_MINUS_152_5ppm              176
+#define DA9052_RTC_OSC_FRQ_MINUS_150_6ppm              177
+#define DA9052_RTC_OSC_FRQ_MINUS_148_7ppm              178
+#define DA9052_RTC_OSC_FRQ_MINUS_146_8ppm              179
+#define DA9052_RTC_OSC_FRQ_MINUS_144_9ppm              180
+#define DA9052_RTC_OSC_FRQ_MINUS_143_0ppm              181
+#define DA9052_RTC_OSC_FRQ_MINUS_141_1ppm              182
+#define DA9052_RTC_OSC_FRQ_MINUS_139_2ppm              183
+#define DA9052_RTC_OSC_FRQ_MINUS_137_3ppm              184
+#define DA9052_RTC_OSC_FRQ_MINUS_135_4ppm              185
+#define DA9052_RTC_OSC_FRQ_MINUS_133_5ppm              186
+#define DA9052_RTC_OSC_FRQ_MINUS_131_6ppm              187
+#define DA9052_RTC_OSC_FRQ_MINUS_129_6ppm              188
+#define DA9052_RTC_OSC_FRQ_MINUS_127_7ppm              189
+#define DA9052_RTC_OSC_FRQ_MINUS_125_8ppm              190
+#define DA9052_RTC_OSC_FRQ_MINUS_123_9ppm              191
+#define DA9052_RTC_OSC_FRQ_MINUS_122_0ppm              192
+#define DA9052_RTC_OSC_FRQ_MINUS_120_1ppm              193
+#define DA9052_RTC_OSC_FRQ_MINUS_118_2ppm              194
+#define DA9052_RTC_OSC_FRQ_MINUS_116_3ppm              195
+#define DA9052_RTC_OSC_FRQ_MINUS_114_4ppm              196
+#define DA9052_RTC_OSC_FRQ_MINUS_112_5ppm              197
+#define DA9052_RTC_OSC_FRQ_MINUS_110_6ppm              198
+#define DA9052_RTC_OSC_FRQ_MINUS_108_7ppm              199
+#define DA9052_RTC_OSC_FRQ_MINUS_106_8ppm              200
+#define DA9052_RTC_OSC_FRQ_MINUS_104_9ppm              201
+#define DA9052_RTC_OSC_FRQ_MINUS_102_9ppm              202
+#define DA9052_RTC_OSC_FRQ_MINUS_101_0ppm              203
+#define DA9052_RTC_OSC_FRQ_MINUS_99_1ppm               204
+#define DA9052_RTC_OSC_FRQ_MINUS_97_2ppm               205
+#define DA9052_RTC_OSC_FRQ_MINUS_95_3ppm               206
+#define DA9052_RTC_OSC_FRQ_MINUS_93_4ppm               207
+#define DA9052_RTC_OSC_FRQ_MINUS_91_5ppm               208
+#define DA9052_RTC_OSC_FRQ_MINUS_89_6ppm               209
+#define DA9052_RTC_OSC_FRQ_MINUS_87_7ppm               210
+#define DA9052_RTC_OSC_FRQ_MINUS_85_8ppm               211
+#define DA9052_RTC_OSC_FRQ_MINUS_83_9ppm               212
+#define DA9052_RTC_OSC_FRQ_MINUS_82_0ppm               213
+#define DA9052_RTC_OSC_FRQ_MINUS_80_1ppm               214
+#define DA9052_RTC_OSC_FRQ_MINUS_78_2ppm               215
+#define DA9052_RTC_OSC_FRQ_MINUS_76_2ppm               216
+#define DA9052_RTC_OSC_FRQ_MINUS_74_3ppm               217
+#define DA9052_RTC_OSC_FRQ_MINUS_72_4ppm               218
+#define DA9052_RTC_OSC_FRQ_MINUS_70_5ppm               219
+#define DA9052_RTC_OSC_FRQ_MINUS_68_6ppm               220
+#define DA9052_RTC_OSC_FRQ_MINUS_66_7ppm               221
+#define DA9052_RTC_OSC_FRQ_MINUS_64_8ppm               222
+#define DA9052_RTC_OSC_FRQ_MINUS_62_9ppm               223
+#define DA9052_RTC_OSC_FRQ_MINUS_61_0ppm               224
+#define DA9052_RTC_OSC_FRQ_MINUS_59_1ppm               225
+#define DA9052_RTC_OSC_FRQ_MINUS_57_2ppm               226
+#define DA9052_RTC_OSC_FRQ_MINUS_55_3ppm               227
+#define DA9052_RTC_OSC_FRQ_MINUS_53_4ppm               228
+#define DA9052_RTC_OSC_FRQ_MINUS_51_4ppm               229
+#define DA9052_RTC_OSC_FRQ_MINUS_49_5ppm               230
+#define DA9052_RTC_OSC_FRQ_MINUS_47_6ppm               231
+#define DA9052_RTC_OSC_FRQ_MINUS_45_7ppm               232
+#define DA9052_RTC_OSC_FRQ_MINUS_43_8ppm               233
+#define DA9052_RTC_OSC_FRQ_MINUS_41_9ppm               234
+#define DA9052_RTC_OSC_FRQ_MINUS_40_0ppm               235
+#define DA9052_RTC_OSC_FRQ_MINUS_38_1ppm               236
+#define DA9052_RTC_OSC_FRQ_MINUS_36_2ppm               237
+#define DA9052_RTC_OSC_FRQ_MINUS_34_3ppm               238
+#define DA9052_RTC_OSC_FRQ_MINUS_32_4ppm               239
+#define DA9052_RTC_OSC_FRQ_MINUS_30_5ppm               240
+#define DA9052_RTC_OSC_FRQ_MINUS_28_6ppm               241
+#define DA9052_RTC_OSC_FRQ_MINUS_26_7ppm               242
+#define DA9052_RTC_OSC_FRQ_MINUS_24_7ppm               243
+#define DA9052_RTC_OSC_FRQ_MINUS_22_8ppm               244
+#define DA9052_RTC_OSC_FRQ_MINUS_20_9ppm               245
+#define DA9052_RTC_OSC_FRQ_MINUS_19_0ppm               246
+#define DA9052_RTC_OSC_FRQ_MINUS_17_1ppm               247
+#define DA9052_RTC_OSC_FRQ_MINUS_15_2ppm               248
+#define DA9052_RTC_OSC_FRQ_MINUS_13_3ppm               249
+#define DA9052_RTC_OSC_FRQ_MINUS_11_4ppm               250
+#define DA9052_RTC_OSC_FRQ_MINUS_9_5ppm                        251
+#define DA9052_RTC_OSC_FRQ_MINUS_7_6ppm                        252
+#define DA9052_RTC_OSC_FRQ_MINUS_5_7ppm                        253
+#define DA9052_RTC_OSC_FRQ_MINUS_3_8ppm                        254
+#define DA9052_RTC_OSC_FRQ_MINUS_1_9ppm                        255
+
+/* RTC error codes */
+#define DA9052_RTC_INVALID_SECONDS                     3
+#define DA9052_RTC_INVALID_MINUTES                     4
+#define DA9052_RTC_INVALID_HOURS                       5
+#define DA9052_RTC_INVALID_DAYS                                6
+#define DA9052_RTC_INVALID_MONTHS                      7
+#define DA9052_RTC_INVALID_YEARS                       8
+#define DA9052_RTC_INVALID_EVENT                       9
+#define DA9052_RTC_INVALID_IOCTL                       10
+#define DA9052_RTC_INVALID_SETTING                     11
+#define DA9052_RTC_EVENT_ALREADY_REGISTERED            12
+#define DA9052_RTC_EVENT_UNREGISTERED                  13
+#define DA9052_RTC_EVENT_REGISTRATION_FAILED           14
+#define DA9052_RTC_EVENT_UNREGISTRATION_FAILED         15
+
+#endif 
+/* __LINUX_MFD_DA9052_RTC_H */
\ No newline at end of file
diff --git a/include/linux/mfd/da9052/tsi.h b/include/linux/mfd/da9052/tsi.h
new file mode 100644 (file)
index 0000000..b0f5c24
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * da9052 TSI module declarations.
+  *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_TSI_H
+#define __LINUX_MFD_DA9052_TSI_H
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/tsi_filter.h>
+#include <linux/mfd/da9052/tsi_calibrate.h>
+#include <linux/mfd/da9052/pm.h>
+
+#define DA9052_TSI_DEVICE_NAME         "da9052-tsi"
+#define DA9052_TSI_INPUT_DEV           DA9052_TSI_DEVICE_NAME
+
+#define TSI_VERSION                    0x0101
+#define DA9052_VENDOR_ID               0x15B6
+#define DA9052_PRODUCT_ID              0x9052
+
+#define TSI_INPUT_DEVICE_OFF           0
+#define NUM_INPUT_DEVS                 1
+
+#define DA9052_DISPLAY_X_MAX           0x3FF
+#define DA9052_DISPLAY_Y_MAX           0x3FF
+#define DA9052_TOUCH_PRESSURE_MAX      0x3FF
+
+#define DA9052_TCA_AUTO_TSI_ENABLE                             (1<<0)
+#define DA9052_TCA_PEN_DET_ENABLE                              (1<<1)
+#define DA9052_TCA_TSI_XP_MODE_ENABLE                          (1<<2)
+
+#define DA9052_TCA_TSI_DELAY_0SLOTS                            (0<<6)
+#define DA9052_TCA_TSI_DELAY_2SLOTS                            (2<<6)
+#define DA9052_TCA_TSI_DELAY_4SLOTS                            (3<<6)
+
+#define DA9052_TCA_TSI_SEL_XPLUS                               (1<<0)
+#define DA9052_TCA_TSI_SEL_XMINUS                              (1<<1)
+#define DA9052_TCA_TSI_SEL_YPLUS                               (1<<2)
+#define DA9052_TCA_TSI_SEL_YMINUS                              (1<<3)
+
+#define DA9052_TCA_TSI_MUX_XPLUS_ROUTED_ADCIN7                 (0<<4)
+#define DA9052_TCA_TSI_MUX_YPLUS_ROUTED_ADCIN7                 (1<<4)
+#define DA9052_TCA_TSI_MUX_XMINUS_ROUTED_ADCIN7                        (2<<4)
+#define DA9052_TCA_TSI_MUX_YMINUS_ROUTED_ADCIN7                        (3<<4)
+
+#define DA9052_TCA_TSI_MAN_ENABLE                              (1<<6)
+#define DA9052_TCA_TSI_SET_TSIREF                              (0<<7)
+#define DA9052_TCA_TSI_SET_XY_REF                              (1<<7)
+
+#define DA9052_EVETN_B_E_PEN_DOWN                              (1<<6)
+#define DA9052_EVENT_B_E_TSI_READY                             (1<<7)
+
+#define DA9052_IRQMASK_B_PENDOWN_MASK                          (1<<6)
+#define DA9052_IRQMASK_B_TSI_READY_MASK                        (1<<7)
+
+#define X_LSB_SHIFT    (0)
+#define Y_LSB_SHIFT    (2)
+#define Z_LSB_SHIFT    (4)
+#define PEN_DET_SHIFT  (6)
+#define X_MSB_SHIFT    (2)
+#define Y_MSB_SHIFT    (2)
+#define Z_MSB_SHIFT    (2)
+#define X_LSB_MASK     (11 << X_LSB_SHIFT)
+#define Y_LSB_MASK     (11 << Y_LSB_SHIFT)
+#define Z_LSB_MASK     (11 << Z_LSB_SHIFT)
+#define PEN_DET_MASK   (11 << PEN_DET_SHIFT)
+
+#define TSI_FIFO_SIZE          16
+
+#define INVALID_LDO9_VOLT_VALUE                        17
+
+#define set_bits(value, mask)          (value | mask)
+#define clear_bits(value, mask)                (value & ~(mask))
+
+#define SUCCESS                0
+#define FAILURE                1
+
+#define SET            1
+#define        RESET           0
+#define        CLEAR           0
+
+#define ENABLE         1
+#define DISABLE                0
+
+#define TRUE           1
+#define FALSE          0
+
+#define incr_with_wrap_reg_fifo(x)                     \
+               if(++x >= TSI_REG_DATA_BUF_SIZE)        \
+                       x = 0
+
+#define incr_with_wrap(x)      \
+               if(++x >= TSI_FIFO_SIZE)        \
+                       x = 0
+
+#undef DA9052_DEBUG
+#if DA9052_TSI_DEBUG
+#define DA9052_DEBUG( fmt, args... ) printk( KERN_CRIT "" fmt, ##args )
+#else
+#define DA9052_DEBUG( fmt, args... )
+#endif
+
+enum ADC_MODE {
+
+       ECONOMY_MODE = 0,
+       FAST_MODE = 1
+};
+
+enum TSI_DELAY {
+       TSI_DELAY_0SLOTS = 0,
+       TSI_DELAY_1SLOTS = 1,
+       TSI_DELAY_2SLOTS = 2,
+       TSI_DELAY_4SLOTS = 3
+};
+
+enum TSI_SLOT_SKIP{
+       TSI_SKIP_0SLOTS = 0,
+       TSI_SKIP_2SLOTS = 1,
+       TSI_SKIP_5SLOTS = 2,
+       TSI_SKIP_10SLOTS = 3,
+       TSI_SKIP_30SLOTS = 4,
+       TSI_SKIP_80SLOTS = 5,
+       TSI_SKIP_130SLOTS = 6, 
+       TSI_SKIP_330SLOTS = 7 
+};
+
+
+enum TSI_MUX_SEL
+{
+       TSI_MUX_XPLUS   = 0,
+       TSI_MUX_YPLUS   = 1,
+       TSI_MUX_XMINUS  = 2,
+       TSI_MUX_YMINUS  = 3
+};
+
+
+enum TSI_IRQ{
+       TSI_PEN_DWN,
+       TSI_DATA_RDY
+};
+
+
+enum TSI_COORDINATE{
+       X_COORDINATE,
+       Y_COORDINATE,
+       Z_COORDINATE
+};
+
+enum TSI_MEASURE_SEQ{
+       XYZP_MODE,
+       XP_MODE
+};
+
+enum TSI_STATE {
+       TSI_AUTO_MODE,
+       TSI_MANUAL_COORD_X,
+       TSI_MANUAL_COORD_Y,
+       TSI_MANUAL_COORD_Z,
+       TSI_MANUAL_SET,
+       TSI_IDLE
+};
+
+union da9052_tsi_cont_reg {
+       u8 da9052_tsi_cont_a;
+       struct{
+               u8 auto_tsi_en:1;
+               u8 pen_det_en:1;
+               u8 tsi_mode:1;
+               u8 tsi_skip:3;
+               u8 tsi_delay:2;
+       }tsi_cont_a;
+};
+
+union da9052_tsi_man_cont_reg {
+       u8 da9052_tsi_cont_b;
+       struct{
+               u8 tsi_sel_0:1;
+               u8 tsi_sel_1:1;
+               u8 tsi_sel_2:1;
+               u8 tsi_sel_3:1;
+               u8 tsi_mux:2;
+               u8 tsi_man:1;
+               u8 tsi_adc_ref:1;
+       }tsi_cont_b;
+};
+
+struct da9052_tsi_conf {
+       union da9052_tsi_cont_reg       auto_cont;
+       union da9052_tsi_man_cont_reg   man_cont;
+       u8                              tsi_adc_sample_intervel:1;
+       enum TSI_STATE                  state;
+       u8                              ldo9_en:1;
+       u8                              ldo9_conf:1;
+       u8                              tsi_ready_irq_mask:1;
+       u8                              tsi_pendown_irq_mask:1;
+};
+
+
+struct da9052_tsi_reg {
+       u8      x_msb;
+       u8      y_msb;
+       u8      z_msb;
+       u8      lsb;
+ };
+
+
+struct da9052_tsi_reg_fifo {
+       struct semaphore        lock;
+       s32                     head;
+       s32                     tail;
+       struct da9052_tsi_reg   data[TSI_REG_DATA_BUF_SIZE];
+};
+
+struct da9052_tsi_info {
+       struct  da9052_tsi_conf  tsi_conf;
+       struct input_dev        *input_devs[NUM_INPUT_DEVS];
+       struct calib_cfg_t      *tsi_calib;
+       u32                     tsi_data_poll_interval;
+       u32                     tsi_penup_count;
+       u32                     tsi_zero_data_cnt;
+       u8                      pen_dwn_event;
+       u8                      tsi_rdy_event;
+       u8                      pd_reg_status;  
+       u8                      datardy_reg_status;
+}; 
+struct da9052_tsi {
+       struct da9052_tsi_reg tsi_fifo[TSI_FIFO_SIZE];
+       struct mutex tsi_fifo_lock;
+       u8 tsi_sampling;
+       u8 tsi_state;
+       u32 tsi_fifo_start;
+       u32 tsi_fifo_end;
+};
+ struct da9052_ts_priv {
+       struct da9052   *da9052;
+       struct da9052_eh_nb pd_nb;
+       struct da9052_eh_nb datardy_nb;
+
+       struct tsi_thread_type  tsi_reg_proc_thread;
+       struct tsi_thread_type tsi_raw_proc_thread;
+
+       struct da9052_tsi_platform_data *tsi_pdata;
+
+       struct da9052_tsi_reg_fifo      tsi_reg_fifo;
+       struct da9052_tsi_raw_fifo      tsi_raw_fifo;
+
+       u32 tsi_reg_data_poll_interval;
+       u32 tsi_raw_data_poll_interval;
+
+       u8 early_data_flag;
+       u8 debounce_over;
+       u8 win_reference_valid;
+
+       int os_data_cnt;
+       int raw_data_cnt;
+};
+
+static inline u8  mask_pendwn_irq(u8 val)
+{ 
+       return (val |= DA9052_IRQMASKB_MPENDOWN);
+}
+
+static inline u8  unmask_pendwn_irq(u8 val)
+{ 
+       return (val &= ~DA9052_IRQMASKB_MPENDOWN);
+}
+
+static inline u8  mask_tsi_rdy_irq(u8 val) 
+{
+       return (val |=DA9052_IRQMASKB_MTSIREADY);
+}
+
+static inline u8  unmask_tsi_rdy_irq(u8 val)
+{ 
+       return (val &= ~DA9052_IRQMASKB_MTSIREADY);
+}
+
+static inline u8  enable_ldo9(u8 val) 
+{
+       return (val |=DA9052_LDO9_LDO9EN);
+}
+
+static inline u8  disable_ldo9(u8 val)
+{
+       return (val &= ~DA9052_LDO9_LDO9EN);
+} 
+
+static inline u8  set_auto_tsi_en(u8 val)
+{
+       return (val |=DA9052_TSICONTA_AUTOTSIEN);
+}
+
+static inline u8  reset_auto_tsi_en(u8 val)
+{
+       return (val &=~DA9052_TSICONTA_AUTOTSIEN);
+}
+
+static inline u8  enable_pen_detect(u8 val)
+{
+       return (val |=DA9052_TSICONTA_PENDETEN);
+}
+
+static inline u8  disable_pen_detect(u8 val) 
+{
+       return (val &=~DA9052_TSICONTA_PENDETEN);
+}
+
+static inline u8  enable_xyzp_mode(u8 val)
+{
+       return (val &= ~DA9052_TSICONTA_TSIMODE);
+}
+
+static inline u8  enable_xp_mode(u8 val)
+{
+       return(val |= DA9052_TSICONTA_TSIMODE);
+}
+
+static inline u8  enable_tsi_manual_mode(u8 val)
+{
+       return(val |= DA9052_TSICONTB_TSIMAN);
+}
+
+static inline u8  disable_tsi_manual_mode(u8 val)
+{
+       return(val &= ~DA9052_TSICONTB_TSIMAN);
+}
+
+static inline u8 tsi_sel_xplus_close(u8 val)
+{
+       return(val |= DA9052_TSICONTB_TSISEL0);
+}
+
+static inline u8 tsi_sel_xplus_open(u8 val)
+{
+       return(val &= ~DA9052_TSICONTB_TSISEL0);
+}
+
+static inline u8 tsi_sel_xminus_close(u8 val)
+{
+       return(val |= DA9052_TSICONTB_TSISEL1);
+}
+
+static inline u8 tsi_sel_xminus_open(u8 val)
+{
+       return(val &= ~DA9052_TSICONTB_TSISEL1);
+}
+
+static inline u8 tsi_sel_yplus_close(u8 val)
+{
+       return(val |= DA9052_TSICONTB_TSISEL2);
+}
+
+static inline u8 tsi_sel_yplus_open(u8 val)
+{
+       return(val &= ~DA9052_TSICONTB_TSISEL2);
+}
+
+static inline u8 tsi_sel_yminus_close(u8 val)
+{
+       return(val |= DA9052_TSICONTB_TSISEL3);
+}
+
+static inline u8 tsi_sel_yminus_open(u8 val)
+{
+       return(val &= ~DA9052_TSICONTB_TSISEL3);
+}
+
+static inline u8 adc_mode_economy_mode(u8 val)
+{
+       return(val &= ~DA9052_ADCCONT_ADCMODE);
+}
+
+static inline u8 adc_mode_fast_mode(u8 val)
+{
+       return(val |= DA9052_ADCCONT_ADCMODE);
+}
+int da9052_tsi_get_calib_display_point(struct da9052_tsi_data *display);
+
+struct da9052_ldo_config {
+       u16             ldo_volt;
+       u8              ldo_num;
+       u8              ldo_conf:1;
+       u8              ldo_pd:1;
+};
+
+static inline  u8 ldo9_mV_to_reg(u16 value)
+{
+       return ((value - DA9052_LDO9_VOLT_LOWER)/DA9052_LDO9_VOLT_STEP);
+}
+
+static inline  u8 validate_ldo9_mV(u16 value)
+{
+       if ((value >= DA9052_LDO9_VOLT_LOWER) && \
+                                       (value <= DA9052_LDO9_VOLT_UPPER))
+               return 
+                       (((value - DA9052_LDO9_VOLT_LOWER) % DA9052_LDO9_VOLT_STEP > 0) ? -1 : 0);
+       return FAILURE;
+}
+
+s32 da9052_tsi_raw_proc_thread (void *ptr);
+void __init da9052_init_tsi_fifos (struct da9052_ts_priv *priv);
+void clean_tsi_fifos(struct da9052_ts_priv *priv);
+u32 get_reg_data_cnt (struct da9052_ts_priv *priv);
+u32 get_reg_free_space_cnt(struct da9052_ts_priv *priv);
+void da9052_tsi_process_reg_data(struct da9052_ts_priv *priv);
+void da9052_tsi_pen_down_handler(struct da9052_eh_nb *eh_data, u32 event);
+void da9052_tsi_data_ready_handler(struct da9052_eh_nb *eh_data, u32 event);
+
+#endif /* __LINUX_MFD_DA9052_TSI_H */
diff --git a/include/linux/mfd/da9052/tsi_calibrate.h b/include/linux/mfd/da9052/tsi_calibrate.h
new file mode 100644 (file)
index 0000000..a4b42ea
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * da9052 TSI calibration module declarations.
+  *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_TSI_CALIBRATE_H
+#define __LINUX_MFD_DA9052_TSI_CALIBRATE_H
+
+#include <linux/mfd/da9052/tsi_filter.h>
+
+struct Calib_xform_matrix_t {
+       s32     An;
+       s32     Bn;
+       s32     Cn;
+       s32     Dn;
+       s32     En;
+       s32     Fn;
+       s32     Divider;
+} ;
+
+
+struct calib_cfg_t {
+       u8 calibrate_flag;
+} ;
+
+ssize_t da9052_tsi_set_calib_matrix(struct da9052_tsi_data *displayPtr,
+                                  struct da9052_tsi_data *screenPtr);
+u8 configure_tsi_calib(struct calib_cfg_t *tsi_calib);
+struct calib_cfg_t *get_calib_config(void);
+#endif /* __LINUX_MFD_DA9052_TSI_CALIBRATE_H */
+
diff --git a/include/linux/mfd/da9052/tsi_cfg.h b/include/linux/mfd/da9052/tsi_cfg.h
new file mode 100644 (file)
index 0000000..729d103
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * da9052 TSI configuration module declarations.
+  *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_TSI_CFG_H
+#define __LINUX_MFD_DA9052_TSI_CFG_H
+
+#define                DA9052_TSI_DEBUG        0
+
+#define AUTO_MODE                      0
+#define IDLE                           1
+#define DEFAULT_TSI_STATE              AUTO_MODE
+
+#define TSI_SLOT_SKIP_VALUE            0
+
+#define TSI_DELAY_VALUE                        3
+
+#define TSI_MODE_VALUE                 0
+
+#define ENABLE_AVERAGE_FILTER          1
+
+#define DEFAULT_AVERAGE_FILTER_SIZE    3
+
+#define ENABLE_WINDOW_FILTER           1
+
+#define TSI_X_WINDOW_SIZE              50
+#define TSI_Y_WINDOW_SIZE              50
+
+#define SAMPLE_CNT_FOR_WIN_REF         3
+
+#define TSI_ECONOMY_MODE               0
+#define TSI_FAST_MODE                  1
+#define DEFAULT_TSI_SAMPLING_MODE      TSI_FAST_MODE
+
+#define TSI_USE_CALIBRATION            1
+
+#define DA9052_TSI_CALIB_AN            1
+#define DA9052_TSI_CALIB_BN            0
+#define DA9052_TSI_CALIB_CN            0
+#define DA9052_TSI_CALIB_DN            0
+#define DA9052_TSI_CALIB_EN            1
+#define DA9052_TSI_CALIB_FN            0
+#define DA9052_TSI_CALIB_DIVIDER       1
+
+#define TS_X_MIN       (0)
+#define TS_X_MAX       (1023)
+#define TS_Y_MIN       (0)
+#define TS_Y_MAX       (1023)
+
+#define DISPLAY_X_MIN  (0)
+#define DISPLAY_X_MAX  (1023)
+#define DISPLAY_Y_MIN  (0)
+#define DISPLAY_Y_MAX  (1023)
+
+#define ENABLE_TSI_DEBOUNCE            0
+
+#define TSI_DEBOUNCE_DATA_CNT          3
+
+
+#define RELEASE
+#define DA9052_TSI_RAW_DATA_PROFILING          0
+#define DA9052_TSI_WIN_FLT_DATA_PROFILING      0
+#define DA9052_TSI_AVG_FLT_DATA_PROFILING      0
+#define DA9052_TSI_CALIB_DATA_PROFILING        0
+#define DA9052_TSI_OS_DATA_PROFILING           1
+#define DA9052_TSI_PRINT_DEBOUNCED_DATA                0
+#define DA9052_TSI_PRINT_PREVIOUS_DATA         0
+
+
+#if ENABLE_AVERAGE_FILTER
+#define TSI_AVERAGE_FILTER_SIZE                DEFAULT_AVERAGE_FILTER_SIZE
+#else
+#define TSI_AVERAGE_FILTER_SIZE                        1
+#endif
+
+#define TSI_FAST_MODE_SAMPLE_CNT               1000
+#define TSI_ECO_MODE_SAMPLE_CNT                        100
+
+#define TSI_POLL_SAMPLE_CNT                    10
+
+#define TSI_FAST_MODE_REG_DATA_PROCESSING_INTERVAL     \
+       ((1000 / TSI_FAST_MODE_SAMPLE_CNT)* TSI_POLL_SAMPLE_CNT)
+#define TSI_ECO_MODE_REG_DATA_PROCESSING_INTERVAL      \
+       ((1000 / TSI_ECO_MODE_SAMPLE_CNT)* TSI_POLL_SAMPLE_CNT)
+
+#if DEFAULT_TSI_SAMPLING_MODE
+#define DEFAULT_REG_DATA_PROCESSING_INTERVAL \
+       TSI_FAST_MODE_REG_DATA_PROCESSING_INTERVAL
+#else
+#define DEFAULT_REG_DATA_PROCESSING_INTERVAL \
+       TSI_ECO_MODE_REG_DATA_PROCESSING_INTERVAL
+#endif
+
+#define TSI_REG_DATA_BUF_SIZE  (2 * TSI_POLL_SAMPLE_CNT)
+
+#define TSI_FAST_MODE_RAW_DATA_PROCESSING_INTERVAL     \
+       ((1000 / TSI_FAST_MODE_SAMPLE_CNT) * (TSI_AVERAGE_FILTER_SIZE))
+#define TSI_ECO_MODE_RAW_DATA_PROCESSING_INTERVAL      \
+       ((1000 / TSI_ECO_MODE_SAMPLE_CNT) * (TSI_AVERAGE_FILTER_SIZE))
+
+
+#if DEFAULT_TSI_SAMPLING_MODE
+#define DEFAULT_RAW_DATA_PROCESSING_INTERVAL \
+       TSI_FAST_MODE_RAW_DATA_PROCESSING_INTERVAL
+#else
+#define DEFAULT_RAW_DATA_PROCESSING_INTERVAL \
+       TSI_ECO_MODE_RAW_DATA_PROCESSING_INTERVAL
+#endif
+
+
+#define TSI_RAW_DATA_BUF_SIZE  \
+       (TSI_REG_DATA_BUF_SIZE * \
+       ( (TSI_AVERAGE_FILTER_SIZE / TSI_POLL_SAMPLE_CNT) + 1))
+
+#endif /* __LINUX_MFD_DA9052_TSI_CFG_H */
diff --git a/include/linux/mfd/da9052/tsi_filter.h b/include/linux/mfd/da9052/tsi_filter.h
new file mode 100644 (file)
index 0000000..0439a08
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * da9052 TSI filter module declarations.
+  *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_TSI_FILTER_H
+#define __LINUX_MFD_DA9052_TSI_FILTER_H
+
+#include <linux/mfd/da9052/tsi_cfg.h>
+
+struct da9052_tsi_data {
+       s16     x;
+       s16     y;
+       s16     z;
+};
+
+struct da9052_tsi_raw_fifo {
+       struct semaphore        lock;
+       s32                     head;
+       s32                     tail;
+       struct da9052_tsi_data  data[TSI_RAW_DATA_BUF_SIZE];
+};
+
+struct tsi_thread_type {
+       u8                      pid;
+       u8                      state;
+       struct completion       notifier;
+       struct task_struct      *thread_task;
+} ;
+
+/* State for TSI thread */
+#define        ACTIVE          0
+#define        INACTIVE        1
+
+
+extern u32 da9052_tsi_get_input_dev(u8 off);
+
+ssize_t da9052_tsi_get_calib_display_point(struct da9052_tsi_data *displayPtr);
+
+#endif /* __LINUX_MFD_DA9052_TSI_FILTER_H */
diff --git a/include/linux/mfd/da9052/wdt.h b/include/linux/mfd/da9052/wdt.h
new file mode 100644 (file)
index 0000000..6a77bfc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * da9052 SM (watchdog) module declarations.
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_DA9052_WDT_H
+#define __LINUX_MFD_DA9052_WDT_H
+
+#include <linux/platform_device.h>
+
+/* To enable debug output for your module, set this to 1 */
+#define        DA9052_SM_DEBUG                         0
+
+/* Error codes */
+#define BUS_ERR                                        2
+#define INIT_FAIL                              3
+#define SM_OPEN_FAIL                           4
+#define NO_IOCTL_CMD                           5
+#define INVALID_SCALING_VALUE                  6
+#define STROBING_FILTER_ERROR                  7
+#define TIMER_DELETE_ERR                       8
+#define STROBING_MODE_ERROR                    9
+
+/* IOCTL Switch */
+/* For strobe watchdog function */
+#define DA9052_SM_IOCTL_STROBE_WDT             1
+
+/* For setting watchdog timer time */
+#define DA9052_SM_IOCTL_SET_WDT                        2
+
+/* For enabling/disabling strobing filter */
+#define DA9052_SM_IOCTL_SET_STROBING_FILTER    3
+
+/* For enabling/disabling strobing filter */
+#define DA9052_SM_IOCTL_SET_STROBING_MODE      4
+
+/* Watchdog time scaling TWDMAX scaling macros */
+#define DA9052_WDT_DISABLE                     0
+#define DA9052_SCALE_1X                                1
+#define DA9052_SCALE_2X                                2
+#define DA9052_SCALE_4X                                3
+#define DA9052_SCALE_8X                                4
+#define DA9052_SCALE_16X                       5
+#define DA9052_SCALE_32X                       6
+#define DA9052_SCALE_64X                       7
+
+#define DA9052_STROBE_WIN_FILTER_PER           80
+#define DA9052_X1_WINDOW       ((1 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+#define DA9052_X2_WINDOW       ((2 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+#define DA9052_X4_WINDOW       ((4 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+#define DA9052_X8_WINDOW       ((8 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+#define DA9052_X16_WINDOW      ((16 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+#define DA9052_X32_WINDOW      ((32 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+#define DA9052_X64_WINDOW      ((64 * 2048 * DA9052_STROBE_WIN_FILTER_PER)/100)
+
+#define DA9052_STROBE_AUTO                     1
+#define DA9052_STROBE_MANUAL                   0
+
+#define DA9052_SM_STROBE_CONF                  DISABLE
+
+#define DA9052_ADC_TWDMIN_TIME                 500
+
+void start_strobing(struct work_struct *work);
+/* Create a handler for the scheduling start_strobing function */
+DECLARE_WORK(strobing_action, start_strobing);
+
+#endif /* __LINUX_MFD_DA9052_WDT_H */
diff --git a/include/linux/regulator/da9052-regulator.h b/include/linux/regulator/da9052-regulator.h
new file mode 100644 (file)
index 0000000..58e6f0b
--- /dev/null
@@ -0,0 +1,15 @@
+/* This file is there to support additional attributes in
+ sysfs - changestate and setvoltage 
+*/
+#ifndef _DA9052_REGULATOR_H
+#define _DA9052_REGULATOR_H
+
+int da9052_ldo_buck_enable(struct regulator_dev *rdev);
+int da9052_ldo_buck_disable(struct regulator_dev *rdev);
+
+
+int da9052_ldo_buck_set_voltage(struct regulator_dev *rdev,
+                                        int min_uV, int max_uV);
+int da9052_ldo_buck_get_voltage(struct regulator_dev *rdev);
+
+#endif