--- /dev/null
+#include <linux/regulator/machine.h>
+#include <mach/sram.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+
+#include <linux/mfd/rt5025.h>
+
+#ifdef CONFIG_MFD_RT5025
+
+static int rt5025_pre_init(struct rt5025_chip *rt5025_chip){
+
+
+ printk("%s,line=%d\n", __func__,__LINE__);
+ int ret;
+ /**********set voltage speed***********************/
+ ret = rt5025_reg_read(rt5025_chip->i2c, 0x08);
+ ret &= (~(3<<0)); //dcdc1 25mv/10us
+ rt5025_reg_write(rt5025_chip->i2c, 0x08,ret);
+
+ ret = rt5025_reg_read(rt5025_chip->i2c, 0x09);
+ ret &= (~(3<<0));//dcdc2 100mv/10us
+ rt5025_reg_write(rt5025_chip->i2c, 0x09,ret);
+
+ ret = rt5025_reg_read(rt5025_chip->i2c, 0x0a);
+ ret &= (~(3<<0));//dcdc3 50mv/12us
+ rt5025_reg_write(rt5025_chip->i2c, 0x0a,ret);
+ /************************************************/
+ /***************set power off voltage***************/
+ ret = rt5025_reg_read(rt5025_chip->i2c, 0x17);
+ ret &= (~(7<<5)); //power off 2.8v
+ rt5025_reg_write(rt5025_chip->i2c, 0x17,ret);
+
+ ret = rt5025_reg_read(rt5025_chip->i2c, 0x17);
+ ret |= (1<<3); //enable DC4 boost
+ rt5025_reg_write(rt5025_chip->i2c, 0x17,ret);
+ /***********************************************/
+ /************************************************/
+ return 0;
+ }
+static int rt5025_post_init(void)
+{
+ struct regulator *dcdc;
+ struct regulator *ldo;
+ int i = 0;
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+ #ifndef CONFIG_RK_CONFIG
+ g_pmic_type = PMIC_TYPE_RT5025;
+ #endif
+ printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type);
+
+ for(i = 0; i < ARRAY_SIZE(rt5025_dcdc_info); i++)
+ {
+ if(rt5025_dcdc_info[i].min_uv == 0 && rt5025_dcdc_info[i].max_uv == 0)
+ continue;
+ dcdc =regulator_get(NULL, rt5025_dcdc_info[i].name);
+
+ regulator_set_voltage(dcdc, rt5025_dcdc_info[i].min_uv, rt5025_dcdc_info[i].max_uv);
+
+ regulator_set_mode(dcdc, REGULATOR_MODE_NORMAL);
+ regulator_enable(dcdc);
+ printk("%s %s =%duV end\n", __func__,rt5025_dcdc_info[i].name, regulator_get_voltage(dcdc));
+ regulator_put(dcdc);
+ udelay(100);
+ }
+
+ for(i = 0; i < ARRAY_SIZE(rt5025_ldo_info); i++)
+ {
+ if(rt5025_ldo_info[i].min_uv == 0 && rt5025_ldo_info[i].max_uv == 0)
+ continue;
+ ldo =regulator_get(NULL, rt5025_ldo_info[i].name);
+ regulator_set_voltage(ldo, rt5025_ldo_info[i].min_uv, rt5025_ldo_info[i].max_uv);
+ regulator_enable(ldo);
+ printk("%s %s =%duV end\n", __func__,rt5025_ldo_info[i].name, regulator_get_voltage(ldo));
+ regulator_put(ldo);
+ }
+
+ printk("%s,line=%d END\n", __func__,__LINE__);
+
+ return 0;
+}
+static struct regulator_consumer_supply rt5025_dcdc1_supply[] = {
+ {
+ .supply = "rt5025-dcdc1",
+ },
+// {
+// .supply = "vdd_cpu",
+// },
+
+};
+static struct regulator_consumer_supply rt5025_dcdc2_supply[] = {
+ {
+ .supply = "rt5025-dcdc2",
+ },
+// {
+// .supply = "vdd_core",
+// },
+};
+static struct regulator_consumer_supply rt5025_dcdc3_supply[] = {
+ {
+ .supply = "rt5025-dcdc3",
+ },
+};
+
+static struct regulator_consumer_supply rt5025_dcdc4_supply[] = {
+ {
+ .supply = "rt5025-dcdc4",
+ },
+};
+
+static struct regulator_consumer_supply rt5025_ldo1_supply[] = {
+ {
+ .supply = "rt5025-ldo1",
+ },
+};
+static struct regulator_consumer_supply rt5025_ldo2_supply[] = {
+ {
+ .supply = "rt5025-ldo2",
+ },
+};
+
+static struct regulator_consumer_supply rt5025_ldo3_supply[] = {
+ {
+ .supply = "rt5025-ldo3",
+ },
+};
+static struct regulator_consumer_supply rt5025_ldo4_supply[] = {
+ {
+ .supply = "rt5025-ldo4",
+ },
+};
+static struct regulator_consumer_supply rt5025_ldo5_supply[] = {
+ {
+ .supply = "rt5025-ldo5",
+ },
+};
+static struct regulator_consumer_supply rt5025_ldo6_supply[] = {
+ {
+ .supply = "rt5025-ldo6",
+ },
+};
+
+static struct regulator_init_data rt5025_dcdc1_info = {
+ .constraints = {
+ .name = "RT5025-DCDC1",
+ .min_uV = 700000,
+ .max_uV = 2275000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS| REGULATOR_CHANGE_MODE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc1_supply),
+ .consumer_supplies = rt5025_dcdc1_supply,
+};
+
+static struct regulator_init_data rt5025_dcdc2_info = {
+ .constraints = {
+ .name = "RT5025-DCDC2",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc2_supply),
+ .consumer_supplies = rt5025_dcdc2_supply,
+};
+
+static struct regulator_init_data rt5025_dcdc3_info = {
+ .constraints = {
+ .name = "RT5025-DCDC3",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc3_supply),
+ .consumer_supplies = rt5025_dcdc3_supply,
+};
+
+static struct regulator_init_data rt5025_dcdc4_info = {
+ .constraints = {
+ .name = "RT5025-DCDC4",
+ .min_uV = 4500000,
+ .max_uV = 5500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_dcdc4_supply),
+ .consumer_supplies = rt5025_dcdc4_supply,
+};
+
+static struct regulator_init_data rt5025_ldo1_info = {
+ .constraints = {
+ .name = "RT5025-LDO1",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo1_supply),
+ .consumer_supplies = rt5025_ldo1_supply,
+};
+
+static struct regulator_init_data rt5025_ldo2_info = {
+ .constraints = {
+ .name = "RT5025-LDO2",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo2_supply),
+ .consumer_supplies = rt5025_ldo2_supply,
+};
+
+static struct regulator_init_data rt5025_ldo3_info = {
+ .constraints = {
+ .name = "RT5025-LDO3",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo3_supply),
+ .consumer_supplies = rt5025_ldo3_supply,
+};
+
+static struct regulator_init_data rt5025_ldo4_info = {
+ .constraints = {
+ .name = "RT5025-LDO4",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo4_supply),
+ .consumer_supplies = rt5025_ldo4_supply,
+};
+
+static struct regulator_init_data rt5025_ldo5_info = {
+ .constraints = {
+ .name = "RT5025-LDO5",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo5_supply),
+ .consumer_supplies = rt5025_ldo5_supply,
+};
+
+static struct regulator_init_data rt5025_ldo6_info = {
+ .constraints = {
+ .name = "RT5025-LDO6",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(rt5025_ldo6_supply),
+ .consumer_supplies = rt5025_ldo6_supply,
+};
+
+static struct rt5025_power_data rt5025_power_data = {
+ .CHGControl2 = {
+ .bitfield = {
+ .CHGBC_EN = 1,
+ .TE = 1,
+ .CCCHG_TIMEOUT = RT5025_CCCHG_TO_6H,
+ .PRECHG_TIMEOUT = RT5025_PRECHG_TO_30M,
+ },
+ },
+ .CHGControl3 = {
+ .bitfield = {
+ .VOREG = 0x23,
+ },
+ },
+ .CHGControl4 = {
+ .bitfield = {
+ .AICR = RT5025_AICR_500MA,
+ .ICC = RT5025_ICC_1P8A,
+ },
+ },
+ .CHGControl5 = {
+ .bitfield = {
+ .DPM = RT5025_DPM_DIS,
+ },
+ },
+ .CHGControl6 = {
+ .bitfield = {
+ .IPREC = RT5025_IPREC_10P,
+ .IEOC = RT5025_IEOC_10P,
+ .VPREC = RT5025_VPREC_3V,
+ },
+ },
+ .CHGControl7 = {
+ .bitfield = {
+ .CHGC_EN = 1,
+ .CHG_DCDC_MODE = 0,
+ .BATD_EN = 0,
+ },
+ },
+};
+
+static struct rt5025_gpio_data rt5025_gpio_data = {
+// .gpio_base = RT5025_GPIO_BASE,
+ .irq_base = IRQ_BOARD_BASE,
+};
+
+static struct rt5025_misc_data rt5025_misc_data = {
+ .RSTCtrl = {
+ .bitfield = {
+ .Action = 2,
+ .Delayed1 = RT5025_RSTDELAY1_1S,
+ .Delayed2 = RT5025_RSTDELAY2_1S,
+ },
+ },
+ .VSYSCtrl = {
+ .bitfield = {
+ .VOFF = RT5025_VOFF_3P1V,
+ },
+ },
+ .PwrOnCfg = {
+ .bitfield = {
+ .PG_DLY = RT5025_PGDLY_100MS,
+ .SHDN_PRESS = RT5025_SHDNPRESS_6S,
+ .LPRESS_TIME = RT5025_LPRESS_1P5S,
+ .START_TIME = RT5025_STARTIME_100MS,
+ },
+ },
+ .SHDNCtrl = {
+ .bitfield = {
+ .SHDN_DLYTIME = RT5025_SHDNDLY_1S,
+ .SHDN_TIMING = 1,
+ .SHDN_CTRL = 0,
+ },
+ },
+ .PwrOffCond = {
+ .bitfield = {
+ .OT_ENSHDN = 1,
+ .PWRON_ENSHDN = 1,
+ .DCDC3LV_ENSHDN = 0,
+ .DCDC2LV_ENSHDN = 0,
+ .DCDC1LV_ENSHDN = 0,
+ .SYSLV_ENSHDN = 0,
+ },
+ },
+};
+
+static struct rt5025_irq_data rt5025_irq_data = {
+ .irq_enable1 = {
+ .bitfield = {
+ .BATABS = 1,
+ .INUSB_PLUGIN = 1,
+ .INUSBOVP = 1,
+ .INAC_PLUGIN = 1,
+ .INACOVP = 1,
+ },
+ },
+ .irq_enable2 = {
+ .bitfield = {
+ .CHTERMI = 1,
+ .CHBATOVI = 1,
+ .CHGOODI_INUSB = 0,
+ .CHBADI_INUSB = 1,
+ .CHSLPI_INUSB = 1,
+ .CHGOODI_INAC = 0,
+ .CHBADI_INAC = 1,
+ .CHSLPI_INAC = 1,
+ },
+ },
+ .irq_enable3 = {
+ .bitfield = {
+ .TIMEOUT_CC = 1,
+ .TIMEOUT_PC = 1,
+ .CHVSREGI = 0,
+ .CHTREGI = 0,
+ .CHRCHGI = 0,
+ },
+ },
+ .irq_enable4 = {
+ .bitfield = {
+ .SYSLV = 0,
+ .DCDC4LVHV = 1,
+ .PWRONLP = 0,
+ .PWRONSP = 0,
+ .DCDC3LV = 1,
+ .DCDC2LV = 1,
+ .DCDC1LV = 1,
+ .OT = 1,
+ },
+ },
+ .irq_enable5 = {
+ .bitfield = {
+ .GPIO0_IE = 0,
+ .GPIO1_IE = 0,
+ .GPIO2_IE = 0,
+ .RESETB = 1,
+ .PWRONF = 0,
+ .PWRONR = 0,
+ .KPSHDN = 1,
+ },
+ },
+};
+
+static void rt5025_charger_event_callback(uint32_t detected)
+{
+ RTINFO("event detected = 0x%08x\n", detected);
+}
+
+static void rt5025_power_event_callback(uint32_t detected)
+{
+ RTINFO("event detected = 0x%08x\n", detected);
+}
+
+static struct rt5025_event_callback rt5025_event_callback = {
+ .charger_event_callback = rt5025_charger_event_callback,
+ .power_event_callkback = rt5025_power_event_callback,
+};
+
+static struct rt5025_platform_data rt5025_data = {
+ .pre_init=rt5025_pre_init,
+ .post_init=rt5025_post_init,
+ .regulator = {
+ &rt5025_dcdc1_info,
+ &rt5025_dcdc2_info,
+ &rt5025_dcdc3_info,
+ &rt5025_dcdc4_info,
+ &rt5025_ldo1_info,
+ &rt5025_ldo2_info,
+ &rt5025_ldo3_info,
+ &rt5025_ldo4_info,
+ &rt5025_ldo5_info,
+ &rt5025_ldo6_info,
+ },
+ .power_data = &rt5025_power_data,
+ .gpio_data = &rt5025_gpio_data,
+ .misc_data = &rt5025_misc_data,
+ .irq_data = &rt5025_irq_data,
+ .cb = &rt5025_event_callback,
+ .intr_pin = 81, //GPIO81
+};
+
+void __sramfunc board_pmu_rt5025_suspend(void)
+{
+}
+void __sramfunc board_pmu_rt5025_resume(void)
+{
+}
+
+
+#endif
+
+
+
+
#include <linux/mfd/rk808.h>
#include <linux/mfd/ricoh619.h>
#include <linux/regulator/rk29-pwm-regulator.h>
+#ifdef CONFIG_MFD_RT5025
+#include <linux/mfd/rt5025.h>
+#endif
#ifdef CONFIG_CW2015_BATTERY
#include <linux/power/cw2015_battery.h>
#include "board-pmu-ricoh619.c"
#endif
+#ifdef CONFIG_MFD_RT5025
+#define RT5025_HOST_IRQ RK30_PIN0_PB3
+
+static struct pmu_info rt5025_dcdc_info[] = {
+ {
+ .name = "rt5025-dcdc1", //arm
+ .min_uv = 1000000,
+ .max_uv = 1000000,
+ },
+ {
+ .name = "rt5025-dcdc2", //logic
+ .min_uv = 1000000,
+ .max_uv = 1000000,
+ },
+
+ {
+ .name = "rt5025-dcdc3", //vccio
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ },
+
+};
+static struct pmu_info rt5025_ldo_info[] = {
+ {
+ .name = "rt5025-ldo1", //vdd10
+ .min_uv = 1000000,
+ .max_uv = 1000000,
+ },
+ {
+ .name = "rt5025-ldo2", //vddjetta
+ .min_uv = 1200000,
+ .max_uv = 1200000,
+ },
+ {
+ .name = "rt5025-ldo3", //vcc18
+ .min_uv = 1800000,
+ .max_uv = 1800000,
+ },
+ {
+ .name = "rt5025-ldo4", //vccjetta
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ },
+ {
+ .name = "rt5025-ldo5", //vcctp
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ },
+ {
+ .name = "rt5025-ldo6", //vccio_wl
+ .min_uv = 1800000,
+ .max_uv = 1800000,
+ },
+
+ };
+
+#include "board-pmu-rt5025.c"
+#endif
+
static struct i2c_board_info __initdata i2c1_info[] = {
},
#endif
+#if defined (CONFIG_MFD_RT5025)
+ {
+ .type = "RT5025",
+ .addr = 0x35,
+ .flags = 0,
+ .irq = RT5025_HOST_IRQ,
+ .platform_data=&rt5025_data,
+ },
+#endif
+
#if defined (CONFIG_RTC_HYM8563)
{
.type = "rtc_hym8563",
}
#endif
+ #if defined(CONFIG_MFD_RT5025)
+ if(pmic_is_rt5025()){
+ rt5025_power_off(); //rt5025 shutdown
+ }
+ #endif
+
gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
while (1);
}
PMIC_TYPE_ACT8846 =3,
PMIC_TYPE_RK808 =4,
PMIC_TYPE_RICOH619 =5,
+ PMIC_TYPE_RT5025 =6,
PMIC_TYPE_MAX,
};
extern __sramdata int g_pmic_type;
#define pmic_is_act8846() (g_pmic_type == PMIC_TYPE_ACT8846)
#define pmic_is_rk808() (g_pmic_type == PMIC_TYPE_RK808)
#define pmic_is_ricoh619() (g_pmic_type == PMIC_TYPE_RICOH619)
+#define pmic_is_rt5025() (g_pmic_type == PMIC_TYPE_RT5025)
struct pmu_info {
char *name;
help
Select this option to enable GPIO driver for the TPS65910
chip family.
+config GPIO_RT5025
+ bool "Richtek RT5025 GPIO support"
+ depends on MFD_RT5025
+ default n
+ help
+ This is the gpio driver for RT5025 PMIC.
endif
obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
+obj-$(CONFIG_GPIO_RT5025) += rt5025-gpio.o
--- /dev/null
+/*
+ * drivers/gpio/rt5025-gpio.c
+ * Driver foo Richtek RT5025 PMIC GPIO
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-gpio.h>
+
+struct rt5025_gpio_info {
+ struct i2c_client *i2c;
+ unsigned gpio_base;
+ unsigned irq_base;
+ struct gpio_chip gpio_chip;
+};
+
+static inline int find_rt5025_gpioreg(unsigned off, int *gpio_reg)
+{
+ int ret = 0;
+ switch (off)
+ {
+ case 0:
+ case 1:
+ case 2:
+ *gpio_reg = RT5025_REG_GPIO0 + off;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int rt5025_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+ int gpio_reg = 0;
+ int ret = 0;
+
+ ret = find_rt5025_gpioreg(offset , &gpio_reg);
+ if (ret < 0)
+ {
+ dev_err(chip->dev, "not a valid gpio index\n");
+ return ret;
+ }
+
+ ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRMASK);
+ if (ret<0)
+ {
+ dev_err(chip->dev, "set gpio input fail\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rt5025_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+ int gpio_reg = 0;
+ int ret = 0;
+
+ ret = find_rt5025_gpioreg(offset, &gpio_reg);
+ if (ret < 0)
+ {
+ dev_err(chip->dev, "not a valid gpio index\n");
+ return ret;
+ }
+
+ ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRSHIFT);
+ if (ret<0)
+ {
+ dev_err(chip->dev, "clr gpio direction fail\n");
+ return ret;
+ }
+
+ ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OUTPUT<<RT5025_GPIO_DIRSHIFT);
+ if (ret<0)
+ {
+ dev_err(chip->dev, "set gpio output dir fail\n");
+ return ret;
+ }
+
+ if (value)
+ ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+ else
+ ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+
+ if (ret<0)
+ {
+ dev_err(chip->dev, "set gpio output value fail\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rt5025_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+ int gpio_reg = 0;
+ int ret = 0;
+
+ ret = find_rt5025_gpioreg(offset, &gpio_reg);
+ if (ret < 0)
+ {
+ dev_err(chip->dev, "not a valid gpio index\n");
+ return ret;
+ }
+
+ ret = rt5025_reg_read(gi->i2c, gpio_reg);
+ if (ret<0)
+ {
+ dev_err(chip->dev, "read gpio register fail\n");
+ return ret;
+ }
+
+ return (ret&RT5025_GPIO_IVALUEMASK)?1:0;
+}
+
+static void rt5025_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
+ int gpio_reg = 0;
+ int ret = 0;
+
+ ret = find_rt5025_gpioreg(offset, &gpio_reg);
+ if (ret < 0)
+ {
+ dev_err(chip->dev, "not a valid gpio index\n");
+ return;
+ }
+
+ if (value)
+ ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+ else
+ ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
+
+ if (ret<0)
+ {
+ dev_err(chip->dev, "read gpio register fail\n");
+ }
+}
+
+static int __devinit rt5025_gpio_probe(struct platform_device *pdev)
+{
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5025_platform_data *pdata = chip->dev->platform_data;
+ struct rt5025_gpio_info *gi;
+ int ret = 0;
+
+ gi = kzalloc(sizeof(*gi), GFP_KERNEL);
+ if (!gi)
+ return -ENOMEM;
+
+ gi->i2c = chip->i2c;
+ gi->gpio_base = pdata->gpio_data->gpio_base;
+ gi->irq_base = pdata->gpio_data->irq_base;
+
+ gi->gpio_chip.direction_input = rt5025_gpio_direction_input;
+ gi->gpio_chip.direction_output = rt5025_gpio_direction_output;
+ gi->gpio_chip.get = rt5025_gpio_get_value;
+ gi->gpio_chip.set = rt5025_gpio_set_value;
+ gi->gpio_chip.can_sleep = 0;
+
+ gi->gpio_chip.base = gi->gpio_base;
+ gi->gpio_chip.ngpio = RT5025_GPIO_NR;
+ gi->gpio_chip.label = pdev->name;
+ gi->gpio_chip.dev = &pdev->dev;
+ gi->gpio_chip.owner = THIS_MODULE;
+
+ ret = gpiochip_add(&gi->gpio_chip);
+ if (ret)
+ goto out_dev;
+
+ platform_set_drvdata(pdev, gi);
+ return ret;
+out_dev:
+ kfree(gi);
+ return ret;
+}
+
+static int __devexit rt5025_gpio_remove(struct platform_device *pdev)
+{
+ int ret;
+ struct rt5025_gpio_info *gi = platform_get_drvdata(pdev);
+
+ ret = gpiochip_remove(&gi->gpio_chip);
+ kfree(gi);
+
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver rt5025_gpio_driver =
+{
+ .driver = {
+ .name = RT5025_DEVICE_NAME "-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_gpio_probe,
+ .remove = __devexit_p(rt5025_gpio_remove),
+};
+
+static int __init rt5025_gpio_init(void)
+{
+ return platform_driver_register(&rt5025_gpio_driver);
+}
+subsys_initcall_sync(rt5025_gpio_init);
+
+static void __exit rt5025_gpio_exit(void)
+{
+ platform_driver_unregister(&rt5025_gpio_driver);
+}
+module_exit(rt5025_gpio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("GPIO driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-gpio");
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
+
+config MFD_RT5025
+ bool "RT5025 PMIC Chip Core driver"
+ depends on I2C
+ select MFD_CORE
+ default n
+ help
+ Enable RT5025 core driver.
+
+config MFD_RT5025_MISC
+ bool "RT5025 PMIC chip misc configuration"
+ depends on MFD_RT5025
+ default n
+ help
+ Enable RT5025 Misc configuration.
+
+config MFD_RT5025_IRQ
+ bool "RT5025_PMIC chip irq driver"
+ depends on MFD_RT5025
+ default n
+ help
+ Enable RT5025 IRQ configuration and interrupt.
+
+config MFD_RT5025_DEBUG
+ bool "RT5025 PMIC Chip Core Debug"
+ depends on MFD_RT5025 && DEBUG_FS
+ default n
+ help
+ Enable RT5025 core debug driver.
+
config MFD_RK610
bool "RK610(Jetta) Multimedia support"
obj-$(CONFIG_MFD_RK808) += rk808.o rk808-irq.o
obj-$(CONFIG_MFD_RK616) += rk616-core.o rk616-vif.o
obj-$(CONFIG_MFD_RICOH619) += ricoh619.o ricoh619-irq.o
+obj-$(CONFIG_MFD_RT5025) += rt5025-i2c.o rt5025-core.o
+obj-$(CONFIG_MFD_RT5025_MISC) += rt5025-misc.o
+obj-$(CONFIG_MFD_RT5025_IRQ) += rt5025-irq.o
+obj-$(CONFIG_MFD_RT5025_DEBUG) += rt5025-debug.o
--- /dev/null
+/*
+ * drivers/mfd/rt5025-core.c
+ * Driver for Richtek RT5025 Core PMIC
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+
+#include <linux/mfd/rt5025.h>
+
+#ifdef CONFIG_REGULATOR_RT5025
+#define RT5025_VR_DEVS(_id) \
+{ \
+ .name = RT5025_DEVICE_NAME "-regulator", \
+ .num_resources = 0, \
+ .id = RT5025_ID_##_id, \
+}
+
+static struct mfd_cell regulator_devs[] = {
+ RT5025_VR_DEVS(DCDC1),
+ RT5025_VR_DEVS(DCDC2),
+ RT5025_VR_DEVS(DCDC3),
+ RT5025_VR_DEVS(DCDC4),
+ RT5025_VR_DEVS(LDO1),
+ RT5025_VR_DEVS(LDO2),
+ RT5025_VR_DEVS(LDO3),
+ RT5025_VR_DEVS(LDO4),
+ RT5025_VR_DEVS(LDO5),
+ RT5025_VR_DEVS(LDO6),
+};
+#endif /* CONFIG_REGULATOR_RT5025 */
+
+#ifdef CONFIG_POWER_RT5025
+static struct mfd_cell power_devs[] = {
+{
+ .name = RT5025_DEVICE_NAME "-power",
+ .id = -1,
+ .num_resources = 0,
+},
+};
+#endif /* CONFIG_POWER_RT5025 */
+
+#ifdef CONFIG_GPIO_RT5025
+static struct mfd_cell gpio_devs[] = {
+{
+ .name = RT5025_DEVICE_NAME "-gpio",
+ .id = -1,
+ .num_resources = 0,
+},
+};
+#endif /* CONFIG_GPIO_RT5025 */
+
+#ifdef CONFIG_MFD_RT5025_MISC
+static struct mfd_cell misc_devs[] = {
+{
+ .name = RT5025_DEVICE_NAME "-misc",
+ .id = -1,
+ .num_resources = 0,
+},
+};
+#endif /* CONFIG_MFD_RT5025_MISC */
+
+#ifdef CONFIG_MFD_RT5025_IRQ
+static struct mfd_cell irq_devs[] = {
+{
+ .name = RT5025_DEVICE_NAME "-irq",
+ .id = -1,
+ .num_resources = 0,
+},
+};
+#endif /* CONFIG_MFD_RT5025_IRQ */
+
+#ifdef CONFIG_MFD_RT5025_DEBUG
+static struct mfd_cell debug_devs[] = {
+{
+ .name = RT5025_DEVICE_NAME "-debug",
+ .id = -1,
+ .num_resources = 0,
+},
+};
+#endif /* CONFIG_MFD_RT5025_DEBUG */
+
+int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_data *pdata)
+{
+ int ret = 0;
+
+ RTINFO("Start to initialize all device\n");
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+ #ifdef CONFIG_REGULATOR_RT5025
+ if (pdata && pdata->regulator[0]) {
+ RTINFO("mfd add regulators dev\n");
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+ ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0],
+ ARRAY_SIZE(regulator_devs),
+ NULL, 0, NULL);
+ #else
+ ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0],
+ ARRAY_SIZE(regulator_devs),
+ NULL, 0);
+ #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ goto out_dev;
+ }
+ }
+ #endif /* CONFIG_REGULATOR_RT5025 */
+
+ #ifdef CONFIG_POWER_RT5025
+ if (pdata && pdata->power_data) {
+ RTINFO("mfd add power dev\n");
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+ ARRAY_SIZE(power_devs),
+ NULL, 0,NULL);
+ #else
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+ ARRAY_SIZE(power_devs),
+ NULL, 0);
+ #endif
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add power supply "
+ "subdev\n");
+ goto out_dev;
+ }
+ }
+ #endif /* CONFIG_MFD_RT5025 */
+
+ //Initialize the RT5025_GPIO
+ #ifdef CONFIG_GPIO_RT5025
+ if (pdata && pdata->gpio_data) {
+ RTINFO("mfd add gpios dev\n");
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+ ret = mfd_add_devices(chip->dev, 0, &gpio_devs[0],
+ ARRAY_SIZE(gpio_devs),
+ NULL, 0, NULL);
+ #else
+ ret = mfd_add_devices(chip->dev, 0, &gpio_devs[0],
+ ARRAY_SIZE(gpio_devs),
+ NULL, 0);
+ #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add gpio subdev\n");
+ goto out_dev;
+ }
+ }
+ #endif /* CONFIG_GPIO_RT5025 */
+\
+ #ifdef CONFIG_MFD_RT5025_MISC
+ if (pdata && pdata->misc_data) {
+ RTINFO("mfd add misc dev\n");
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+ ret = mfd_add_devices(chip->dev, 0, &misc_devs[0],
+ ARRAY_SIZE(misc_devs),
+ NULL, 0, NULL);
+ #else
+ ret = mfd_add_devices(chip->dev, 0, &misc_devs[0],
+ ARRAY_SIZE(misc_devs),
+ NULL, 0);
+ #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add misc subdev\n");
+ goto out_dev;
+ }
+ }
+ #endif /* CONFIG_MFD_RT5025_MISC */
+
+ #ifdef CONFIG_MFD_RT5025_IRQ
+ if (pdata && pdata->irq_data) {
+ RTINFO("mfd add irq dev\n");
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+ ret = mfd_add_devices(chip->dev, 0, &irq_devs[0],
+ ARRAY_SIZE(irq_devs),
+ NULL, 0, NULL);
+ #else
+ ret = mfd_add_devices(chip->dev, 0, &irq_devs[0],
+ ARRAY_SIZE(irq_devs),
+ NULL, 0);
+ #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add irq subdev\n");
+ goto out_dev;
+ }
+ }
+ #endif /* CONFIG_MFD_RT5025_IRQ */
+#if 0
+ #ifdef CONFIG_MFD_RT5025_DEBUG
+ RTINFO("mfd add debug dev\n");
+ printk("%s,line=%d\n", __func__,__LINE__);
+ #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
+ ret = mfd_add_devices(chip->dev, 0, &debug_devs[0],
+ ARRAY_SIZE(debug_devs),
+ NULL, 0, NULL);
+ #else
+ ret = mfd_add_devices(chip->dev, 0, &debug_devs[0],
+ ARRAY_SIZE(debug_devs),
+ NULL, 0);
+ #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add debug subdev\n");
+ goto out_dev;
+ }
+ #endif /* CONFIG_MFD_RT5025_DEBUG */
+#endif
+
+ RTINFO("Initialize all device successfully\n");
+ return ret;
+out_dev:
+ mfd_remove_devices(chip->dev);
+ return ret;
+}
+subsys_initcall_sync(rt5025_core_init);
+
+int __devexit rt5025_core_deinit(struct rt5025_chip *chip)
+{
+ mfd_remove_devices(chip->dev);
+ return 0;
+}
+EXPORT_SYMBOL(rt5025_core_deinit);
--- /dev/null
+/*
+ * drivers/mfd/rt5025-debug.c
+ * Driver foo Richtek RT5025 PMIC Debug
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/string.h>
+
+#include <linux/mfd/rt5025.h>
+
+struct rt5025_debug_info {
+ struct i2c_client *i2c;
+};
+
+static struct i2c_client *client;
+static struct dentry *debugfs_rt_dent;
+static struct dentry *debugfs_peek;
+static struct dentry *debugfs_poke;
+
+static unsigned char read_data;
+
+static int reg_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+ char *token;
+ int base, cnt;
+
+ token = strsep(&buf, " ");
+
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token != NULL) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (strict_strtoul(token, base, ¶m1[cnt]) != 0)
+ return -EINVAL;
+
+ token = strsep(&buf, " ");
+ }
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static ssize_t reg_debug_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[8];
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data);
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf));
+}
+
+static ssize_t reg_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char *access_str = filp->private_data;
+ char lbuf[32];
+ int rc;
+ long int param[5];
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+
+ if (!strcmp(access_str, "poke")) {
+ /* write */
+ rc = get_parameters(lbuf, param, 2);
+ if ((param[0] <= 0xFF) && (param[1] <= 0xFF) && (rc == 0))
+ {
+ rt5025_reg_write(client, param[0], (unsigned char)param[1]);
+ }
+ else
+ rc = -EINVAL;
+ } else if (!strcmp(access_str, "peek")) {
+ /* read */
+ rc = get_parameters(lbuf, param, 1);
+ if ((param[0] <= 0xFF) && (rc == 0))
+ {
+ read_data = rt5025_reg_read(client, param[0]);
+ }
+ else
+ rc = -EINVAL;
+ }
+
+ if (rc == 0)
+ rc = cnt;
+
+ return rc;
+}
+
+static const struct file_operations reg_debug_ops = {
+ .open = reg_debug_open,
+ .write = reg_debug_write,
+ .read = reg_debug_read
+};
+
+static int __devinit rt5025_debug_probe(struct platform_device *pdev)
+{
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5025_debug_info *di;
+
+ di = kzalloc(sizeof(*di), GFP_KERNEL);
+ if (!di)
+ return -ENOMEM;
+
+ di->i2c = chip->i2c;
+
+ RTINFO("add debugfs for core RT5025");
+ client = chip->i2c;
+ debugfs_rt_dent = debugfs_create_dir("rt5025_dbg", 0);
+ if (!IS_ERR(debugfs_rt_dent)) {
+ debugfs_peek = debugfs_create_file("peek",
+ S_IFREG | S_IRUGO, debugfs_rt_dent,
+ (void *) "peek", ®_debug_ops);
+
+ debugfs_poke = debugfs_create_file("poke",
+ S_IFREG | S_IRUGO, debugfs_rt_dent,
+ (void *) "poke", ®_debug_ops);
+ }
+
+ platform_set_drvdata(pdev, di);
+
+ return 0;
+}
+
+static int __devexit rt5025_debug_remove(struct platform_device *pdev)
+{
+ struct rt5025_debug_info *di = platform_get_drvdata(pdev);
+
+ if (!IS_ERR(debugfs_rt_dent))
+ debugfs_remove_recursive(debugfs_rt_dent);
+
+ kfree(di);
+ return 0;
+}
+
+static struct platform_driver rt5025_debug_driver =
+{
+ .driver = {
+ .name = RT5025_DEVICE_NAME "-debug",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_debug_probe,
+ .remove = __devexit_p(rt5025_debug_remove),
+};
+
+static int __init rt5025_debug_init(void)
+{
+ return platform_driver_register(&rt5025_debug_driver);
+}
+subsys_initcall_sync(rt5025_debug_init);
+
+static void __exit rt5025_debug_exit(void)
+{
+ platform_driver_unregister(&rt5025_debug_driver);
+}
+module_exit(rt5025_debug_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Debug driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-debug");
--- /dev/null
+/* drivers/mfd/rt5025-i2c.c
+ * I2C Driver for Richtek RT5025
+ * Multi function device - multi functional baseband PMIC
+ *
+ * Copyright (C) 2013
+ * Author: CY Huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/mfd/rt5025.h>
+
+static inline int rt5025_read_device(struct i2c_client *i2c,
+ int reg, int bytes, void *dest)
+{
+ int ret;
+ if (bytes > 1)
+ ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
+ else {
+ ret = i2c_smbus_read_byte_data(i2c, reg);
+ if (ret < 0)
+ return ret;
+ *(unsigned char *)dest = (unsigned char)ret;
+ }
+
+ return ret;
+}
+
+int rt5025_reg_block_read(struct i2c_client *i2c, \
+ int reg, int bytes, void *dest)
+{
+ return rt5025_read_device(i2c, reg, bytes, dest);
+}
+EXPORT_SYMBOL(rt5025_reg_block_read);
+#if 0
+int rt5025_reg_read(struct i2c_client *i2c, int reg)
+{
+ struct rt5025_chip* chip = i2c_get_clientdata(i2c);
+ int ret;
+ RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n",
+ (unsigned int)i2c,(unsigned int)reg);
+ mutex_lock(&chip->io_lock);
+ ret = i2c_smbus_read_byte_data(i2c, reg);
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(rt5025_reg_read);
+
+int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data)
+{
+ struct rt5025_chip* chip = i2c_get_clientdata(i2c);
+ int ret;
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+// RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n",
+ // (unsigned int)i2c,(unsigned int)reg,(unsigned int)data);
+ mutex_lock(&chip->io_lock);
+printk("%s,line=%d \n", __func__,__LINE__);
+
+ ret = i2c_smbus_write_byte_data(i2c, reg, data);
+ mutex_unlock(&chip->io_lock);
+ printk("%s,line=%d %d \n", __func__,__LINE__,ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(rt5025_reg_write);
+#else
+int rt5025_reg_read(struct i2c_client *i2c, int reg)
+{
+ struct i2c_adapter *adap;
+ struct i2c_msg msgs[2];
+ int ret;
+ unsigned char *dest;
+ u8 val;
+
+ dest = &val;
+
+ if(!i2c)
+ return ret;
+
+ adap = i2c->adapter;
+
+ msgs[0].addr = i2c->addr;
+ msgs[0].buf = ®
+ msgs[0].flags = i2c->flags;
+ msgs[0].len = 1;
+ msgs[0].scl_rate = 200*1000;
+
+ msgs[1].buf = dest;
+ msgs[1].addr = i2c->addr;
+ msgs[1].flags = i2c->flags | I2C_M_RD;
+ msgs[1].len = 1;
+ msgs[1].scl_rate = 200*1000;
+ ret = i2c_transfer(adap, msgs, 2);
+
+// printk("***run in %s %d msgs[1].buf = %d\n",__FUNCTION__,__LINE__,*(msgs[1].buf));
+
+ return val;
+}
+EXPORT_SYMBOL(rt5025_reg_read);
+
+int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data)
+{
+
+ int ret=-1;
+
+ struct i2c_adapter *adap;
+ struct i2c_msg msg;
+ char tx_buf[2];
+
+ if(!i2c)
+ return ret;
+
+ adap = i2c->adapter;
+ tx_buf[0] = reg;
+ tx_buf[1] = data;
+
+ msg.addr = i2c->addr;
+ msg.buf = &tx_buf[0];
+ msg.len = 1 +1;
+ msg.flags = i2c->flags;
+ msg.scl_rate = 200*1000;
+
+ ret = i2c_transfer(adap, &msg, 1);
+ return ret;
+}
+EXPORT_SYMBOL(rt5025_reg_write);
+#endif
+int rt5025_assign_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask, unsigned char data)
+{
+ struct rt5025_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char value;
+ int ret;
+ mutex_lock(&chip->io_lock);
+
+ ret = rt5025_read_device(i2c, reg, 1, &value);
+
+ if (ret < 0)
+ goto out;
+ value &= ~mask;
+ value |= (data&mask);
+ ret = rt5025_reg_write(i2c,reg,value);
+out:
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(rt5025_assign_bits);
+
+int rt5025_set_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask)
+{
+ return rt5025_assign_bits(i2c,reg,mask,mask);
+}
+EXPORT_SYMBOL(rt5025_set_bits);
+
+int rt5025_clr_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask)
+{
+ return rt5025_assign_bits(i2c,reg,mask,0);
+}
+EXPORT_SYMBOL(rt5025_clr_bits);
+
+static int __devinit rt5025_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct rt5025_platform_data *pdata = client->dev.platform_data;
+ struct rt5025_chip *chip;
+ int ret = 0;
+ u8 val;
+
+ if (!pdata)
+ return -EINVAL;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->irq = client->irq;
+ chip->i2c = client;
+ chip->dev = &client->dev;
+
+#if 0
+ if (pdata->event_callback)
+ {
+ chip->event_callback = kzalloc(sizeof(struct rt5025_event_callback), GFP_KERNEL);
+ memcpy(chip->event_callback, pdata->event_callback, sizeof(struct rt5025_event_callback));
+ }
+#endif /* #if 0 */
+
+ i2c_set_clientdata(client, chip);
+ mutex_init(&chip->io_lock);
+
+ rt5025_read_device(client,0x00,1,&val);
+ if (val != 0x81){
+ printk("The PMIC is not RT5025\n");
+ return 0;
+ }
+ ret = rt5025_core_init(chip, pdata);
+ if (ret < 0)
+ dev_err(chip->dev, "rt5025_core_init_fail\n");
+ else
+ pr_info("RT5025 Initialize successfully\n");
+
+ if (pdata && pdata->pre_init) {
+ ret = pdata->pre_init(chip);
+ if (ret != 0) {
+ dev_err(chip->dev, "pre_init() failed: %d\n", ret);
+ }
+ }
+
+ if (pdata && pdata->post_init) {
+ ret = pdata->post_init();
+ if (ret != 0) {
+ dev_err(chip->dev, "post_init() failed: %d\n", ret);
+ }
+ }
+
+ return ret;
+
+}
+
+static int __devexit rt5025_i2c_remove(struct i2c_client *client)
+{
+ struct rt5025_chip *chip = i2c_get_clientdata(client);
+ rt5025_core_deinit(chip);
+ #if 0
+ if (chip->event_callback)
+ kfree(chip->event_callback);a
+ #endif
+ kfree(chip);
+ return 0;
+}
+
+static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct rt5025_chip *chip = i2c_get_clientdata(client);
+ chip->suspend = 1;
+ return 0;
+}
+
+static int rt5025_i2c_resume(struct i2c_client *client)
+{
+ struct rt5025_chip *chip = i2c_get_clientdata(client);
+ chip->suspend = 0;
+ return 0;
+}
+
+static const struct i2c_device_id rt5025_id_table[] = {
+ { RT5025_DEVICE_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, rt5025_id_table);
+
+static struct i2c_driver rt5025_driver = {
+ .driver = {
+ .name = RT5025_DEVICE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_i2c_probe,
+ .remove = __devexit_p(rt5025_i2c_remove),
+ .suspend = rt5025_i2c_suspend,
+ .resume = rt5025_i2c_resume,
+ .id_table = rt5025_id_table,
+};
+
+static int __init rt5025_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&rt5025_driver);
+ if (ret != 0)
+ pr_err("Failed to register RT5025 I2C driver: %d\n", ret);
+ return ret;
+}
+subsys_initcall_sync(rt5025_i2c_init);
+
+static void __exit rt5025_i2c_exit(void)
+{
+ i2c_del_driver(&rt5025_driver);
+}
+module_exit(rt5025_i2c_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("I2C Driver for Richtek RT5025");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
--- /dev/null
+/*
+ * drivers/mfd/rt5025-irq.c
+ * Driver foo Richtek RT5025 PMIC irq
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-irq.h>
+
+struct rt5025_irq_info {
+ struct i2c_client *i2c;
+ struct device *dev;
+ struct rt5025_chip *chip;
+ struct workqueue_struct *wq;
+ struct rt5025_event_callback *event_cb;
+ struct delayed_work delayed_work;
+ int intr_pin;
+ int irq;
+};
+
+static void rt5025_work_func(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work);
+ struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(delayed_work, struct rt5025_irq_info, delayed_work);
+ unsigned char irq_stat[10] = {0};
+ uint32_t chg_event = 0, pwr_event = 0;
+
+ if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0)
+ {
+ RTINFO("irq1->%02x, irq2->%02x, irq3->%02x\n", irq_stat[1], irq_stat[3], irq_stat[5]);
+ RTINFO("irq4->%02x, irq5->%02x\n", irq_stat[7], irq_stat[9]);
+ RTINFO("stat value = %02x\n", rt5025_reg_read(ii->i2c, RT5025_REG_CHGSTAT));
+
+ chg_event = irq_stat[1]<<16 | irq_stat[3]<<8 | irq_stat[5];
+ pwr_event = irq_stat[7]<<8 | irq_stat[9];
+ #ifdef CONFIG_POWER_RT5025
+ if (chg_event & CHARGER_DETECT_MASK)
+ rt5025_power_charge_detect(ii->chip->power_info);
+ #endif /* CONFIG_POWER_RT5025 */
+ if (ii->event_cb)
+ {
+ if (chg_event)
+ ii->event_cb->charger_event_callback(chg_event);
+ if (pwr_event)
+ ii->event_cb->power_event_callkback(pwr_event);
+ }
+ }
+ else
+ dev_err(ii->dev, "read irq stat io fail\n");
+
+ #ifdef CONFIG_POWER_RT5025
+ rt5025_power_passirq_to_gauge(ii->chip->power_info);
+ #endif /* CONFIG_POWER_RT5025 */
+
+ enable_irq(ii->irq);
+}
+
+static irqreturn_t rt5025_interrupt(int irqno, void *param)
+{
+ struct rt5025_irq_info *ii = (struct rt5025_irq_info *)param;
+
+ disable_irq_nosync(ii->irq);
+ queue_delayed_work(ii->wq, &ii->delayed_work, 0);
+ return IRQ_HANDLED;
+}
+
+static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii)
+{
+ int ret;
+
+ RTINFO("\n");
+ ii->wq = create_workqueue("rt5025_wq");
+ INIT_DELAYED_WORK(&ii->delayed_work, rt5025_work_func);
+
+ if (gpio_is_valid(ii->intr_pin))
+ {
+ ret = gpio_request(ii->intr_pin, "rt5025_interrupt");
+ if (ret)
+ return ret;
+
+ ret = gpio_direction_input(ii->intr_pin);
+ if (ret)
+ return ret;
+
+ if (request_irq(ii->irq, rt5025_interrupt, IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED, "RT5025_IRQ", ii))
+ {
+ dev_err(ii->dev, "couldn't allocate IRQ_NO(%d) !\n", ii->irq);
+ return -EINVAL;
+ }
+ enable_irq_wake(ii->irq);
+
+ if (!gpio_get_value(ii->intr_pin))
+ {
+ disable_irq_nosync(ii->irq);
+ queue_delayed_work(ii->wq, &ii->delayed_work, 0);
+ }
+ }
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static void __devexit rt5025_interrupt_deinit(struct rt5025_irq_info* ii)
+{
+ if (ii->irq)
+ free_irq(ii->irq, ii);
+
+ if (ii->wq)
+ {
+ cancel_delayed_work_sync(&ii->delayed_work);
+ flush_workqueue(ii->wq);
+ destroy_workqueue(ii->wq);
+ }
+}
+
+static int __devinit rt5025_irq_reg_init(struct rt5025_irq_info* ii, struct rt5025_irq_data* irq_data)
+{
+ RTINFO("\n");
+ // will just enable the interrupt that we want
+ rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_data->irq_enable1.val);
+ rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_data->irq_enable2.val);
+ rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_data->irq_enable3.val);
+ rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, irq_data->irq_enable4.val);
+ rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, irq_data->irq_enable5.val);
+ return 0;
+}
+
+static int __devinit rt5025_irq_probe(struct platform_device *pdev)
+{
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5025_platform_data *pdata = chip->dev->platform_data;
+ struct rt5025_irq_info *ii;
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+ RTINFO("\n");
+ ii = kzalloc(sizeof(*ii), GFP_KERNEL);
+ if (!ii)
+ return -ENOMEM;
+
+ ii->i2c = chip->i2c;
+ ii->dev = &pdev->dev;
+ ii->chip = chip;
+ ii->intr_pin = pdata->intr_pin;
+ ii->irq = gpio_to_irq(pdata->intr_pin);
+ if (pdata->cb)
+ ii->event_cb = pdata->cb;
+
+ rt5025_irq_reg_init(ii, pdata->irq_data);
+ rt5025_interrupt_init(ii);
+
+ platform_set_drvdata(pdev, ii);
+ return 0;
+}
+
+static int __devexit rt5025_irq_remove(struct platform_device *pdev)
+{
+ struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
+
+ rt5025_interrupt_deinit(ii);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver rt5025_irq_driver =
+{
+ .driver = {
+ .name = RT5025_DEVICE_NAME "-irq",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_irq_probe,
+ .remove = __devexit_p(rt5025_irq_remove),
+};
+
+static int __init rt5025_irq_init(void)
+{
+ return platform_driver_register(&rt5025_irq_driver);
+}
+subsys_initcall_sync(rt5025_irq_init);
+
+static void __exit rt5025_irq_exit(void)
+{
+ platform_driver_unregister(&rt5025_irq_driver);
+}
+module_exit(rt5025_irq_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("IRQ driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-irq");
--- /dev/null
+/*
+ * drivers/mfd/rt5025-misc.c
+ * Driver foo Richtek RT5025 PMIC Misc Part
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-misc.h>
+
+struct rt5025_misc_info {
+ struct i2c_client *i2c;
+};
+
+static struct i2c_client *g_shdn;
+void rt5025_power_off(void)
+{
+ rt5025_set_bits(g_shdn, RT5025_SHDNCTRL_REG, RT5025_SHDNCTRL_MASK);
+}
+EXPORT_SYMBOL(rt5025_power_off);
+
+static int __devinit rt5025_misc_reg_init(struct i2c_client *client, struct rt5025_misc_data *md)
+{
+ int ret = 0;
+
+ rt5025_reg_write(client, RT5025_RESETCTRL_REG, md->RSTCtrl.val);
+ rt5025_assign_bits(client, RT5025_VSYSULVO_REG, RT5025_VSYSOFF_MASK, md->VSYSCtrl.val);
+ rt5025_reg_write(client, RT5025_PWRONCTRL_REG, md->PwrOnCfg.val);
+ rt5025_reg_write(client, RT5025_SHDNCTRL_REG, md->SHDNCtrl.val);
+ rt5025_reg_write(client, RT5025_PWROFFEN_REG, md->PwrOffCond.val);
+
+ return ret;
+}
+
+static int __devinit rt5025_misc_probe(struct platform_device *pdev)
+{
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5025_platform_data *pdata = chip->dev->platform_data;
+ struct rt5025_misc_info *mi;
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+ mi = kzalloc(sizeof(*mi), GFP_KERNEL);
+ if (!mi)
+ return -ENOMEM;
+
+ mi->i2c = chip->i2c;
+ rt5025_misc_reg_init(mi->i2c, pdata->misc_data);
+
+ //for shutdown control
+ g_shdn = chip->i2c;
+
+ platform_set_drvdata(pdev, mi);
+ return 0;
+}
+
+static int __devexit rt5025_misc_remove(struct platform_device *pdev)
+{
+ struct rt5025_misc_info *mi = platform_get_drvdata(pdev);
+
+ kfree(mi);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver rt5025_misc_driver =
+{
+ .driver = {
+ .name = RT5025_DEVICE_NAME "-misc",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_misc_probe,
+ .remove = __devexit_p(rt5025_misc_remove),
+};
+
+static int __init rt5025_misc_init(void)
+{
+ return platform_driver_register(&rt5025_misc_driver);
+}
+subsys_initcall_sync(rt5025_misc_init);
+
+static void __exit rt5025_misc_exit(void)
+{
+ platform_driver_unregister(&rt5025_misc_driver);
+}
+module_exit(rt5025_misc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Misc driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-misc");
config TWL60xx_VBAT_LOW_DETECTION
tristate "Support for twl60xx low battery detection."
default n
+
+config POWER_RT5025
+ bool "RT5025 Pmic Chip Power Driver"
+ depends on MFD_RT5025
+ default n
+ help
+ Enable RT5025 Power/Gauge part driver.
config CHARGER_SMB347
tristate "Summit Microelectronics SMB347 Battery Charger"
obj-$(CONFIG_BATTERY_RK30_ADC_FAC) += rk30_factory_adc_battery.o
obj-$(CONFIG_CW2015_BATTERY) += cw2015_battery.o
obj-$(CONFIG_BATTERY_RICOH619) += ricoh619-battery.o
+obj-$(CONFIG_POWER_RT5025) += rt5025-power.o rt5025-gauge.o
\ No newline at end of file
--- /dev/null
+/*
+ * rt5025_gauge.c
+ * fuel-gauge driver
+ * revision 0.1
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/android_alarm.h>
+#include <linux/mfd/rt5025.h>
+#include <linux/power/rt5025-gauge.h>
+
+#define RT5025_REG_IRQ_CTL 0x50
+#define RT5025_REG_IRQ_FLAG 0x51
+#define RT5025_REG_VALRT_MAXTH 0x53
+#define RT5025_REG_VALRT_MIN1TH 0x54
+#define RT5025_REG_VALRT_MIN2TH 0x55
+#define RT5025_REG_TALRT_MAXTH 0x56
+#define RT5025_REG_TALRT_MINTH 0x57
+#define RT5025_REG_VCELL_MSB 0x58
+#define RT5025_REG_VCELL_LSB 0x59
+#define RT5025_REG_INT_TEMPERATUE_MSB 0x5B
+#define RT5025_REG_INT_TEMPERATUE_LSB 0x5C
+#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E
+#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F
+#define RT5025_REG_TIMER 0x60
+#define RT5025_REG_CHANNEL_MSB 0x62
+#define RT5025_REG_CHANNEL_LSB 0x63
+#define RT5025_REG_CURRENT_MSB 0x76
+#define RT5025_REG_CURRENT_LSB 0x77
+#define RT5025_REG_QCHGH_MSB 0x78
+#define RT5025_REG_QCHGH_LSB 0x79
+#define RT5025_REG_QCHGL_MSB 0x7A
+#define RT5025_REG_QCHGL_LSB 0x7B
+#define RT5025_REG_QDCHGH_MSB 0x7C
+#define RT5025_REG_QDCHGH_LSB 0x7D
+#define RT5025_REG_QDCHGL_MSB 0x7E
+#define RT5025_REG_QDCHGL_LSB 0x7F
+
+#define IRQ_CTL_BIT_TMX (1 << 5)
+#define IRQ_CTL_BIT_TMN (1 << 4)
+#define IRQ_CTL_BIT_VMX (1 << 2)
+#define IRQ_CTL_BIT_VMN1 (1 << 1)
+#define IRQ_CTL_BIT_VMN2 (1 << 0)
+
+#define IRQ_FLG_BIT_TMX (1 << 5)
+#define IRQ_FLG_BIT_TMN (1 << 4)
+#define IRQ_FLG_BIT_VMX (1 << 2)
+#define IRQ_FLG_BIT_VMN1 (1 << 1)
+#define IRQ_FLG_BIT_VMN2 (1 << 0)
+
+#define CHANNEL_H_BIT_CLRQDCHG (1 << 7)
+#define CHANNEL_H_BIT_CLRQCHG (1 << 6)
+
+#define CHANNEL_L_BIT_CADC_EN (1 << 7)
+#define CHANNEL_L_BIT_INTEMPCH (1 << 6)
+#define CHANNEL_L_BIT_AINCH (1 << 2)
+#define CHANNEL_L_BIT_VBATSCH (1 << 1)
+#define CHANNEL_L_BIT_VADC_EN (1 << 0)
+
+#define NORMAL_POLL 10 /* 10 sec */
+#define SUSPEND_POLL (30*60) /* 30 min */
+
+#define HIGH_TEMP_THRES 650
+#define HIGH_TEMP_RECOVER 430
+#define LOW_TEMP_THRES (-30)
+#define LOW_TEMP_RECOVER 0
+#define TEMP_ABNORMAL_COUNT 3
+
+#define TALRTMAX_VALUE 0x38 //65.39'C 0x9
+#define TALRTMIN_VALUE 0x11 //-18.75'C 0x17
+#define VALRTMAX_VALUE 0xDC //4297mV
+#define VALRTMIN1_VALUE 0xB8 //3600mV
+#define VALRTMIN2_VALUE 0x99 //3000mV
+#define TRLS_VALUE 55 //5'C
+#define VRLS_VALUE 100 //100mV
+
+#define IRQ_THRES_UNIT 1953
+
+struct rt5025_gauge_chip {
+ struct i2c_client *client;
+ struct rt5025_power_info *info;
+ struct rt5025_gauge_callbacks cb;
+
+ struct power_supply battery;
+
+ struct delayed_work monitor_work;
+ struct wake_lock monitor_wake_lock;
+ struct alarm wakeup_alarm;
+
+ bool suspend_poll;
+ ktime_t last_poll;
+
+ /* battery voltage */
+ u16 vcell;
+ /* battery current */
+ s16 curr;
+ /* battery current offset */
+ u8 curr_offset;
+ /* AIN voltage */
+ u16 ain_volt;
+ /* battery external temperature */
+ s16 ext_temp;
+ /* charge coulomb counter */
+ u32 chg_cc;
+ u32 chg_cc_unuse;
+ /* discharge coulomb counter */
+ u32 dchg_cc;
+ u32 dchg_cc_unuse;
+ /* battery capacity */
+ u8 soc;
+ u16 time_interval;
+ u16 pre_gauge_timer;
+
+ u8 online;
+ u8 status;
+ u8 health;
+
+ /* IRQ flag */
+ u8 irq_flag;
+
+ /* max voltage IRQ flag */
+ bool max_volt_irq;
+ /* min voltage1 IRQ flag */
+ bool min_volt1_irq;
+ /* min voltage2 IRQ flag */
+ bool min_volt2_irq;
+ /* max temperature IRQ flag */
+ bool max_temp_irq;
+ /* min temperature IRQ flag */
+ bool min_temp_irq;
+
+ u8 temp_high_cnt;
+ u8 temp_low_cnt;
+ u8 temp_recover_cnt;
+};
+
+struct rt5025_gauge_chip *chip;
+u8 irq_thres[LAST_TYPE];
+
+void rt5025_set_status(int status)
+{
+ chip->status = status;
+}
+
+static int rt5025_read_reg(struct i2c_client *client,
+ u8 reg, u8 *data, u8 len)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msgs[2];
+ int ret;
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = client->flags;
+ msgs[0].len = 1;
+ msgs[0].buf = ®
+ msgs[0].scl_rate = 200*1000;
+
+ msgs[1].addr = client->addr;
+ msgs[1].flags = client->flags | I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = data;
+ msgs[1].scl_rate = 200*1000;
+
+ ret = i2c_transfer(adap, msgs, 2);
+
+ return (ret == 2)? len : ret;
+}
+
+static int rt5025_write_reg(struct i2c_client *client,
+ u8 reg, u8 *data, u8 len)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+ int ret;
+ char *tx_buf = (char *)kmalloc(len + 1, GFP_KERNEL);
+
+ if(!tx_buf)
+ return -ENOMEM;
+ tx_buf[0] = reg;
+ memcpy(tx_buf+1, data, len);
+
+ msg.addr = client->addr;
+ msg.flags = client->flags;
+ msg.len = len + 1;
+ msg.buf = (char *)tx_buf;
+ msg.scl_rate = 200*1000;
+ ret = i2c_transfer(adap, &msg, 1);
+ kfree(tx_buf);
+ return (ret == 1) ? len : ret;
+}
+
+static void rt5025_gauge_alarm(struct alarm *alarm)
+{
+ wake_lock(&chip->monitor_wake_lock);
+ schedule_delayed_work(&chip->monitor_work, 0);
+}
+
+static void rt5025_program_alarm(int seconds)
+{
+ ktime_t low_interval = ktime_set(seconds, 0);
+ ktime_t slack = ktime_set(20, 0);
+ ktime_t next;
+
+ next = ktime_add(chip->last_poll, low_interval);
+ alarm_start_range(&chip->wakeup_alarm, next, ktime_add(next, slack));
+}
+
+static int rt5025_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = chip->status;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = chip->health;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = chip->online;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = chip->ext_temp;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = chip->vcell * 1000; //uV
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = chip->curr * 1000; //uA
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = chip->soc;
+ if (val->intval > 100)
+ val->intval = 100;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void rt5025_get_vcell(struct i2c_client *client)
+{
+ u8 data[2];
+
+ if (rt5025_read_reg(client, RT5025_REG_VCELL_MSB, data, 2) < 0){
+ printk(KERN_ERR "%s: Failed to read Voltage\n", __func__);
+ }
+
+ chip->vcell = ((data[0] << 8) + data[1]) * 61 / 100;
+ chip->curr_offset = (15444 * chip->vcell - 27444000) / 10000;
+
+ RTINFO("[RT5025] vcell: %d, offset: %d\n", chip->vcell, chip->curr_offset);
+}
+
+static void rt5025_get_current(struct i2c_client *client)
+{
+ u8 data[2];
+ u16 temp;
+ int sign = 0;
+
+ if (rt5025_read_reg(client, RT5025_REG_CURRENT_MSB, data, 2) < 0) {
+ printk(KERN_ERR "%s: Failed to read CURRENT\n", __func__);
+ }
+
+ temp = (data[0]<<8) | data[1];
+ if (data[0] & (1 << 7)) {
+ sign = 1;
+ temp = (((temp & 0x7FFF) * 3125) / 10 + chip->curr_offset) / 1000;
+ }else
+ temp = ((temp * 3125) / 10 - chip->curr_offset) / 1000;
+
+ if (sign)
+ temp *= -1;
+
+ chip->curr = temp;
+ RTINFO("[RT5025] current: %d\n", chip->curr);
+}
+
+static void rt5025_get_external_temp(struct i2c_client *client)
+{
+ u8 data[2];
+ long int temp;
+
+ if (rt5025_read_reg(client, RT5025_REG_EXT_TEMPERATUE_MSB, data, 2) < 0) {
+ printk(KERN_ERR "%s: Failed to read TEMPERATURE\n", __func__);
+ }
+ chip->ain_volt = (data[0] * 256 + data[1]) * 61 / 100;
+ /// Check battery present
+ if (chip->ain_volt < 1150)
+ chip->online = true;
+ else
+ chip->online = false;
+ temp = (chip->ain_volt * (-91738) + 81521000) / 100000;
+ chip->ext_temp = (int)temp;
+
+ if (chip->ext_temp >= HIGH_TEMP_THRES) {
+ if (chip->health != POWER_SUPPLY_HEALTH_OVERHEAT)
+ chip->temp_high_cnt++;
+ } else if (chip->ext_temp <= HIGH_TEMP_RECOVER && chip->ext_temp >= LOW_TEMP_RECOVER) {
+ if (chip->health == POWER_SUPPLY_HEALTH_OVERHEAT ||
+ chip->health == POWER_SUPPLY_HEALTH_COLD)
+ chip->temp_recover_cnt++;
+ } else if (chip->ext_temp <= LOW_TEMP_THRES) {
+ if (chip->health != POWER_SUPPLY_HEALTH_COLD)
+ chip->temp_low_cnt++;
+ } else {
+ chip->temp_high_cnt = 0;
+ chip->temp_low_cnt = 0;
+ chip->temp_recover_cnt = 0;
+ }
+
+ if (chip->temp_high_cnt >= TEMP_ABNORMAL_COUNT) {
+ chip->health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ chip->temp_high_cnt = 0;
+ } else if (chip->temp_low_cnt >= TEMP_ABNORMAL_COUNT) {
+ chip->health = POWER_SUPPLY_HEALTH_COLD;
+ chip->temp_low_cnt = 0;
+ } else if (chip->temp_recover_cnt >= TEMP_ABNORMAL_COUNT) {
+ chip->health = POWER_SUPPLY_HEALTH_GOOD;
+ chip->temp_recover_cnt = 0;
+ }
+ RTINFO("[RT5025] external temperature: %d\n", chip->ext_temp);
+}
+
+static void rt5025_clear_cc(operation_mode mode)
+{
+ u8 data[2];
+
+ if (rt5025_read_reg(chip->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){
+ printk(KERN_ERR "%s: failed to read channel\n", __func__);
+ }
+
+ if (mode == CHG)
+ data[0] = data[0] | CHANNEL_H_BIT_CLRQCHG;
+ else
+ data[0] = data[0] | CHANNEL_H_BIT_CLRQDCHG;
+
+ if (rt5025_write_reg(chip->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){
+ printk(KERN_ERR "%s: failed to write channel\n", __func__);
+ }
+}
+
+static void rt5025_get_chg_cc(struct i2c_client *client)
+{
+ u8 data[4];
+ u32 qh_old,ql_old,qh_new,ql_new;
+ u32 cc_masec,offset;
+
+ if (rt5025_read_reg(client, RT5025_REG_QCHGH_MSB, data, 4) < 0){
+ printk(KERN_ERR "%s: Failed to read QCHG\n", __func__);
+ }
+ qh_old = (data[0]<<8) + data[1];
+ ql_old = (data[2]<<8) + data[3];
+
+ if (rt5025_read_reg(client, RT5025_REG_QCHGH_MSB, data, 4) < 0){
+ printk(KERN_ERR "%s: Failed to read QCHG\n", __func__);
+ }
+ qh_new = (data[0]<<8) + data[1];
+ ql_new = (data[2]<<8) + data[3];
+
+ if (qh_new > qh_old){
+ cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+ }else if (qh_new == qh_old){
+ if (ql_new >= ql_old){
+ cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+ }else {
+ cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10;
+ }
+ }
+
+ offset = chip->curr_offset * chip->time_interval;
+
+ if (cc_masec != 0){
+ cc_masec = (cc_masec - offset) / 1000;
+ }
+
+ RTINFO("[RT5025] chg_cc_mAsec: %d\n", cc_masec);
+
+ chip->chg_cc = (cc_masec + chip->chg_cc_unuse) / 3600;
+ chip->chg_cc_unuse = (cc_masec + chip->chg_cc_unuse) % 3600;
+ RTINFO("[RT5025] chg_cc_mAH: %d\n", chip->chg_cc);
+ rt5025_clear_cc(CHG);
+}
+
+static void rt5025_get_dchg_cc(struct i2c_client *client)
+{
+ u8 data[4];
+ u32 qh_old,ql_old,qh_new,ql_new;
+ u32 cc_masec,offset;
+
+ if (rt5025_read_reg(client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){
+ printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__);
+ }
+ qh_old = (data[0]<<8) + data[1];
+ ql_old = (data[2]<<8) + data[3];
+
+ if (rt5025_read_reg(client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){
+ printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__);
+ }
+ qh_new = (data[0]<<8) + data[1];
+ ql_new = (data[2]<<8) + data[3];
+
+ if (qh_new > qh_old){
+ cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+ }else if (qh_new == qh_old){
+ if (ql_new >= ql_old){
+ cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;
+ }else {
+ cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10;
+ }
+ }
+
+ offset = chip->curr_offset * chip->time_interval;
+
+ if (cc_masec != 0){
+ cc_masec = (cc_masec - offset) / 1000;
+ }
+
+ RTINFO("[RT5025] dchg_cc_mAsec: %d\n", cc_masec);
+
+ chip->dchg_cc = (cc_masec + chip->dchg_cc_unuse) / 3600;
+ chip->dchg_cc_unuse = (cc_masec + chip->dchg_cc_unuse) % 3600;
+ RTINFO("[RT5025] dchg_cc_mAH: %d\n", chip->dchg_cc);
+ rt5025_clear_cc(DCHG);
+}
+
+static void rt5025_get_irq_flag(struct i2c_client *client)
+{
+ u8 data[1];
+
+ if (rt5025_read_reg(client, RT5025_REG_IRQ_FLAG, data, 1) < 0){
+ printk(KERN_ERR "%s: Failed to read irq_flag\n", __func__);
+ }
+
+ chip->irq_flag = data[0];
+ RTINFO("[RT5025] IRQ_FLG 0x%x\n", chip->irq_flag);
+}
+
+static void rt5025_get_timer(struct i2c_client *client)
+{
+ u8 data[2];
+ u16 gauge_timer;
+
+ if (rt5025_read_reg(client, RT5025_REG_TIMER, data, 2) < 0){
+ printk(KERN_ERR "%s: Failed to read Timer\n", __func__);
+ }
+
+ gauge_timer = (data[0] << 8) + data[1];
+ if (gauge_timer > chip->pre_gauge_timer)
+ chip->time_interval = gauge_timer - chip->pre_gauge_timer;
+ else
+ chip->time_interval = 65536 - chip->pre_gauge_timer + gauge_timer;
+
+ chip->pre_gauge_timer = gauge_timer;
+ RTINFO("[RT5025] timer %d , interval %d\n", gauge_timer,chip->time_interval);
+}
+
+static void rt5025_get_soc(struct i2c_client *client)
+{
+ chip->soc = 50;
+}
+
+static void rt5025_channel_cc(bool enable)
+{
+ u8 data[1];
+
+ if (rt5025_read_reg(chip->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+ printk(KERN_ERR "%s: failed to read channel\n", __func__);
+ }
+
+ if (enable){
+ data[0] = data[0] | 0x80;
+ }else {
+ data[0] = data[0] & 0x7F;
+ }
+
+ if (rt5025_write_reg(chip->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+ printk(KERN_ERR "%s: failed to write channel\n", __func__);
+ }
+}
+
+static void rt5025_register_init(struct i2c_client *client)
+{
+ u8 data[1];
+
+ /* enable the channel of current,qc,ain,vbat and vadc */
+ if (rt5025_read_reg(client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+ printk("%s: failed to read channel\n", __func__);
+ }
+ data[0] = data[0] |
+ CHANNEL_L_BIT_CADC_EN |
+ CHANNEL_L_BIT_AINCH |
+ CHANNEL_L_BIT_VBATSCH |
+ CHANNEL_L_BIT_VADC_EN;
+ if (rt5025_write_reg(client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){
+ printk("%s: failed to write channel\n", __func__);
+ }
+ /* set the alert threshold value */
+ irq_thres[MAXTEMP] = TALRTMAX_VALUE;
+ irq_thres[MINTEMP] = TALRTMIN_VALUE;
+ irq_thres[MAXVOLT] = VALRTMAX_VALUE;
+ irq_thres[MINVOLT1] = VALRTMIN1_VALUE;
+ irq_thres[MINVOLT2] = VALRTMIN2_VALUE;
+ irq_thres[TEMP_RLS] = TRLS_VALUE;
+ irq_thres[VOLT_RLS] = VRLS_VALUE;
+
+ chip->chg_cc_unuse = 0;
+ chip->dchg_cc_unuse = 0;
+ chip->pre_gauge_timer = 0;
+ chip->online = 1;
+ chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
+ chip->health = POWER_SUPPLY_HEALTH_GOOD;
+ RTINFO("[RT5025] register initialized\n");
+}
+
+static void rt5025_alert_setting(alert_type type, bool enable)
+{
+ u8 data[1];
+
+ if (rt5025_read_reg(chip->client, RT5025_REG_IRQ_CTL, data, 1) < 0){
+ printk(KERN_ERR "%s: Failed to read CONFIG\n", __func__);
+ }
+
+ if(enable){
+ switch(type){
+ case MAXTEMP:
+ data[0] |= IRQ_CTL_BIT_TMX; //Enable max temperature alert
+ chip->max_temp_irq = true;
+ RTINFO("Enable min temperature alert");
+ break;
+ case MINTEMP:
+ data[0] |= IRQ_CTL_BIT_TMN; //Enable min temperature alert
+ chip->min_temp_irq = true;
+ RTINFO("Enable max temperature alert");
+ break;
+ case MAXVOLT:
+ data[0] |= IRQ_CTL_BIT_VMX; //Enable max voltage alert
+ chip->max_volt_irq = true;
+ RTINFO("Enable max voltage alert");
+ break;
+ case MINVOLT1:
+ data[0] |= IRQ_CTL_BIT_VMN1; //Enable min1 voltage alert
+ chip->min_volt1_irq = true;
+ RTINFO("Enable min1 voltage alert");
+ break;
+ case MINVOLT2:
+ data[0] |= IRQ_CTL_BIT_VMN2; //Enable min2 voltage alert
+ chip->min_volt2_irq = true;
+ RTINFO("Enable min2 voltage alert");
+ break;
+ default:
+ break;
+ }
+ }else{
+ switch(type){
+ case MAXTEMP:
+ data[0] = data[0] &~ IRQ_CTL_BIT_TMX; //Disable max temperature alert
+ chip->max_temp_irq = false;
+ RTINFO("Disable min temperature alert");
+ break;
+ case MINTEMP:
+ data[0] = data[0] &~ IRQ_CTL_BIT_TMN; //Disable min temperature alert
+ chip->min_temp_irq = false;
+ RTINFO("Disable max temperature alert");
+ break;
+ case MAXVOLT:
+ data[0] = data[0] &~ IRQ_CTL_BIT_VMX; //Disable max voltage alert
+ chip->max_volt_irq = false;
+ RTINFO("Disable max voltage alert");
+ break;
+ case MINVOLT1:
+ data[0] = data[0] &~ IRQ_CTL_BIT_VMN1; //Disable min1 voltage alert
+ chip->min_volt1_irq = false;
+ RTINFO("Disable min1 voltage alert");
+ break;
+ case MINVOLT2:
+ data[0] = data[0] &~ IRQ_CTL_BIT_VMN2; //Disable min2 voltage alert
+ chip->min_volt2_irq = false;
+ RTINFO("Disable min2 voltage alert");
+ break;
+ default:
+ break;
+ }
+ }
+ if (rt5025_write_reg(chip->client, RT5025_REG_IRQ_CTL, data, 1) < 0)
+ printk(KERN_ERR "%s: failed to write IRQ control\n", __func__);
+}
+static void rt5025_alert_threshold_init(struct i2c_client *client)
+{
+ u8 data[1];
+
+ /* TALRT MAX threshold setting */
+ data[0] = irq_thres[MAXTEMP];
+ if (rt5025_write_reg(client, RT5025_REG_TALRT_MAXTH, data, 1) < 0)
+ printk(KERN_ERR "%s: failed to write TALRT MAX threshold\n", __func__);
+ /* TALRT MIN threshold setting */
+ data[0] = irq_thres[MINTEMP];
+ if (rt5025_write_reg(client, RT5025_REG_TALRT_MINTH, data, 1) < 0)
+ printk(KERN_ERR "%s: failed to write TALRT MIN threshold\n", __func__);
+ /* VALRT MAX threshold setting */
+ data[0] = irq_thres[MAXVOLT];
+ if (rt5025_write_reg(client, RT5025_REG_VALRT_MAXTH, data, 1) < 0)
+ printk(KERN_ERR "%s: failed to write VALRT MAX threshold\n", __func__);
+ /* VALRT MIN1 threshold setting */
+ data[0] = irq_thres[MINVOLT1];
+ if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN1TH, data, 1) < 0)
+ printk(KERN_ERR "%s: failed to write VALRT MIN1 threshold\n", __func__);
+ /* VALRT MIN2 threshold setting */
+ data[0] = irq_thres[MINVOLT2];
+ if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN2TH, data, 1) < 0)
+ printk(KERN_ERR "%s: failed to write VALRT MIN2 threshold\n", __func__);
+}
+
+static void rt5025_alert_init(struct i2c_client *client)
+{
+ /* Set RT5025 gauge alert configuration */
+ rt5025_alert_threshold_init(client);
+ /* Enable gauge alert function */
+ rt5025_alert_setting(MAXTEMP,true);
+ rt5025_alert_setting(MINTEMP,true);
+ rt5025_alert_setting(MAXVOLT,true);
+ rt5025_alert_setting(MINVOLT1,true);
+ rt5025_alert_setting(MINVOLT2,true);
+}
+
+void rt5025_irq_handler(void)
+{
+ rt5025_get_irq_flag(chip->client);
+
+ if ((chip->irq_flag) & IRQ_FLG_BIT_TMX){
+ printk(KERN_INFO "[RT5025]: Min temperature IRQ received\n");
+ rt5025_alert_setting(MAXTEMP,false);
+ chip->max_temp_irq = false;
+ }
+ if ((chip->irq_flag) & IRQ_FLG_BIT_TMN){
+ printk(KERN_INFO "[RT5025]: Max temperature IRQ received\n");
+ rt5025_alert_setting(MINTEMP,false);
+ chip->min_temp_irq = false;
+ }
+ if ((chip->irq_flag) & IRQ_FLG_BIT_VMX){
+ printk(KERN_INFO "[RT5025]: Max voltage IRQ received\n");
+ rt5025_alert_setting(MAXVOLT,false);
+ chip->max_volt_irq = false;
+ }
+ if ((chip->irq_flag) & IRQ_FLG_BIT_VMN1){
+ printk(KERN_INFO "[RT5025]: Min voltage1 IRQ received\n");
+ rt5025_alert_setting(MINVOLT1,false);
+ chip->min_volt1_irq = false;
+ }
+ if ((chip->irq_flag) & IRQ_FLG_BIT_VMN2){
+ printk(KERN_INFO "[RT5025]: Min voltage2 IRQ received\n");
+ rt5025_alert_setting(MINVOLT2,false);
+ chip->min_volt2_irq = false;
+ }
+
+ wake_lock(&chip->monitor_wake_lock);
+ schedule_delayed_work(&chip->monitor_work, 0);
+}
+
+static void rt5025_update(struct i2c_client *client)
+{
+ /* Update voltage */
+ rt5025_get_vcell(client);
+ /* Update current */
+ rt5025_get_current(client);
+ /* Update external temperature */
+ rt5025_get_external_temp(client);
+ /* Read timer */
+ rt5025_get_timer(client);
+ /* Update chg cc */
+ rt5025_get_chg_cc(client);
+ /* Update dchg cc */
+ rt5025_get_dchg_cc(client);
+ /* Update SOC */
+ rt5025_get_soc(client);
+
+ if ((chip->max_temp_irq == false) &&
+ (((irq_thres[MAXTEMP] * IRQ_THRES_UNIT) / 100 - chip->ain_volt) > irq_thres[TEMP_RLS])){
+ rt5025_alert_setting(MAXTEMP,true);
+ }else if ((chip->min_temp_irq == false) &&
+ ((chip->ain_volt - (irq_thres[MINTEMP] * IRQ_THRES_UNIT) / 100) > irq_thres[TEMP_RLS])){
+ rt5025_alert_setting(MINTEMP,true);
+ }else if ((chip->max_volt_irq == false) &&
+ ((((irq_thres[MAXVOLT] * IRQ_THRES_UNIT) / 100) - chip->vcell) > irq_thres[VOLT_RLS])){
+ rt5025_alert_setting(MAXVOLT,true);
+ }else if ((chip->min_volt1_irq == false) &&
+ ((chip->vcell - ((irq_thres[MINVOLT1] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){
+ rt5025_alert_setting(MINVOLT1,true);
+ }else if ((chip->min_volt2_irq == false) &&
+ ((chip->vcell - ((irq_thres[MINVOLT2] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){
+ rt5025_alert_setting(MINVOLT2,true);
+ }
+}
+
+static void rt5025_update_work(struct work_struct *work)
+{
+ unsigned long flags;
+
+ rt5025_update(chip->client);
+
+ /* Update data to framework */
+ power_supply_changed(&chip->battery);
+
+ /* prevent suspend before starting the alarm */
+ local_irq_save(flags);
+ chip->last_poll = alarm_get_elapsed_realtime();
+ rt5025_program_alarm(NORMAL_POLL);
+ local_irq_restore(flags);
+
+ wake_unlock(&chip->monitor_wake_lock);
+}
+
+static enum power_supply_property rt5025_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+};
+
+void rt5025_gauge_suspend(void)
+{
+ rt5025_channel_cc(false);
+ cancel_delayed_work(&chip->monitor_work);
+
+ RTINFO("\n");
+}
+
+void rt5025_gauge_resume(void)
+{
+ rt5025_channel_cc(true);
+ wake_lock(&chip->monitor_wake_lock);
+ schedule_delayed_work(&chip->monitor_work, 0);
+ RTINFO("\n");
+}
+
+void rt5025_gauge_remove(void)
+{
+ chip->info->event_callback = NULL;
+ power_supply_unregister(&chip->battery);
+ cancel_delayed_work(&chip->monitor_work);
+ wake_lock_destroy(&chip->monitor_wake_lock);
+ kfree(chip);
+}
+
+int rt5025_gauge_init(struct rt5025_power_info *info)
+{
+ int ret;
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = info->i2c;
+ chip->info = info;
+ chip->battery.name = "rt5025-battery";
+ chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->battery.get_property = rt5025_get_property;
+ chip->battery.properties = rt5025_battery_props;
+ chip->battery.num_properties = ARRAY_SIZE(rt5025_battery_props);
+
+ ret = power_supply_register(info->dev, &chip->battery);
+ if (ret) {
+ printk(KERN_ERR "[RT5025] power supply register failed\n");
+ goto err_wake_lock;
+ }
+
+ chip->last_poll = alarm_get_elapsed_realtime();
+ alarm_init(&chip->wakeup_alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ rt5025_gauge_alarm);
+
+ INIT_DELAYED_WORK(&chip->monitor_work, rt5025_update_work);
+
+ wake_lock_init(&chip->monitor_wake_lock, WAKE_LOCK_SUSPEND,
+ "rt-battery-monitor");
+ /* enable channel */
+ rt5025_register_init(info->i2c);
+
+ /* enable gauge IRQ */
+ rt5025_alert_init(info->i2c);
+
+ /* register callback functions */
+ chip->cb.rt5025_gauge_irq_handler = rt5025_irq_handler;
+ chip->cb.rt5025_gauge_set_status = rt5025_set_status;
+ chip->cb.rt5025_gauge_suspend = rt5025_gauge_suspend;
+ chip->cb.rt5025_gauge_resume = rt5025_gauge_resume;
+ chip->cb.rt5025_gauge_remove = rt5025_gauge_remove;
+ info->event_callback=&chip->cb;
+
+ //rt_register_gauge_callbacks(info->i2c, &chip->cb);
+
+ wake_lock(&chip->monitor_wake_lock);
+ schedule_delayed_work(&chip->monitor_work, msecs_to_jiffies(1000));
+
+ return 0;
+
+err_wake_lock:
+ wake_lock_destroy(&chip->monitor_wake_lock);
+ kfree(chip);
+
+ return ret;
+}
--- /dev/null
+/* drivers/power/rt5025-power.c
+ * I2C Driver for Richtek RT5025 PMIC
+ * Multi function device - multi functional baseband PMIC Power part
+ *
+ * Copyright (C) 2013
+ * Author: CY Huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/mfd/rt5025.h>
+#include <linux/power/rt5025-power.h>
+#include <linux/power/rt5025-gauge.h>
+#include <linux/delay.h>
+
+
+static enum power_supply_property rt5025_adap_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *rt5025_supply_list[] = {
+ "rt5025-battery",
+};
+
+static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
+{
+ int ret;
+ if (onoff)
+ ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
+ else
+ ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
+ return ret;
+}
+
+static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
+{
+ int ret;
+ if (onoff)
+ ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+ else
+ ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+ return ret;
+}
+
+static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_val)
+{
+ int ret = 0;
+ switch (new_val)
+ {
+ case 0x00:
+ rt5025_set_charging_current_switch(info->i2c, 1);
+ rt5025_set_charging_buck(info->i2c, 1);
+ info->chg_stat = 0x00;
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
+ break;
+ case 0x01:
+ //rt5025_set_charging_current_switch(info->i2c, 1);
+ info->chg_stat = 0x01;
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
+ break;
+ case 0x02:
+ rt5025_set_charging_current_switch(info->i2c, 0);
+ info->chg_stat = 0x02;
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL);
+ break;
+ case 0x03:
+ rt5025_set_charging_buck(info->i2c, 0);
+ rt5025_set_charging_current_switch(info->i2c, 0);
+ info->chg_stat = 0x03;
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
+{
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_irq_handler();
+ return 0;
+}
+EXPORT_SYMBOL(rt5025_power_passirq_to_gauge);
+
+int rt5025_power_charge_detect(struct rt5025_power_info *info)
+{
+ int ret = 0;
+ unsigned char chgstatval = 0;
+ unsigned old_usbval, old_acval, old_chgval, new_usbval, new_acval, new_chgval;
+
+ old_acval = info->ac_online;
+ old_usbval = info->usb_online;
+ old_chgval = info->chg_stat;
+
+ ret = rt5025_reg_read(info->i2c, RT5025_REG_CHGSTAT);
+ if (ret<0)
+ {
+ dev_err(info->dev, "read chg stat reg fail\n");
+ return ret;
+ }
+ chgstatval = ret;
+
+ new_acval = (chgstatval&RT5025_CHG_ACONLINE)>>RT5025_CHG_ACSHIFT;
+ if (old_acval != new_acval)
+ {
+ info->ac_online = new_acval;
+ power_supply_changed(&info->ac);
+ }
+ new_usbval = (chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT;
+ if (old_usbval != new_usbval)
+ {
+ info->usb_online = new_usbval;
+ power_supply_changed(&info->usb);
+ }
+
+ new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT;
+ if (new_acval || new_usbval)
+ {
+ if (old_chgval != new_chgval)
+ {
+ ret = rt5025_chgstat_changed(info, new_chgval);
+ }
+ }
+ else
+ {
+ rt5025_set_charging_buck(info->i2c, 0);
+ rt5025_set_charging_current_switch(info->i2c, 0);
+ info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(rt5025_power_charge_detect);
+
+static int rt5025_adap_get_props(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct rt5025_power_info *info = dev_get_drvdata(psy->dev->parent);
+ switch(psp)
+ {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+ val->intval = info->ac_online;
+ else if (psy->type == POWER_SUPPLY_TYPE_USB)
+ val->intval = info->usb_online;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd)
+{
+ info->ac_online = 0;
+ info->usb_online =0;
+ //init charger buckck & charger current en to disable stat
+ info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
+ if (info->event_callback)
+ info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
+ rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK);
+ udelay(200);
+ //init register setting
+ rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL2, pd->CHGControl2.val);
+ rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL3, pd->CHGControl3.val);
+ rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL4, pd->CHGControl4.val);
+ rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL5, pd->CHGControl5.val);
+ rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL6, pd->CHGControl6.val);
+ rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
+
+ rt5025_power_charge_detect(info);
+
+ return 0;
+}
+
+static int __devinit rt5025_power_probe(struct platform_device *pdev)
+{
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5025_platform_data *pdata = chip->dev->platform_data;
+ struct rt5025_power_info *pi;
+ int ret = 0;
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+ pi = kzalloc(sizeof(*pi), GFP_KERNEL);
+ if (!pi)
+ return -ENOMEM;
+
+ pi->i2c = chip->i2c;
+ pi->dev = &pdev->dev;
+
+ ret = rt5025_gauge_init(pi);
+ if (ret)
+ goto out;
+
+ platform_set_drvdata(pdev, pi);
+
+ pi->ac.name = "rt5025-ac";
+ pi->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ pi->ac.supplied_to = rt5025_supply_list;
+ pi->ac.properties = rt5025_adap_props;
+ pi->ac.num_properties = ARRAY_SIZE(rt5025_adap_props);
+ pi->ac.get_property = rt5025_adap_get_props;
+ ret = power_supply_register(&pdev->dev, &pi->ac);
+ if (ret)
+ goto out;
+
+ pi->usb.name = "rt5025-usb";
+ pi->usb.type = POWER_SUPPLY_TYPE_USB;
+ pi->ac.supplied_to = rt5025_supply_list;
+ pi->usb.properties = rt5025_adap_props;
+ pi->usb.num_properties = ARRAY_SIZE(rt5025_adap_props);
+ pi->usb.get_property = rt5025_adap_get_props;
+ ret = power_supply_register(&pdev->dev, &pi->usb);
+ if (ret)
+ goto out_usb;
+
+ rt5025_init_charger(pi, pdata->power_data);
+ chip->power_info = pi;
+
+ return ret;
+out_usb:
+ power_supply_unregister(&pi->ac);
+out:
+ kfree(pi);
+
+ return ret;
+}
+
+static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+
+ if (pi->event_callback)
+ pi->event_callback->rt5025_gauge_suspend();
+ return 0;
+}
+
+static int rt5025_power_resume(struct platform_device *pdev)
+{
+ struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+ if (pi->event_callback)
+ pi->event_callback->rt5025_gauge_resume();
+ return 0;
+}
+
+static int __devexit rt5025_power_remove(struct platform_device *pdev)
+{
+ struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (pi->event_callback)
+ pi->event_callback->rt5025_gauge_remove();
+ power_supply_unregister(&pi->usb);
+ power_supply_unregister(&pi->ac);
+ chip->power_info = NULL;
+ kfree(pi);
+
+ return 0;
+}
+
+static struct platform_driver rt5025_power_driver =
+{
+ .driver = {
+ .name = RT5025_DEVICE_NAME "-power",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_power_probe,
+ .remove = __devexit_p(rt5025_power_remove),
+ .suspend = rt5025_power_suspend,
+ .resume = rt5025_power_resume,
+};
+
+static int __init rt5025_power_init(void)
+{
+ return platform_driver_register(&rt5025_power_driver);
+}
+subsys_initcall_sync(rt5025_power_init);
+
+static void __exit rt5025_power_exit(void)
+{
+ platform_driver_unregister(&rt5025_power_driver);
+}
+module_exit(rt5025_power_exit);
+
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Power/Gauge driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-power");
+config REGULATOR_RT5025
+ bool "Richtek RT5025 PMIC Voltage regulstors"
+ depends on MFD_RT5025
+ help
+ This driver supports voltage regulator in RT5025 PMIC chips.
endif
obj-$(CONFIG_REGULATOR_ACT8931) += act8931.o
obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
obj-$(CONFIG_REGULATOR_RICOH619) += ricoh619-regulator.o
+obj-$(CONFIG_REGULATOR_RT5025) += rt5025-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
--- /dev/null
+/*
+ * drivers/regulator/rt5025-regulator.c
+ * Driver foo Richtek RT5025 PMIC Regulator
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/version.h>
+#include <linux/mfd/rt5025.h>
+#include <linux/regulator/rt5025-regulator.h>
+
+struct rt5025_regulator_info {
+ struct regulator_desc desc;
+ struct regulator_dev *regulator;
+ struct i2c_client *i2c;
+ struct rt5025_chip *chip;
+ const unsigned int *vol_output_list;
+ const int vol_output_size;
+ int min_uV;
+ int max_uV;
+ int vol_reg;
+ int vol_shift;
+ int vol_mask;
+ int enable_bit;
+ int enable_reg;
+};
+
+//for DCDC1
+static const unsigned int rt5025_vol_output_list1[] =
+{
+ 700*1000, 725*1000, 750*1000, 775*1000, 800*1000, 825*1000, 850*1000, 875*1000,
+ 900*1000, 925*1000, 950*1000, 975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000,
+ 1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000,
+ 1300*1000, 1325*1000, 1350*1000, 1375*1000, 1400*1000, 1425*1000, 1450*1000, 1475*1000,
+ 1500*1000, 1525*1000, 1550*1000, 1575*1000, 1600*1000, 1625*1000, 1650*1000, 1675*1000,
+ 1700*1000, 1725*1000, 1750*1000, 1775*1000, 1800*1000, 1825*1000, 1850*1000, 1875*1000,
+ 1900*1000, 1925*1000, 1950*1000, 1975*1000, 2000*2000, 2025*1000, 2050*1000, 2075*1000,
+ 2100*1000, 2125*1000, 2150*1000, 2175*1000, 2200*1000, 2225*1000, 2250*1000, 2275*1000,
+};
+#define rt5025_vol_output_size1 ARRAY_SIZE(rt5025_vol_output_list1)
+
+//DCDC2, LDO1, LDO2
+static const unsigned int rt5025_vol_output_list2[] =
+{
+ 700*1000, 725*1000, 750*1000, 775*1000, 800*1000, 825*1000, 850*1000, 875*1000,
+ 900*1000, 925*1000, 950*1000, 975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000,
+ 1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000,
+ 1300*1000, 1325*1000, 1350*1000, 1375*1000, 1400*1000, 1425*1000, 1450*1000, 1475*1000,
+ 1500*1000, 1525*1000, 1550*1000, 1575*1000, 1600*1000, 1625*1000, 1650*1000, 1675*1000,
+ 1700*1000, 1725*1000, 1750*1000, 1775*1000, 1800*1000, 1825*1000, 1850*1000, 1875*1000,
+ 1900*1000, 1925*1000, 1950*1000, 1975*1000, 2000*2000, 2025*1000, 2050*1000, 2075*1000,
+ 2100*1000, 2125*1000, 2150*1000, 2175*1000, 2200*1000, 2225*1000, 2250*1000, 2275*1000,
+ 2300*1000, 2325*1000, 2350*1000, 2375*1000, 2400*1000, 2425*1000, 2450*1000, 2475*1000,
+ 2500*1000, 2525*1000, 2550*1000, 2575*1000, 2600*1000, 2625*1000, 2650*1000, 2675*1000,
+ 2700*1000, 2725*1000, 2750*1000, 2775*1000, 2800*1000, 2825*1000, 2850*1000, 2875*1000,
+ 2900*1000, 2925*1000, 2950*1000, 2975*1000, 3000*1000, 3025*1000, 3050*1000, 3075*1000,
+ 3100*1000, 3125*1000, 3150*1000, 3175*1000, 3200*1000, 3225*1000, 3250*1000, 3275*1000,
+ 3300*1000, 3325*1000, 3350*1000, 3375*1000, 3400*1000, 3425*1000, 3450*1000, 3475*1000,
+ 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000,
+ 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000,
+};
+#define rt5025_vol_output_size2 ARRAY_SIZE(rt5025_vol_output_list2)
+
+//DCDC3
+static const unsigned int rt5025_vol_output_list3[] =
+{
+ 700*1000, 750*1000, 800*1000, 850*1000, 900*1000, 950*1000, 1000*1000, 1050*1000,
+ 1100*1000, 1150*1000, 1200*1000, 1250*1000, 1300*1000, 1350*1000, 1400*1000, 1450*1000,
+ 1500*1000, 1550*1000, 1600*1000, 1650*1000, 1700*1000, 1750*1000, 1800*1000, 1850*1000,
+ 1900*1000, 1950*1000, 2000*1000, 2050*1000, 2100*1000, 2150*1000, 2200*1000, 2250*1000,
+ 2300*1000, 2350*1000, 2400*1000, 2450*1000, 2500*1000, 2550*1000, 2600*1000, 2650*1000,
+ 2700*1000, 2750*1000, 2800*1000, 2850*1000, 2900*1000, 2950*1000, 3000*1000, 3050*1000,
+ 3100*1000, 3150*1000, 3200*1000, 3250*1000, 3300*1000, 3350*1000, 3400*1000, 3450*1000,
+ 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000, 3500*1000,
+};
+#define rt5025_vol_output_size3 ARRAY_SIZE(rt5025_vol_output_list3)
+
+//DCDC4
+static const unsigned int rt5025_vol_output_list4[] =
+{
+ 4500*1000, 4600*1000, 4700*1000, 4800*1000, 4900*1000, 5000*1000, 5100*1000, 5200*1000,
+ 5300*1000, 5400*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000,
+};
+#define rt5025_vol_output_size4 ARRAY_SIZE(rt5025_vol_output_list4)
+
+//LDO3, LDO4, LDO5, LDO6
+static const unsigned int rt5025_vol_output_list5[] =
+{
+ 1000*1000, 1100*1000, 1200*1000, 1300*1000, 1400*1000, 1500*1000, 1600*1000, 1700*1000,
+ 1800*1000, 1900*1000, 2000*1000, 2100*1000, 2200*1000, 2300*1000, 2400*1000, 2500*1000,
+ 2600*1000, 2700*1000, 2800*1000, 2900*1000, 3000*1000, 3100*1000, 3200*1000, 3300*1000,
+ 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000,
+ 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000, 3300*1000,
+};
+#define rt5025_vol_output_size5 ARRAY_SIZE(rt5025_vol_output_list5)
+
+static inline int check_range(struct rt5025_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (min_uV < info->min_uV || min_uV > info->max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int rt5025_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return (index>=info->vol_output_size)? \
+ -EINVAL: \
+ info->vol_output_list[index ];
+}
+
+//#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38))
+static int rt5025_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data;
+ const int count = info->vol_output_size;
+
+ if (selector>count)
+ return -EINVAL;
+ data = (unsigned char)selector;
+ data <<= info->vol_shift;
+ return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data);
+}
+
+static int rt5025_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+ ret = rt5025_reg_read(info->i2c, info->vol_reg);
+ if (ret < 0)
+ return ret;
+ return (ret & info->vol_mask) >> info->vol_shift;
+}
+//#else
+static int rt5025_find_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ int i=0;
+ const int count = info->vol_output_size;
+ for (i=0;i<count;i++)
+ {
+ if ((info->vol_output_list[i]>=min_uV)
+ && (info->vol_output_list[i]<=max_uV))
+ return i;
+ }
+ return -EINVAL;
+}
+
+static int rt5025_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned char data;
+ if (check_range(info, min_uV, max_uV)) {
+ dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ data = rt5025_find_voltage(rdev,min_uV,max_uV);
+ data <<= info->vol_shift;
+ return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data);
+}
+
+
+static int rt5025_get_voltage(struct regulator_dev *rdev)
+{
+ int ret;
+ ret = rt5025_get_voltage_sel(rdev);
+ if (ret < 0)
+ return ret;
+ return rt5025_list_voltage(rdev, ret );
+
+}
+//#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */
+
+static int rt5025_enable(struct regulator_dev *rdev)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return rt5025_set_bits(info->i2c, info->enable_reg,
+ info->enable_bit);
+}
+
+static int rt5025_disable(struct regulator_dev *rdev)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return rt5025_clr_bits(info->i2c, info->enable_reg,
+ info->enable_bit);
+}
+
+static int rt5025_is_enabled(struct regulator_dev *rdev)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = rt5025_reg_read(info->i2c, info->enable_reg);
+ if (ret < 0)
+ return ret;
+
+ return (ret & (info->enable_bit))?1:0;
+}
+static int rt5025_dcdc_get_mode(struct regulator_dev *rdev)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ int buck = rdev_get_id(rdev) - 0;
+ int ret;
+ uint8_t control;
+
+ ret = rt5025_reg_read(info->i2c, 0x0c);
+ if (ret < 0) {
+ return ret;
+ }
+ if (buck ==0){
+ control =(ret & 0x80)>>7;
+ }
+ else if (buck ==1){
+ control =(ret & 0x40)>>6;
+ }
+ else if (buck ==2){
+ control =(ret & 0x20)>>5;
+ }
+ else{
+ return -1;
+ }
+ switch (control) {
+ case 0:
+ return REGULATOR_MODE_FAST;
+ case 1:
+ return REGULATOR_MODE_NORMAL;
+ default:
+ return -1;
+ }
+
+}
+static int rt5025_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
+ int buck = rdev_get_id(rdev) - 0;
+ int ret;
+ uint8_t control;
+
+ ret = rt5025_reg_read(info->i2c, 0x0c);
+ if (buck ==0){
+ control =ret &(~ (1 <<7));
+ }
+ else if (buck ==1){
+ control =ret &(~ (1 <<6));
+ }
+ else if (buck ==2){
+ control =ret &(~ (1 <<5));
+ }
+ else{
+ return -1;
+ }
+
+ switch(mode)
+ {
+ case REGULATOR_MODE_FAST:
+ return rt5025_reg_write(info->i2c, 0x0c,control);
+ case REGULATOR_MODE_NORMAL:
+ return rt5025_reg_write(info->i2c, 0x0c,(control | (1 <<(7-buck))));
+ default:
+ printk("error:pmu_rt5025 only powersave pwm & auto mode\n");
+ return -EINVAL;
+ }
+}
+static int rt5025_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector,
+ unsigned int new_selector)
+{
+ int old_volt, new_volt;
+
+ old_volt = rt5025_list_voltage(rdev, old_selector);
+ if (old_volt < 0)
+ return old_volt;
+
+ new_volt = rt5025_list_voltage(rdev, new_selector);
+ if (new_volt < 0)
+ return new_volt;
+
+ return DIV_ROUND_UP(abs(old_volt - new_volt), 25000);
+}
+
+static struct regulator_ops rt5025_regulator_ops = {
+ .list_voltage = rt5025_list_voltage,
+//#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38))
+// .get_voltage_sel = rt5025_get_voltage_sel,
+// .set_voltage_sel = rt5025_set_voltage_sel,
+//#else
+ .set_voltage = rt5025_set_voltage,
+ .get_voltage = rt5025_get_voltage,
+//#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */
+ .enable = rt5025_enable,
+ .disable = rt5025_disable,
+ .is_enabled = rt5025_is_enabled,
+ .get_mode = rt5025_dcdc_get_mode,
+ .set_mode = rt5025_dcdc_set_mode,
+ .set_voltage_time_sel = rt5025_dcdc_set_voltage_time_sel,
+};
+
+#define RT5025_DCDCVOUT_LIST1 rt5025_vol_output_list1
+#define RT5025_DCDCVOUT_LIST2 rt5025_vol_output_list2
+#define RT5025_DCDCVOUT_LIST3 rt5025_vol_output_list3
+#define RT5025_DCDCVOUT_LIST4 rt5025_vol_output_list4
+#define RT5025_LDOVOUT_LIST1 rt5025_vol_output_list2
+#define RT5025_LDOVOUT_LIST2 rt5025_vol_output_list2
+#define RT5025_LDOVOUT_LIST3 rt5025_vol_output_list5
+#define RT5025_LDOVOUT_LIST4 rt5025_vol_output_list5
+#define RT5025_LDOVOUT_LIST5 rt5025_vol_output_list5
+#define RT5025_LDOVOUT_LIST6 rt5025_vol_output_list5
+
+#define RT5025_DCDCVOUT_SIZE1 rt5025_vol_output_size1
+#define RT5025_DCDCVOUT_SIZE2 rt5025_vol_output_size2
+#define RT5025_DCDCVOUT_SIZE3 rt5025_vol_output_size3
+#define RT5025_DCDCVOUT_SIZE4 rt5025_vol_output_size4
+#define RT5025_LDOVOUT_SIZE1 rt5025_vol_output_size2
+#define RT5025_LDOVOUT_SIZE2 rt5025_vol_output_size2
+#define RT5025_LDOVOUT_SIZE3 rt5025_vol_output_size5
+#define RT5025_LDOVOUT_SIZE4 rt5025_vol_output_size5
+#define RT5025_LDOVOUT_SIZE5 rt5025_vol_output_size5
+#define RT5025_LDOVOUT_SIZE6 rt5025_vol_output_size5
+
+
+#define RT5025_DCDC(_id, min, max) \
+{ \
+ .desc = { \
+ .name = "rt5025-dcdc" #_id, \
+ .n_voltages = RT5025_DCDCVOUT_SIZE##_id, \
+ .ops = &rt5025_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = RT5025_ID_DCDC##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .vol_output_list= RT5025_DCDCVOUT_LIST##_id, \
+ .vol_output_size= RT5025_DCDCVOUT_SIZE##_id, \
+ .min_uV = min , \
+ .max_uV = max , \
+ .vol_reg = RT5025_DCDCVOUT##_id, \
+ .vol_shift = RT5025_DCDCVOUT_SHIFT##_id, \
+ .vol_mask = RT5025_DCDCVOUT_MASK##_id, \
+ .enable_reg = RT5025_DCDC_OUTPUT_EN, \
+ .enable_bit = RT5025_DCDCEN_MASK##_id, \
+}
+
+#define RT5025_LDO(_id, min, max) \
+{ \
+ .desc = { \
+ .name = "rt5025-ldo" #_id, \
+ .n_voltages = RT5025_LDOVOUT_SIZE##_id, \
+ .ops = &rt5025_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = RT5025_ID_LDO##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .vol_output_list= RT5025_LDOVOUT_LIST##_id, \
+ .vol_output_size= RT5025_LDOVOUT_SIZE##_id, \
+ .min_uV = min , \
+ .max_uV = max, \
+ .vol_reg = RT5025_LDOVOUT##_id, \
+ .vol_shift = RT5025_LDOVOUT_SHIFT##_id, \
+ .vol_mask = RT5025_LDOVOUT_MASK##_id, \
+ .enable_reg = RT5025_LDO_OUTPUT_EN, \
+ .enable_bit = RT5025_LDOEN_MASK##_id, \
+}
+
+static struct rt5025_regulator_info rt5025_regulator_info[] =
+{
+ RT5025_DCDC(1, 700000, 2275000),
+ RT5025_DCDC(2, 700000, 3500000),
+ RT5025_DCDC(3, 700000, 3500000),
+ RT5025_DCDC(4, 4500000, 5500000),
+ RT5025_LDO( 1, 700000, 3500000),
+ RT5025_LDO( 2, 700000, 3500000),
+ RT5025_LDO( 3, 1000000, 3300000),
+ RT5025_LDO( 4, 1000000, 3300000),
+ RT5025_LDO( 5, 1000000, 3300000),
+ RT5025_LDO( 6, 1000000, 3300000),
+};
+
+static struct rt5025_regulator_info * __devinit find_regulator_info(int id)
+{
+ struct rt5025_regulator_info *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5025_regulator_info); i++) {
+ ri = &rt5025_regulator_info[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+inline struct regulator_dev* rt5025_regulator_register(struct regulator_desc *regulator_desc,
+ struct device *dev, struct regulator_init_data *init_data,
+ void *driver_data)
+{
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0))
+ struct regulator_config config = {
+ .dev = dev,
+ .init_data = init_data,
+ .driver_data = driver_data,
+ };
+ return regulator_register(®ulator_desc, &config);
+#else
+ return regulator_register(regulator_desc,dev,init_data,driver_data);
+#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) */
+}
+
+static int __devinit rt5025_regulator_probe(struct platform_device *pdev)
+{
+ struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5025_platform_data *pdata = chip->dev->platform_data;
+ struct rt5025_regulator_info *ri;
+ struct regulator_dev *rdev;
+ struct regulator_init_data* init_data;
+
+ ri = find_regulator_info(pdev->id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+ init_data = pdata->regulator[pdev->id];
+ if (init_data == NULL) {
+ dev_err(&pdev->dev, "no initializing data\n");
+ return -EINVAL;
+ }
+ ri->i2c = chip->i2c;
+ ri->chip = chip;
+
+ rdev = rt5025_regulator_register(&ri->desc, &pdev->dev,
+ init_data, ri);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+
+ return 0;
+}
+
+static int __devexit rt5025_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+static struct platform_driver rt5025_regulator_driver =
+{
+ .driver = {
+ .name = RT5025_DEVICE_NAME "-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5025_regulator_probe,
+ .remove = __devexit_p(rt5025_regulator_remove),
+};
+
+static int __init rt5025_regulator_init(void)
+{
+ return platform_driver_register(&rt5025_regulator_driver);
+}
+subsys_initcall_sync(rt5025_regulator_init);
+
+static void __exit rt5025_regulator_exit(void)
+{
+ platform_driver_unregister(&rt5025_regulator_driver);
+}
+module_exit(rt5025_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Regulator driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-regulator");
--- /dev/null
+/*
+ * include/linux/mfd/rt5025-gpio.h
+ * Include header file for Richtek RT5025 PMIC GPIO file
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_GPIO_H
+#define __LINUX_RT5025_GPIO_H
+
+#define RT5025_REG_GPIO0 0x1C
+#define RT5025_REG_GPIO1 0x1D
+#define RT5025_REG_GPIO2 0x1E
+
+#define RT5025_GPIO_NR 3
+
+#define RT5025_GPIO_INPUT 0x00
+#define RT5025_GPIO_OUTPUT 0x02
+
+#define RT5025_GPIO_DIRSHIFT 6
+#define RT5025_GPIO_DIRMASK 0xC0
+#define RT5025_GPIO_OVALUESHIFT 4
+#define RT5025_GPIO_OVALUEMASK 0x10
+#define RT5025_GPIO_IVALUEMASK 0x08
+
+#endif /* #ifndef __LINUX_RT5025_GPIO_H */
--- /dev/null
+/*
+ * include/linux/mfd/rt5025-irq.h
+ * Include header file for Richtek RT5025 PMIC IRQ file
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_IRQ_H
+#define __LINUX_RT5025_IRQ_H
+
+#define RT5025_REG_CHGSTAT 0x01
+
+#define RT5025_REG_IRQEN1 0x30
+#define RT5025_REG_IRQEN2 0x32
+#define RT5025_REG_IRQEN3 0x34
+#define RT5025_REG_IRQEN4 0x36
+#define RT5025_REG_IRQEN5 0x38
+
+#endif /* #ifndef __LINUX_RT5025_IRQ_H */
--- /dev/null
+/*
+ * include/linux/mfd/rt5025-misc.h
+ * Include header file for Richtek RT5025 PMIC Misc
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_MISC_H
+#define __LINUX_RT5025_MISC_H
+
+#define RT5025_RESETCTRL_REG 0x15
+#define RT5025_VSYSULVO_REG 0x17
+#define RT5025_PWRONCTRL_REG 0x19
+#define RT5025_SHDNCTRL_REG 0x1A
+#define RT5025_PWROFFEN_REG 0x1B
+
+#define RT5025_SHDNCTRL_MASK 0x80
+#define RT5025_VSYSOFF_MASK 0xE0
+
+#endif /* #ifndef __LINUX_RT5025_MISC_H */
--- /dev/null
+/*
+ * include/linux/mfd/rt5025.h
+ * Include header file for Richtek RT5025 Core file
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_RT5025_H
+#define __LINUX_MFD_RT5025_H
+
+#include <linux/power_supply.h>
+
+#define RT5025_DEVICE_NAME "RT5025"
+
+enum {
+ RT5025_RSTDELAY1_100MS,
+ RT5025_RSTDELAY1_500MS,
+ RT5025_RSTDELAY1_1S,
+ RT5025_RSTDELAY1_2S,
+};
+
+enum {
+ RT5025_RSTDELAY2_100MS,
+ RT5025_RSTDELAY2_500MS,
+ RT5025_RSTDELAY2_1S,
+ RT5025_RSTDELAY2_2S,
+};
+
+enum {
+ RT5025_VOFF_2P8V,
+ RT5025_VOFF_2P9V,
+ RT5025_VOFF_3P0V,
+ RT5025_VOFF_3P1V,
+ RT5025_VOFF_3P2V,
+ RT5025_VOFF_3P3V,
+ RT5025_VOFF_3P4V,
+ RT5025_VOFF_3P5V,
+};
+
+enum {
+ RT5025_STARTIME_100MS,
+ RT5025_STARTIME_1S,
+ RT5025_STARTIME_2S,
+ RT5025_STARTIME_3S,
+};
+
+enum {
+ RT5025_LPRESS_1S,
+ RT5025_LPRESS_1P5S,
+ RT5025_LPRESS_2S,
+ RT5025_LPRESS_2P5S,
+};
+
+enum {
+ RT5025_SHDNPRESS_4S,
+ RT5025_SHDNPRESS_6S,
+ RT5025_SHDNPRESS_8S,
+ RT5025_SHDNPRESS_10S,
+};
+
+enum {
+ RT5025_PGDLY_10MS,
+ RT5025_PGDLY_50MS,
+ RT5025_PGDLY_100MS,
+ RT5025_PGDLY_200MS,
+};
+
+enum {
+ RT5025_SHDNDLY_100MS,
+ RT5025_SHDNDLY_500MS,
+ RT5025_SHDNDLY_1S,
+ RT5025_SHDNDLY_2S,
+};
+
+enum {
+ RT5025_CCCHG_TO_4H,
+ RT5025_CCCHG_TO_6H,
+ RT5025_CCCHG_TO_8H,
+ RT5025_CCCHG_TO_10H,
+};
+
+enum {
+ RT5025_PRECHG_TO_30M,
+ RT5025_PRECHG_TO_40M,
+ RT5025_PRECHG_TO_50M,
+ RT5025_PRECHG_TO_60M,
+};
+
+enum {
+ RT5025_ICC_0P5A,
+ RT5025_ICC_0P6A,
+ RT5025_ICC_0P7A,
+ RT5025_ICC_0P8A,
+ RT5025_ICC_0P9A,
+ RT5025_ICC_1A,
+ RT5025_ICC_1P1A,
+ RT5025_ICC_1P2A,
+ RT5025_ICC_1P3A,
+ RT5025_ICC_1P4A,
+ RT5025_ICC_1P5A,
+ RT5025_ICC_1P6A,
+ RT5025_ICC_1P7A,
+ RT5025_ICC_1P8A,
+ RT5025_ICC_1P9A,
+ RT5025_ICC_2A,
+ RT5025_ICC_MAX,
+};
+
+enum {
+ RT5025_AICR_100MA,
+ RT5025_AICR_500MA,
+ RT5025_AICR_1A,
+ RT5025_AICR_NOLIMIT,
+};
+
+enum {
+ RT5025_DPM_4V,
+ RT5025_DPM_4P25V,
+ RT5025_DPM_4P5V,
+ RT5025_DPM_DIS,
+};
+
+enum {
+ RT5025_VPREC_2V,
+ RT5025_VPREC_2P2V,
+ RT5025_VPREC_2P4V,
+ RT5025_VPREC_2P6V,
+ RT5025_VPREC_2P8V,
+ RT5025_VPREC_3V,
+ RT5025_VPREC_3V_1,
+ RT5025_VPREC_3V_2,
+};
+
+enum {
+ RT5025_IEOC_10P,
+ RT5025_IEOC_20P,
+};
+
+enum {
+ RT5025_IPREC_10P,
+ RT5025_IPREC_20P,
+};
+
+enum {
+ RT5025_ID_DCDC1,
+ RT5025_ID_DCDC2,
+ RT5025_ID_DCDC3,
+ RT5025_ID_DCDC4,
+ RT5025_ID_LDO1,
+ RT5025_ID_LDO2,
+ RT5025_ID_LDO3,
+ RT5025_ID_LDO4,
+ RT5025_ID_LDO5,
+ RT5025_ID_LDO6,
+ RT5025_MAX_REGULATOR,
+};
+
+struct rt5025_power_data {
+ union {
+ struct {
+ unsigned char Resv1:1;
+ unsigned char CHGBC_EN:1;
+ unsigned char TE:1;
+ unsigned char Resv2:1;
+ unsigned char CCCHG_TIMEOUT:2;
+ unsigned char PRECHG_TIMEOUT:2;
+ }bitfield;
+ unsigned char val;
+ }CHGControl2;
+ union {
+ struct {
+ unsigned char Resv:2;
+ unsigned char VOREG:6;
+ }bitfield;
+ unsigned char val;
+ }CHGControl3;
+ union {
+ struct {
+ unsigned char Resv:1;
+ unsigned char AICR:2;
+ unsigned char ICC:4;
+ unsigned char CHG_RST:1;
+ }bitfield;
+ unsigned char val;
+ }CHGControl4;
+ union {
+ struct {
+ unsigned char Resv1:4;
+ unsigned char DPM:2;
+ unsigned char Resv2:2;
+ }bitfield;
+ unsigned char val;
+ }CHGControl5;
+ union {
+ struct {
+ unsigned char IPREC:1;
+ unsigned char IEOC:1;
+ unsigned char VPREC:3;
+ unsigned char Resv:3;
+ }bitfield;
+ unsigned char val;
+ }CHGControl6;
+ union {
+ struct {
+ unsigned char Resv1:4;
+ unsigned char CHGC_EN:1;
+ unsigned char CHG_DCDC_MODE:1;
+ unsigned char BATD_EN:1;
+ unsigned char Resv2:1;
+ }bitfield;
+ unsigned char val;
+ }CHGControl7;
+};
+
+struct rt5025_gpio_data {
+ unsigned gpio_base;
+ unsigned irq_base;
+};
+
+struct rt5025_misc_data {
+ union {
+ struct {
+ unsigned char Action:2;
+ unsigned char Delayed1:2;
+ unsigned char Delayed2:2;
+ unsigned char Resv:2;
+ }bitfield;
+ unsigned char val;
+ }RSTCtrl;
+ union {
+ struct {
+ unsigned char Resv:5;
+ unsigned char VOFF:3;
+ }bitfield;
+ unsigned char val;
+ }VSYSCtrl;
+ union {
+ struct {
+ unsigned char PG_DLY:2;
+ unsigned char SHDN_PRESS:2;
+ unsigned char LPRESS_TIME:2;
+ unsigned char START_TIME:2;
+ }bitfield;
+ unsigned char val;
+ }PwrOnCfg;
+ union {
+ struct {
+ unsigned char Resv:4;
+ unsigned char SHDN_DLYTIME:2;
+ unsigned char SHDN_TIMING:1;
+ unsigned char SHDN_CTRL:1;
+ }bitfield;
+ unsigned char val;
+ }SHDNCtrl;
+ union {
+ struct {
+ unsigned char Resv:2;
+ unsigned char OT_ENSHDN:1;
+ unsigned char PWRON_ENSHDN:1;
+ unsigned char DCDC3LV_ENSHDN:1;
+ unsigned char DCDC2LV_ENSHDN:1;
+ unsigned char DCDC1LV_ENSHDN:1;
+ unsigned char SYSLV_ENSHDN:1;
+ }bitfield;
+ unsigned char val;
+ }PwrOffCond;
+};
+
+struct rt5025_irq_data {
+ union {
+ struct {
+ unsigned char BATABS:1;
+ unsigned char Resv1:2;
+ unsigned char INUSB_PLUGIN:1;
+ unsigned char INUSBOVP:1;
+ unsigned char Resv2:1;
+ unsigned char INAC_PLUGIN:1;
+ unsigned char INACOVP:1;
+ }bitfield;
+ unsigned char val;
+ }irq_enable1;
+ union {
+ struct {
+ unsigned char CHTERMI:1;
+ unsigned char CHBATOVI:1;
+ unsigned char CHGOODI_INUSB:1;
+ unsigned char CHBADI_INUSB:1;
+ unsigned char CHSLPI_INUSB:1;
+ unsigned char CHGOODI_INAC:1;
+ unsigned char CHBADI_INAC:1;
+ unsigned char CHSLPI_INAC:1;
+ }bitfield;
+ unsigned char val;
+ }irq_enable2;
+ union {
+ struct {
+ unsigned char TIMEOUT_CC:1;
+ unsigned char TIMEOUT_PC:1;
+ unsigned char Resv:3;
+ unsigned char CHVSREGI:1;
+ unsigned char CHTREGI:1;
+ unsigned char CHRCHGI:1;
+ }bitfield;
+ unsigned char val;
+ }irq_enable3;
+ union {
+ struct {
+ unsigned char SYSLV:1;
+ unsigned char DCDC4LVHV:1;
+ unsigned char PWRONLP:1;
+ unsigned char PWRONSP:1;
+ unsigned char DCDC3LV:1;
+ unsigned char DCDC2LV:1;
+ unsigned char DCDC1LV:1;
+ unsigned char OT:1;
+ }bitfield;
+ unsigned char val;
+ }irq_enable4;
+ union {
+ struct {
+ unsigned char Resv:1;
+ unsigned char GPIO0_IE:1;
+ unsigned char GPIO1_IE:1;
+ unsigned char GPIO2_IE:1;
+ unsigned char RESETB:1;
+ unsigned char PWRONF:1;
+ unsigned char PWRONR:1;
+ unsigned char KPSHDN:1;
+ }bitfield;
+ unsigned char val;
+ }irq_enable5;
+};
+
+#define CHG_EVENT_INACOVP (0x80<<16)
+#define CHG_EVENT_INAC_PLUGIN (0x40<<16)
+#define CHG_EVENT_INUSBOVP (0x10<<16)
+#define CHG_EVENT_INUSB_PLUGIN (0x08<<16)
+#define CHG_EVENT_BAT_ABS (0x01<<16)
+
+#define CHG_EVENT_CHSLPI_INAC (0x80<<8)
+#define CHG_EVENT_CHBADI_INAC (0x40<<8)
+#define CHG_EVENT_CHGOODI_INAC (0x20<<8)
+#define CHG_EVENT_CHSLPI_INUSB (0x10<<8)
+#define CHG_EVENT_CHBADI_INUSB (0x08<<8)
+#define CHG_EVENT_CHGOODI_INUSB (0x04<<8)
+#define CHG_EVENT_CHBATOVI (0x02<<8)
+#define CHG_EVENT_CHTERMI (0x01<<8)
+
+#define CHG_EVENT_CHRCHGI (0x80<<0)
+#define CHG_EVENT_CHTREGI (0x40<<0)
+#define CHG_EVENT_CHVSREGI (0x20<<0)
+#define CHG_EVENT_TIMEOUTPC (0x02<<0)
+#define CHG_EVENT_TIMEOUTCC (0x01<<0)
+
+#define CHARGER_DETECT_MASK (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN | \
+ CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB | \
+ CHG_EVENT_CHBADI_INAC | CHG_EVENT_CHBADI_INUSB)
+
+#define PWR_EVENT_OTIQ (0x80<<8)
+#define PWR_EVENT_DCDC1LV (0x40<<8)
+#define PWR_EVENT_DCDC2LV (0x20<<8)
+#define PWR_EVENT_DCDC3LV (0x10<<8)
+#define PWR_EVENT_PWRONSP (0x08<<8)
+#define PWR_EVENT_PWRONLP (0x04<<8)
+#define PWR_EVENT_DCDC4LVHV (0x02<<8)
+#define PWR_EVENT_SYSLV (0x01<<8)
+
+#define PWR_EVENT_KPSHDN (0x80<<0)
+#define PWR_EVNET_PWRONR (0x40<<0)
+#define PWR_EVENT_PWRONF (0x20<<0)
+#define PWR_EVENT_RESETB (0x10<<0)
+#define PWR_EVENT_GPIO2IE (0x08<<0)
+#define PWR_EVENT_GPIO1IE (0x04<<0)
+#define PWR_EVENT_GPIO0IE (0x02<<0)
+
+struct rt5025_event_callback {
+ #if 1
+ void (*charger_event_callback)(uint32_t detected);
+ void (*power_event_callkback)(uint32_t detected);
+ #else
+ void (*over_temperature_callback)(uint8_t detected);
+ void (*charging_complete_callback)(void);
+ void (*over_voltage_callback)(uint8_t detected);
+ void (*under_voltage_callback)(uint8_t detected);
+ void (*charge_fault_callback)(uint8_t detected);
+ void (*charge_warning_callback)(uint8_t detected);
+ #endif
+};
+
+struct rt5025_power_info {
+ struct i2c_client *i2c;
+ struct device *dev;
+ struct rt5025_gauge_callbacks *event_callback;
+ struct power_supply ac;
+ struct power_supply usb;
+ unsigned ac_online:1;
+ unsigned usb_online:1;
+ unsigned chg_stat:3;
+};
+
+struct rt5025_chip {
+ struct i2c_client *i2c;
+ struct workqueue_struct *wq;
+ struct device *dev;
+ struct rt5025_power_info *power_info;
+ int suspend;
+ int irq;
+ struct delayed_work delayed_work;
+ struct mutex io_lock;
+};
+
+struct rt5025_platform_data {
+ struct regulator_init_data* regulator[RT5025_MAX_REGULATOR];
+ struct rt5025_power_data* power_data;
+ struct rt5025_gpio_data* gpio_data;
+ struct rt5025_misc_data* misc_data;
+ struct rt5025_irq_data* irq_data;
+ struct rt5025_event_callback *cb;
+ int (*pre_init)(struct rt5025_chip *rt5025_chip);
+ /** Called after subdevices are set up */
+ int (*post_init)(void);
+ int intr_pin;
+};
+
+#ifdef CONFIG_MFD_RT5025_MISC
+extern void rt5025_power_off(void);
+#endif /* CONFIG_MFD_RT5025_MISC */
+
+#ifdef CONFIG_POWER_RT5025
+extern int rt5025_gauge_init(struct rt5025_power_info *);
+extern int rt5025_power_passirq_to_gauge(struct rt5025_power_info *);
+extern int rt5025_power_charge_detect(struct rt5025_power_info *);
+#endif /* CONFIG_POEWR_RT5025 */
+
+extern int rt5025_reg_block_read(struct i2c_client *, int, int, void *);
+extern int rt5025_reg_read(struct i2c_client *, int);
+extern int rt5025_reg_write(struct i2c_client *, int, unsigned char);
+extern int rt5025_assign_bits(struct i2c_client *, int, unsigned char, unsigned char);
+extern int rt5025_set_bits(struct i2c_client *, int, unsigned char);
+extern int rt5025_clr_bits(struct i2c_client *, int, unsigned char);
+
+extern int rt5025_core_init(struct rt5025_chip *, struct rt5025_platform_data *);
+extern int rt5025_core_deinit(struct rt5025_chip *);
+
+#ifdef CONFIG_MFD_RT_SHOW_INFO
+#define RTINFO(format, args...) \
+ printk(KERN_INFO "%s:%s() line-%d: " format, RT5025_DEVICE_NAME,__FUNCTION__,__LINE__, ##args)
+#else
+#define RTINFO(format,args...)
+#endif /* CONFIG_MFD_RT_SHOW_INFO */
+
+#endif /* __LINUX_MFD_RT5025_H */
--- /dev/null
+/*
+ * rt5025_gauge.h
+ * fuel-gauge driver
+ * revision 0.1
+ */
+
+#ifndef __LINUX_RT5025_GAUGE_H_
+#define __LINUX_RT5025_GAUGE_H_
+
+#define GPIO_GAUGE_ALERT 4
+
+struct rt5025_gauge_callbacks {
+ void (*rt5025_gauge_irq_handler)(void);
+ void (*rt5025_gauge_set_status)(int status);
+ void (*rt5025_gauge_suspend)(void);
+ void (*rt5025_gauge_resume)(void);
+ void (*rt5025_gauge_remove)(void);
+};
+
+
+typedef enum{
+ CHG,
+ DCHG
+}operation_mode;
+
+typedef enum{
+ MAXTEMP,
+ MINTEMP,
+ MAXVOLT,
+ MINVOLT1,
+ MINVOLT2,
+ TEMP_RLS,
+ VOLT_RLS,
+ LAST_TYPE
+}alert_type;
+
+#endif /* #ifndef __LINUX_RT5025_GAUGE_H_ */
--- /dev/null
+/*
+ * include/linux/power/rt5025-power.h
+ * Include header file for Richtek RT5025 Core Power Driver
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_POWER_H
+#define __LINUX_RT5025_POWER_H
+
+#define RT5025_REG_CHGSTAT 0x01
+#define RT5025_REG_CHGCTL2 0x02
+#define RT5025_REG_CHGCTL3 0x03
+#define RT5025_REG_CHGCTL4 0x04
+#define RT5025_REG_CHGCTL5 0x05
+#define RT5025_REG_CHGCTL6 0x06
+#define RT5025_REG_CHGCTL7 0x07
+
+#define RT5025_CHGRST_MASK 0x80
+
+#define RT5025_CHGBUCKEN_MASK 0x02
+#define RT5025_CHGCEN_MASK 0x10
+
+#define RT5025_CHGSTAT_MASK 0x30
+#define RT5025_CHGSTAT_SHIFT 4
+#define RT5025_CHGSTAT_UNKNOWN 0x04
+
+#define RT5025_CHG_ACONLINE 0x02
+#define RT5025_CHG_ACSHIFT 1
+#define RT5025_CHG_USBONLINE 0x01
+#define RT5025_CHG_USBSHIFT 0
+
+#endif /* #ifndef __LINUX_RT5025_POWER_H */
--- /dev/null
+/*
+ * include/linux/regulator/rt5025-regulator.h
+ * Include header file to Richtek RT5025 Regulator driver
+ *
+ * Copyright (C) 2013 Richtek Electronics
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RT5025_REGULATOR_H
+#define __LINUX_RT5025_REGULATOR_H
+
+#define RT5025_REG_DCDCCTRL1 0x08
+#define RT5025_REG_DCDCCTRL2 0x09
+#define RT5025_REG_DCDCCTRL3 0x0A
+#define RT5025_REG_DCDCCTRL4 0x0B
+#define RT5025_REG_LDOCTRL1 0x0D
+#define RT5025_REG_LDOCTRL2 0x0E
+#define RT5025_REG_LDOCTRL3 0x0F
+#define RT5025_REG_LDOCTRL4 0x10
+#define RT5025_REG_LDOCTRL5 0x11
+#define RT5025_REG_LDOCTRL6 0x12
+#define RT5025_REG_DCDCEN 0x17
+#define RT5025_REG_LDOEN 0x18
+
+#define RT5025_DCDCVOUT1 RT5025_REG_DCDCCTRL1
+#define RT5025_DCDCVOUT2 RT5025_REG_DCDCCTRL2
+#define RT5025_DCDCVOUT3 RT5025_REG_DCDCCTRL3
+#define RT5025_DCDCVOUT4 RT5025_REG_DCDCCTRL4
+#define RT5025_LDOVOUT1 RT5025_REG_LDOCTRL1
+#define RT5025_LDOVOUT2 RT5025_REG_LDOCTRL2
+#define RT5025_LDOVOUT3 RT5025_REG_LDOCTRL3
+#define RT5025_LDOVOUT4 RT5025_REG_LDOCTRL4
+#define RT5025_LDOVOUT5 RT5025_REG_LDOCTRL5
+#define RT5025_LDOVOUT6 RT5025_REG_LDOCTRL6
+
+#define RT5025_DCDCVOUT_SHIFT1 2
+#define RT5025_DCDCVOUT_SHIFT2 1
+#define RT5025_DCDCVOUT_SHIFT3 2
+#define RT5025_DCDCVOUT_SHIFT4 0
+#define RT5025_LDOVOUT_SHIFT1 0
+#define RT5025_LDOVOUT_SHIFT2 0
+#define RT5025_LDOVOUT_SHIFT3 3
+#define RT5025_LDOVOUT_SHIFT4 3
+#define RT5025_LDOVOUT_SHIFT5 3
+#define RT5025_LDOVOUT_SHIFT6 3
+
+#define RT5025_DCDCVOUT_MASK1 0xFC
+#define RT5025_DCDCVOUT_MASK2 0xFE
+#define RT5025_DCDCVOUT_MASK3 0xFC
+#define RT5025_DCDCVOUT_MASK4 0x0F
+#define RT5025_LDOVOUT_MASK1 0x7F
+#define RT5025_LDOVOUT_MASK2 0x7F
+#define RT5025_LDOVOUT_MASK3 0xF8
+#define RT5025_LDOVOUT_MASK4 0xF8
+#define RT5025_LDOVOUT_MASK5 0xF8
+#define RT5025_LDOVOUT_MASK6 0xF8
+
+#define RT5025_DCDC_OUTPUT_EN RT5025_REG_DCDCEN
+#define RT5025_LDO_OUTPUT_EN RT5025_REG_LDOEN
+
+#define RT5025_DCDCEN_MASK1 0x01
+#define RT5025_DCDCEN_MASK2 0x02
+#define RT5025_DCDCEN_MASK3 0x04
+#define RT5025_DCDCEN_MASK4 0x08
+#define RT5025_LDOEN_MASK1 0x01
+#define RT5025_LDOEN_MASK2 0x02
+#define RT5025_LDOEN_MASK3 0x04
+#define RT5025_LDOEN_MASK4 0x08
+#define RT5025_LDOEN_MASK5 0x10
+#define RT5025_LDOEN_MASK6 0x20
+
+#endif /* __LINUX_RT5025_REGULATOR_H */