summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/da9052-gpio.c731
-rw-r--r--drivers/hwmon/da9052-adc.c644
-rw-r--r--drivers/input/misc/da9052_onkey.c133
-rw-r--r--drivers/input/touchscreen/da9052_tsi.c1448
-rw-r--r--drivers/input/touchscreen/da9052_tsi_calibrate.c107
-rw-r--r--drivers/input/touchscreen/da9052_tsi_filter.c489
-rw-r--r--drivers/leds/leds-da9052.c307
-rw-r--r--drivers/mfd/da9052-core.c533
-rw-r--r--drivers/mfd/da9052-i2c.c376
-rw-r--r--drivers/mfd/da9052-spi.c399
-rw-r--r--drivers/power/da9052-battery.c844
-rw-r--r--drivers/regulator/da9052-regulator.c487
-rw-r--r--drivers/rtc/rtc-da9052.c694
-rw-r--r--drivers/spi/spi_sam.c1161
-rw-r--r--drivers/video/backlight/da9052_bl.c455
-rw-r--r--drivers/watchdog/da9052_wdt.c542
-rw-r--r--include/linux/mfd/da9052/adc.h66
-rw-r--r--include/linux/mfd/da9052/bat.h264
-rw-r--r--include/linux/mfd/da9052/bl.h289
-rw-r--r--include/linux/mfd/da9052/da9052.h206
-rw-r--r--include/linux/mfd/da9052/eh.h77
-rw-r--r--include/linux/mfd/da9052/gpio.h253
-rw-r--r--include/linux/mfd/da9052/led.h39
-rw-r--r--include/linux/mfd/da9052/pm.h81
-rw-r--r--include/linux/mfd/da9052/reg.h929
-rw-r--r--include/linux/mfd/da9052/rtc.h322
-rw-r--r--include/linux/mfd/da9052/tsi.h427
-rw-r--r--include/linux/mfd/da9052/tsi_calibrate.h47
-rw-r--r--include/linux/mfd/da9052/tsi_cfg.h132
-rw-r--r--include/linux/mfd/da9052/tsi_filter.h56
-rw-r--r--include/linux/mfd/da9052/wdt.h83
-rw-r--r--include/linux/regulator/da9052-regulator.h15
32 files changed, 12636 insertions, 0 deletions
diff --git a/drivers/gpio/da9052-gpio.c b/drivers/gpio/da9052-gpio.c
new file mode 100644
index 000000000000..a9c53f219c3e
--- /dev/null
+++ b/drivers/gpio/da9052-gpio.c
@@ -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
index 000000000000..647e580e2131
--- /dev/null
+++ b/drivers/hwmon/da9052-adc.c
@@ -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
index 000000000000..2271b59261fa
--- /dev/null
+++ b/drivers/input/misc/da9052_onkey.c
@@ -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
index 000000000000..3b79cf3debfa
--- /dev/null
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -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
index 000000000000..4ffd0bbe7483
--- /dev/null
+++ b/drivers/input/touchscreen/da9052_tsi_calibrate.c
@@ -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
index 000000000000..16467edf386f
--- /dev/null
+++ b/drivers/input/touchscreen/da9052_tsi_filter.c
@@ -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
index 000000000000..187d4d2372e0
--- /dev/null
+++ b/drivers/leds/leds-da9052.c
@@ -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
index 000000000000..b19eeafbc857
--- /dev/null
+++ b/drivers/mfd/da9052-core.c
@@ -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
index 000000000000..5828b6db4585
--- /dev/null
+++ b/drivers/mfd/da9052-i2c.c
@@ -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
index 000000000000..9dd90c2d19f9
--- /dev/null
+++ b/drivers/mfd/da9052-spi.c
@@ -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
index 000000000000..85561b463df5
--- /dev/null
+++ b/drivers/power/da9052-battery.c
@@ -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
index 000000000000..780c82427b95
--- /dev/null
+++ b/drivers/regulator/da9052-regulator.c
@@ -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
index 000000000000..be80c228d5a3
--- /dev/null
+++ b/drivers/rtc/rtc-da9052.c
@@ -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
index 000000000000..a67a01368010
--- /dev/null
+++ b/drivers/spi/spi_sam.c
@@ -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
index 000000000000..060cd894a267
--- /dev/null
+++ b/drivers/video/backlight/da9052_bl.c
@@ -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
index 000000000000..11e1d75212c3
--- /dev/null
+++ b/drivers/watchdog/da9052_wdt.c
@@ -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
index 000000000000..49c7d181d150
--- /dev/null
+++ b/include/linux/mfd/da9052/adc.h
@@ -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
index 000000000000..ac2404fe46e4
--- /dev/null
+++ b/include/linux/mfd/da9052/bat.h
@@ -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
index 000000000000..9217eb95a77e
--- /dev/null
+++ b/include/linux/mfd/da9052/bl.h
@@ -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
index 000000000000..7652d07f70d3
--- /dev/null
+++ b/include/linux/mfd/da9052/da9052.h
@@ -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
index 000000000000..c46df5d8962e
--- /dev/null
+++ b/include/linux/mfd/da9052/eh.h
@@ -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
index 000000000000..68a24ad9d828
--- /dev/null
+++ b/include/linux/mfd/da9052/gpio.h
@@ -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
index 000000000000..b4145cd2023d
--- /dev/null
+++ b/include/linux/mfd/da9052/led.h
@@ -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
index 000000000000..9a1c4f8b4ea8
--- /dev/null
+++ b/include/linux/mfd/da9052/pm.h
@@ -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
index 000000000000..9daaa02e565f
--- /dev/null
+++ b/include/linux/mfd/da9052/reg.h
@@ -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
index 000000000000..c7fc87dd7eb2
--- /dev/null
+++ b/include/linux/mfd/da9052/rtc.h
@@ -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
index 000000000000..b0f5c2449e4f
--- /dev/null
+++ b/include/linux/mfd/da9052/tsi.h
@@ -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
index 000000000000..a4b42ea079a9
--- /dev/null
+++ b/include/linux/mfd/da9052/tsi_calibrate.h
@@ -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
index 000000000000..729d10316283
--- /dev/null
+++ b/include/linux/mfd/da9052/tsi_cfg.h
@@ -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
index 000000000000..0439a08fa64d
--- /dev/null
+++ b/include/linux/mfd/da9052/tsi_filter.h
@@ -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
index 000000000000..6a77bfc5fd9b
--- /dev/null
+++ b/include/linux/mfd/da9052/wdt.h
@@ -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
index 000000000000..58e6f0bafef6
--- /dev/null
+++ b/include/linux/regulator/da9052-regulator.h
@@ -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