From fcabb239dc0613e6c2615399e40fe26b1ab684f2 Mon Sep 17 00:00:00 2001 From: dkl Date: Fri, 19 Sep 2014 10:46:25 +0800 Subject: [PATCH] regulator: move pmu act8931 driver to kernel 3.10 Signed-off-by: dkl --- arch/arm/boot/dts/act8931.dtsi | 61 +++ arch/arm/boot/dts/rk312x-sdk.dtsi | 60 +++ arch/arm/configs/rockchip_defconfig | 1 + drivers/regulator/Kconfig | 6 + drivers/regulator/Makefile | 1 + drivers/regulator/act8931.c | 759 ++++++++++++++++------------ 6 files changed, 572 insertions(+), 316 deletions(-) create mode 100644 arch/arm/boot/dts/act8931.dtsi diff --git a/arch/arm/boot/dts/act8931.dtsi b/arch/arm/boot/dts/act8931.dtsi new file mode 100644 index 000000000000..238ef95f58f4 --- /dev/null +++ b/arch/arm/boot/dts/act8931.dtsi @@ -0,0 +1,61 @@ + +&act8931{ + + compatible = "act,act8931"; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + regulator@0{ + reg = <0>; + regulator-compatible= "act_dcdc1"; + regulator-always-on; + regulator-boot-on; + }; + + regulator@1 { + reg = <1>; + regulator-compatible = "act_dcdc2"; + regulator-always-on; + regulator-boot-on; + }; + + regulator@2 { + reg = <2>; + regulator-compatible = "act_dcdc3"; + regulator-always-on; + regulator-boot-on; + }; + + regulator@3 { + reg = <3>; + regulator-compatible= "act_ldo1"; + regulator-always-on; + regulator-boot-on; + }; + + regulator@4 { + reg = <4>; + regulator-compatible = "act_ldo2"; + regulator-always-on; + regulator-boot-on; + }; + + regulator@5 { + reg = <5>; + regulator-compatible = "act_ldo3"; + regulator-always-on; + regulator-boot-on; + }; + + regulator@6 { + reg = <6>; + regulator-compatible = "act_ldo4"; + regulator-always-on; + regulator-boot-on; + }; + + }; + +}; diff --git a/arch/arm/boot/dts/rk312x-sdk.dtsi b/arch/arm/boot/dts/rk312x-sdk.dtsi index 2978dceb1275..f33a9a11b382 100755 --- a/arch/arm/boot/dts/rk312x-sdk.dtsi +++ b/arch/arm/boot/dts/rk312x-sdk.dtsi @@ -169,6 +169,10 @@ reg = <0x1c>; status = "okay"; }; + act8931: act8931@5b { + reg = <0x5b>; + status = "okay"; + }; rt5025: rt5025@35 { compatible = "rt,rt5025"; reg = <0x35>; @@ -616,6 +620,62 @@ }; +/include/ "act8931.dtsi" +&act8931 { + /* gpio: 0-irq, 1-pwr_hold */ + gpios = <&gpio2 GPIO_B1 GPIO_ACTIVE_HIGH>, <&gpio1 GPIO_A2 GPIO_ACTIVE_HIGH>; + act8931,system-power-controller; + + regulators { + + act8931_dcdc1_reg: regulator@0{ + regulator-name= "vccio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <0x2>; + }; + + act8931_dcdc2_reg: regulator@1 { + regulator-name= "act_dcdc2"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = <0x2>; + }; + + act8931_dcdc3_reg: regulator@2 { + regulator-name= "vdd_arm"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = <0x2>; + }; + + act8931_ldo1_reg:regulator@3 { + regulator-name= "act_ldo1"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + act8931_ldo2_reg: regulator@4 { + regulator-name= "act_ldo2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + act8931_ldo3_reg: regulator@5 { + regulator-name= "act_ldo3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + act8931_ldo4_reg: regulator@6 { + regulator-name= "act_ldo4"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + +}; + &pwm0 { status = "okay"; }; diff --git a/arch/arm/configs/rockchip_defconfig b/arch/arm/configs/rockchip_defconfig index fcf6e2d92b6c..4ea09b35ca71 100644 --- a/arch/arm/configs/rockchip_defconfig +++ b/arch/arm/configs/rockchip_defconfig @@ -370,6 +370,7 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_ACT8846=y CONFIG_ACT8846_SUPPORT_RESET=y +CONFIG_REGULATOR_ACT8931=y CONFIG_REGULATOR_RT5025=y CONFIG_REGULATOR_RT5036=y CONFIG_ROCKCHIP_PWM_REGULATOR=y diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 0e3d77db3a5d..bae14d243f81 100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -262,6 +262,12 @@ config ACT8846_SUPPORT_RESET help Support short press key to restart. +config REGULATOR_ACT8931 + tristate "Active Semi ACT8931 PMIC regulators" + depends on I2C + help + Support the voltage and current regulators of the ACT8931 series of PMIC devices. + config REGULATOR_RT5025 bool "Richtek RT5025 PMIC Voltage regulstors" depends on MFD_RT5025 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index efdfb9b86d34..c6f9f5238896 100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o ab8500-ext.o +obj-$(CONFIG_REGULATOR_ACT8931) += act8931.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o diff --git a/drivers/regulator/act8931.c b/drivers/regulator/act8931.c index d5215f1cb49a..11ae72354c3a 100755 --- a/drivers/regulator/act8931.c +++ b/drivers/regulator/act8931.c @@ -1,58 +1,72 @@ /* - * Regulator driver for Active-semi act8931 PMIC chip for rk29xx + * Regulator driver for Active-semi act8931 PMIC chip * - * Copyright (C) 2010, 2011 ROCKCHIP, Inc. - - * Based on act8891.c that is work by zhangqing + * Copyright (C) 2014 ROCKCHIP, Inc. + * + * Based on act8931.c in kernel 3.0 that is work by xhc * * 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 #include #include #include #include -#include -#include -#include #include -#include #include #include -#include -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif - +#include +#include +#include +#include +#include +#include +#include +#include + #if 0 #define DBG(x...) printk(KERN_INFO x) #else #define DBG(x...) #endif -#if 1 -#define DBG_INFO(x...) printk(KERN_INFO x) -#else -#define DBG_INFO(x...) -#endif -#define PM_CONTROL + +#define ACT8931_NUM_REGULATORS 7 struct act8931 *g_act8931; struct act8931 { unsigned int irq; + unsigned int pwr_hold_gpio; struct device *dev; struct mutex io_lock; struct i2c_client *i2c; int num_regulators; struct regulator_dev **rdev; - struct early_suspend act8931_suspend; +}; + +struct act8931_board { + int irq_gpio; + int pwr_hold_gpio; + bool pm_off; + struct regulator_init_data *act8931_init_data[ACT8931_NUM_REGULATORS]; + struct device_node *of_node[ACT8931_NUM_REGULATORS]; }; static u8 act8931_reg_read(struct act8931 *act8931, u8 reg); static int act8931_set_bits(struct act8931 *act8931, u8 reg, u16 mask, u16 val); +#define ACT8931_DCDC1 0 +#define ACT8931_DCDC2 1 +#define ACT8931_DCDC3 2 + +#define ACT8931_LDO1 3 +#define ACT8931_LDO2 4 +#define ACT8931_LDO3 5 +#define ACT8931_LDO4 6 #define act8931_BUCK1_SET_VOL_BASE 0x20 #define act8931_BUCK2_SET_VOL_BASE 0x30 @@ -86,31 +100,32 @@ static int act8931_set_bits(struct act8931 *act8931, u8 reg, u16 mask, u16 val); #define INDIS_MASK (1<<1) #define CHGEOCOUT_MASK (1<<0) -int act8931_charge_det, act8931_charge_ok; +int act8931_charge_det; EXPORT_SYMBOL(act8931_charge_det); + +int act8931_charge_ok; EXPORT_SYMBOL(act8931_charge_ok); -const static int buck_set_vol_base_addr[] = { +static const int buck_set_vol_base_addr[] = { act8931_BUCK1_SET_VOL_BASE, act8931_BUCK2_SET_VOL_BASE, act8931_BUCK3_SET_VOL_BASE, }; -const static int buck_contr_base_addr[] = { +static const int buck_contr_base_addr[] = { act8931_BUCK1_CONTR_BASE, - act8931_BUCK2_CONTR_BASE, - act8931_BUCK3_CONTR_BASE, + act8931_BUCK2_CONTR_BASE, + act8931_BUCK3_CONTR_BASE, }; #define act8931_BUCK_SET_VOL_REG(x) (buck_set_vol_base_addr[x]) #define act8931_BUCK_CONTR_REG(x) (buck_contr_base_addr[x]) - -const static int ldo_set_vol_base_addr[] = { +static const int ldo_set_vol_base_addr[] = { act8931_LDO1_SET_VOL_BASE, act8931_LDO2_SET_VOL_BASE, act8931_LDO3_SET_VOL_BASE, - act8931_LDO4_SET_VOL_BASE, + act8931_LDO4_SET_VOL_BASE, }; -const static int ldo_contr_base_addr[] = { +static const int ldo_contr_base_addr[] = { act8931_LDO1_CONTR_BASE, act8931_LDO2_CONTR_BASE, act8931_LDO3_CONTR_BASE, @@ -119,26 +134,26 @@ const static int ldo_contr_base_addr[] = { #define act8931_LDO_SET_VOL_REG(x) (ldo_set_vol_base_addr[x]) #define act8931_LDO_CONTR_REG(x) (ldo_contr_base_addr[x]) -const static int buck_voltage_map[] = { +static const int buck_voltage_map[] = { 600, 625, 650, 675, 700, 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1250, 1300, 1350, 1400, 1450, - 1500, 1550, 1600, 1650, 1700, 1750, 1800, - 1850, 1900, 1950, 2000, 2050, 2100, 2150, - 2200, 2250, 2300, 2350, 2400, 2500, 2600, + 1500, 1550, 1600, 1650, 1700, 1750, 1800, + 1850, 1900, 1950, 2000, 2050, 2100, 2150, + 2200, 2250, 2300, 2350, 2400, 2500, 2600, 2700, 2800, 2850, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, }; -const static int ldo_voltage_map[] = { +static const int ldo_voltage_map[] = { 600, 625, 650, 675, 700, 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1250, 1300, 1350, 1400, 1450, - 1500, 1550, 1600, 1650, 1700, 1750, 1800, - 1850, 1900, 1950, 2000, 2050, 2100, 2150, - 2200, 2250, 2300, 2350, 2400, 2500, 2600, + 1500, 1550, 1600, 1650, 1700, 1750, 1800, + 1850, 1900, 1950, 2000, 2050, 2100, 2150, + 2200, 2250, 2300, 2350, 2400, 2500, 2600, 2700, 2800, 2850, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, }; @@ -149,108 +164,119 @@ static int act8931_ldo_list_voltage(struct regulator_dev *dev, unsigned index) return -EINVAL; return 1000 * ldo_voltage_map[index]; } + static int act8931_ldo_is_enabled(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev) -ACT8931_LDO1; + int ldo = rdev_get_id(dev) - ACT8931_LDO1; u16 val; - u16 mask=0x80; - val = act8931_reg_read(act8931, act8931_LDO_CONTR_REG(ldo)); + u16 mask = 0x80; + + val = act8931_reg_read(act8931, act8931_LDO_CONTR_REG(ldo)); if (val < 0) return val; - val=val&~0x7f; + val = val & ~0x7f; if (val & mask) return 1; else - return 0; + return 0; } + static int act8931_ldo_enable(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo= rdev_get_id(dev) -ACT8931_LDO1; - u16 mask=0x80; + int ldo = rdev_get_id(dev) - ACT8931_LDO1; + u16 mask = 0x80; - return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), mask, 0x80); - + return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), mask, + 0x80); } + static int act8931_ldo_disable(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo= rdev_get_id(dev) -ACT8931_LDO1; - u16 mask=0x80; - - return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), mask, 0); + int ldo = rdev_get_id(dev) - ACT8931_LDO1; + u16 mask = 0x80; + return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), mask, 0); } + static int act8931_ldo_get_voltage(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo= rdev_get_id(dev) -ACT8931_LDO1; + int ldo = rdev_get_id(dev) - ACT8931_LDO1; u16 reg = 0; int val; - reg = act8931_reg_read(act8931,act8931_LDO_SET_VOL_REG(ldo)); + + reg = act8931_reg_read(act8931, act8931_LDO_SET_VOL_REG(ldo)); reg &= LDO_VOL_MASK; - val = 1000 * ldo_voltage_map[reg]; + val = 1000 * ldo_voltage_map[reg]; + return val; } + static int act8931_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) + int min_uV, int max_uV, unsigned *selector) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo= rdev_get_id(dev) -ACT8931_LDO1; + int ldo = rdev_get_id(dev) - ACT8931_LDO1; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const int *vol_map =ldo_voltage_map; + const int *vol_map = ldo_voltage_map; u16 val; int ret = 0; - if (min_vol < vol_map[VOL_MIN_IDX] || - min_vol > vol_map[VOL_MAX_IDX]) + + if (min_vol < vol_map[VOL_MIN_IDX] || min_vol > vol_map[VOL_MAX_IDX]) return -EINVAL; - for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; - val++){ + for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; val++) { if (vol_map[val] >= min_vol) - break; } - + break; + } + if (vol_map[val] > max_vol) return -EINVAL; ret = act8931_set_bits(act8931, act8931_LDO_SET_VOL_REG(ldo), - LDO_VOL_MASK, val); - return ret; + LDO_VOL_MASK, val); + return ret; } + static unsigned int act8931_ldo_get_mode(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev) -ACT8931_LDO1 ; + int ldo = rdev_get_id(dev) - ACT8931_LDO1; u16 mask = 0xcf; u16 val; + val = act8931_reg_read(act8931, act8931_LDO_CONTR_REG(ldo)); - val=val|mask; - if (val== mask) + val = val | mask; + + if (val == mask) return REGULATOR_MODE_NORMAL; else return REGULATOR_MODE_STANDBY; - } + static int act8931_ldo_set_mode(struct regulator_dev *dev, unsigned int mode) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev) -ACT8931_LDO1 ; + int ldo = rdev_get_id(dev) - ACT8931_LDO1; u16 mask = 0x20; - switch(mode) - { + + switch (mode) { case REGULATOR_MODE_NORMAL: - return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), mask, 0); + return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), + mask, 0); case REGULATOR_MODE_STANDBY: - return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), mask, mask); + return act8931_set_bits(act8931, act8931_LDO_CONTR_REG(ldo), + mask, mask); default: - printk("error:pmu_act8931 only lowpower and nomal mode\n"); + pr_err("pmu_act8931 only lowpower and normal mode\n"); return -EINVAL; } - - } + static struct regulator_ops act8931_ldo_ops = { .set_voltage = act8931_ldo_set_voltage, .get_voltage = act8931_ldo_get_voltage, @@ -260,250 +286,265 @@ static struct regulator_ops act8931_ldo_ops = { .disable = act8931_ldo_disable, .get_mode = act8931_ldo_get_mode, .set_mode = act8931_ldo_set_mode, - }; static int act8931_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) { if (index >= ARRAY_SIZE(buck_voltage_map)) return -EINVAL; + return 1000 * buck_voltage_map[index]; } + static int act8931_dcdc_is_enabled(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1; + int buck = rdev_get_id(dev) - ACT8931_DCDC1; u16 val; - u16 mask=0x80; + u16 mask = 0x80; + val = act8931_reg_read(act8931, act8931_BUCK_CONTR_REG(buck)); if (val < 0) return val; - val=val&~0x7f; + val = val & ~0x7f; if (val & mask) return 1; else - return 0; + return 0; } + static int act8931_dcdc_enable(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1 ; - u16 mask=0x80; - return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), mask, 0x80); + int buck = rdev_get_id(dev) - ACT8931_DCDC1; + u16 mask = 0x80; + return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), mask, + 0x80); } + static int act8931_dcdc_disable(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1 ; - u16 mask=0x80; - return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), mask, 0); + int buck = rdev_get_id(dev) - ACT8931_DCDC1; + u16 mask = 0x80; + + return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), mask, 0); } + static int act8931_dcdc_get_voltage(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1 ; + int buck = rdev_get_id(dev) - ACT8931_DCDC1; u16 reg = 0; int val; - reg = act8931_reg_read(act8931,act8931_BUCK_SET_VOL_REG(buck)); + + reg = act8931_reg_read(act8931, act8931_BUCK_SET_VOL_REG(buck)); reg &= BUCK_VOL_MASK; - DBG("%d\n", reg); - val = 1000 * buck_voltage_map[reg]; - DBG("%d\n", val); + DBG("%d\n", reg); + val = 1000 * buck_voltage_map[reg]; + DBG("%d\n", val); + return val; } + static int act8931_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) + int min_uV, int max_uV, unsigned *selector) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1 ; + int buck = rdev_get_id(dev) - ACT8931_DCDC1; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const int *vol_map = buck_voltage_map; u16 val; int ret = 0; - DBG("%s, min_uV = %d, max_uV = %d!\n", __func__, min_uV, max_uV); + DBG("%s, min_uV = %d, max_uV = %d!\n", __func__, min_uV, max_uV); if (min_vol < vol_map[VOL_MIN_IDX] || min_vol > vol_map[VOL_MAX_IDX]) return -EINVAL; - for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; - val++){ + for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; val++) { if (vol_map[val] >= min_vol) - break;} + break; + } if (vol_map[val] > max_vol) - printk("WARNING:this voltage is not support!voltage set is %d mv\n",vol_map[val]); + pr_warn("this voltage is not support!voltage set is %d mv\n", + vol_map[val]); + ret = act8931_set_bits(act8931, act8931_BUCK_SET_VOL_REG(buck), - BUCK_VOL_MASK, val); + BUCK_VOL_MASK, val); ret = act8931_set_bits(act8931, act8931_BUCK_SET_VOL_REG(buck) + 0x01, - BUCK_VOL_MASK, val); - //if (ret) - return ret; + BUCK_VOL_MASK, val); + + return ret; } + static unsigned int act8931_dcdc_get_mode(struct regulator_dev *dev) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1 ; + int buck = rdev_get_id(dev) - ACT8931_DCDC1; u16 mask = 0xcf; u16 val; + val = act8931_reg_read(act8931, act8931_BUCK_CONTR_REG(buck)); - val=val|mask; - if (val== mask) + val = val | mask; + if (val == mask) return REGULATOR_MODE_STANDBY; else return REGULATOR_MODE_NORMAL; - } + static int act8931_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode) { struct act8931 *act8931 = rdev_get_drvdata(dev); - int buck = rdev_get_id(dev) -ACT8931_DCDC1 ; + int buck = rdev_get_id(dev) - ACT8931_DCDC1; u16 mask = 0x20; - switch(mode) - { + + switch (mode) { case REGULATOR_MODE_STANDBY: - return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), mask, 0); + return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), + mask, 0); case REGULATOR_MODE_NORMAL: - return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), mask, mask); + return act8931_set_bits(act8931, act8931_BUCK_CONTR_REG(buck), + mask, mask); default: - printk("error:pmu_act8931 only powersave and pwm mode\n"); + pr_err("pmu_act8931 only powersave and pwm mode\n"); return -EINVAL; } - - } -static struct regulator_ops act8931_dcdc_ops = { + +static struct regulator_ops act8931_dcdc_ops = { .set_voltage = act8931_dcdc_set_voltage, .get_voltage = act8931_dcdc_get_voltage, - .list_voltage= act8931_dcdc_list_voltage, + .list_voltage = act8931_dcdc_list_voltage, .is_enabled = act8931_dcdc_is_enabled, .enable = act8931_dcdc_enable, .disable = act8931_dcdc_disable, .get_mode = act8931_dcdc_get_mode, .set_mode = act8931_dcdc_set_mode, }; + static struct regulator_desc regulators[] = { { - .name = "ACT_LDO1", - .id =0, - .ops = &act8931_ldo_ops, - .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .name = "ACT_DCDC1", + .id = 0, + .ops = &act8931_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "ACT_LDO2", + .name = "ACT_DCDC2", .id = 1, - .ops = &act8931_ldo_ops, - .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .ops = &act8931_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "ACT_LDO3", + .name = "ACT_DCDC3", .id = 2, - .ops = &act8931_ldo_ops, - .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .ops = &act8931_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "ACT_LDO4", + .name = "ACT_LDO1", .id = 3, .ops = &act8931_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, - { - .name = "ACT_DCDC1", + .name = "ACT_LDO2", .id = 4, - .ops = &act8931_dcdc_ops, - .n_voltages = ARRAY_SIZE(buck_voltage_map), + .ops = &act8931_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "ACT_DCDC2", + .name = "ACT_LDO3", .id = 5, - .ops = &act8931_dcdc_ops, - .n_voltages = ARRAY_SIZE(buck_voltage_map), + .ops = &act8931_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "ACT_DCDC3", + .name = "ACT_LDO4", .id = 6, - .ops = &act8931_dcdc_ops, - .n_voltages = ARRAY_SIZE(buck_voltage_map), + .ops = &act8931_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, - + }; -/* - * - */ -static int act8931_i2c_read(struct i2c_client *i2c, char reg, int count, u16 *dest) +static int act8931_i2c_read(struct i2c_client *i2c, char reg, int count, + u16 *dest) { - int ret; - struct i2c_adapter *adap; - struct i2c_msg msgs[2]; + int ret; + struct i2c_adapter *adap; + struct i2c_msg msgs[2]; - if(!i2c) + if (!i2c) return ret; if (count != 1) - return -EIO; - - 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 = (u8 *)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); - - DBG("***run in %s %d msgs[1].buf = %d\n",__FUNCTION__,__LINE__,*(msgs[1].buf)); - - return 0; + return -EIO; + + 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 = (u8 *)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); + + DBG("***run in %s %d msgs[1].buf = %d\n", __func__, __LINE__, + *(msgs[1].buf)); + + return 0; } -static int act8931_i2c_write(struct i2c_client *i2c, char reg, int count, const u16 src) +static int act8931_i2c_write(struct i2c_client *i2c, char reg, int count, + const u16 src) { - int ret=-1; - struct i2c_adapter *adap; struct i2c_msg msg; char tx_buf[2]; + int ret = -1; - if(!i2c) + if (!i2c) return ret; if (count != 1) return -EIO; - - adap = i2c->adapter; + + adap = i2c->adapter; tx_buf[0] = reg; tx_buf[1] = src; - + msg.addr = i2c->addr; msg.buf = &tx_buf[0]; - msg.len = 1 +1; - msg.flags = i2c->flags; - msg.scl_rate = 200*1000; + msg.len = 1 + 1; + msg.flags = i2c->flags; + msg.scl_rate = 200*1000; ret = i2c_transfer(adap, &msg, 1); - return 0; + + return 0; } static u8 act8931_reg_read(struct act8931 *act8931, u8 reg) @@ -518,7 +559,7 @@ static u8 act8931_reg_read(struct act8931 *act8931, u8 reg) mutex_unlock(&act8931->io_lock); - return val & 0xff; + return val & 0xff; } static int act8931_set_bits(struct act8931 *act8931, u8 reg, u16 mask, u16 val) @@ -533,192 +574,282 @@ static int act8931_set_bits(struct act8931 *act8931, u8 reg, u16 mask, u16 val) tmp = (tmp & ~mask) | val; if (ret == 0) { ret = act8931_i2c_write(act8931->i2c, reg, 1, tmp); - DBG("reg write 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff); + DBG("reg write 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val&0xff); } act8931_i2c_read(act8931->i2c, reg, 1, &tmp); DBG("2 reg read 0x%02x -> 0x%02x\n", (int)reg, (unsigned)tmp&0xff); mutex_unlock(&act8931->io_lock); - return ret; -} -static int __devinit setup_regulators(struct act8931 *act8931, struct act8931_platform_data *pdata) -{ - int i, err; - - act8931->num_regulators = pdata->num_regulators; - act8931->rdev = kcalloc(pdata->num_regulators, - sizeof(struct regulator_dev *), GFP_KERNEL); - if (!act8931->rdev) { - return -ENOMEM; - } - /* Instantiate the regulators */ - for (i = 0; i < pdata->num_regulators; i++) { - int id = pdata->regulators[i].id; - act8931->rdev[i] = regulator_register(®ulators[id], - act8931->dev, pdata->regulators[i].initdata, act8931); -/* - if (IS_ERR(act8931->rdev[i])) { - err = PTR_ERR(act8931->rdev[i]); - dev_err(act8931->dev, "regulator init failed: %d\n", - err); - goto error; - }*/ - } - - return 0; -error: - while (--i >= 0) - regulator_unregister(act8931->rdev[i]); - kfree(act8931->rdev); - act8931->rdev = NULL; - return err; + return ret; } -int act8931_device_shutdown(void) +void act8931_device_shutdown(void) { int ret; - int err = -1; struct act8931 *act8931 = g_act8931; - - printk("%s\n",__func__); - ret = act8931_reg_read(act8931,0x01); - ret = act8931_set_bits(act8931, 0x01,(0x1<<5) |(0x3<<0),(0x1<<5) | (0x3<<0)); - if (ret < 0) { - printk("act8931 set 0x00 error!\n"); - return err; - } - return 0; + pr_info("%s\n", __func__); + + ret = act8931_reg_read(act8931, 0x01); + ret = act8931_set_bits(act8931, 0x01, (0x1<<5) | (0x3<<0), + (0x1<<5) | (0x3<<0)); + if (ret < 0) + pr_err("act8931 set 0x01 error!\n"); + + mdelay(100); + arm_pm_restart('h', "charge"); } -EXPORT_SYMBOL_GPL(act8931_device_shutdown); +#ifdef CONFIG_OF +static struct of_device_id act8931_of_match[] = { + { .compatible = "act,act8931"}, + { }, +}; +MODULE_DEVICE_TABLE(of, act8931_of_match); +#endif + +#ifdef CONFIG_OF +static struct of_regulator_match act8931_reg_matches[] = { + { .name = "act_dcdc1" }, + { .name = "act_dcdc2" }, + { .name = "act_dcdc3" }, + { .name = "act_ldo1" }, + { .name = "act_ldo2" }, + { .name = "act_ldo3" }, + { .name = "act_ldo4" }, +}; -static irqreturn_t act8931_irq_thread(unsigned int irq, void *dev_id) +static struct act8931_board *act8931_parse_dt(struct act8931 *act8931) +{ + struct act8931_board *pdata; + struct device_node *regs; + struct device_node *node; + int i, count; + + node = of_node_get(act8931->dev->of_node); + if (!node) { + pr_err("%s: could not find pmic node\n", __func__); + return NULL; + } + + regs = of_get_child_by_name(node, "regulators"); + if (!regs) + return NULL; + + count = of_regulator_match(act8931->dev, regs, act8931_reg_matches, + ACT8931_NUM_REGULATORS); + of_node_put(regs); + + if ((count < 0) || (count > ACT8931_NUM_REGULATORS)) + return NULL; + + pdata = devm_kzalloc(act8931->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + for (i = 0; i < count; i++) { + pdata->act8931_init_data[i] = act8931_reg_matches[i].init_data; + pdata->of_node[i] = act8931_reg_matches[i].of_node; + } + + pdata->irq_gpio = of_get_named_gpio(node, "gpios", 0); + if (!gpio_is_valid(pdata->irq_gpio)) { + pr_err("%s: invalid gpio: %d\n", __func__, pdata->irq_gpio); + return NULL; + } + + pdata->pwr_hold_gpio = of_get_named_gpio(node, "gpios", 1); + if (!gpio_is_valid(pdata->pwr_hold_gpio)) { + pr_err("%s: invalid gpio: %d\n", __func__, + pdata->pwr_hold_gpio); + return NULL; + } + + pdata->pm_off = of_property_read_bool(node, + "act8931,system-power-controller"); + + return pdata; +} +#else +static struct act8931_board *act8931_parse_dt(struct act8931 *act8931) +{ + return NULL; +} +#endif + +static irqreturn_t act8931_irq_thread(int irq, void *dev_id) { struct act8931 *act8931 = (struct act8931 *)dev_id; int ret; u8 val; - val = act8931_reg_read(act8931,0x78); - act8931_charge_det = (val & INDAT_MASK )? 1:0; - act8931_charge_ok = (val & CHGDAT_MASK )? 1:0; - DBG(charge_det? "connect! " : "disconnect! "); - DBG(charge_ok? "charge ok! \n" : "charging or discharge! \n"); + + val = act8931_reg_read(act8931, 0x78); + act8931_charge_det = (val & INDAT_MASK) ? 1 : 0; + act8931_charge_ok = (val & CHGDAT_MASK) ? 1 : 0; + DBG(charge_det ? "connect!" : "disconnect!"); + DBG(charge_ok ? "charge ok!\n" : "charging or discharge!\n"); /* reset related regs according to spec */ - ret = act8931_set_bits(act8931, 0x78, INSTAT_MASK | CHGSTAT_MASK, - INSTAT_MASK | CHGSTAT_MASK); - if (ret < 0) { - printk("act8931 set 0x78 error!\n"); - } + ret = act8931_set_bits(act8931, 0x78, INSTAT_MASK | CHGSTAT_MASK, + INSTAT_MASK | CHGSTAT_MASK); + if (ret < 0) + pr_err("act8931 set 0x78 error!\n"); - /* FIXME: it's better that waking up screen in battery driver */ - rk28_send_wakeup_key(); return IRQ_HANDLED; } -#ifdef CONFIG_HAS_EARLYSUSPEND -__weak void act8931_early_suspend(struct early_suspend *h) {} -__weak void act8931_late_resume(struct early_suspend *h) {} -#endif - -static int __devinit act8931_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static int act8931_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct act8931 *act8931; - struct act8931_platform_data *pdata = i2c->dev.platform_data; - int ret; + const struct of_device_id *match; + struct act8931 *act8931; + struct act8931_board *pdata; + struct regulator_init_data *reg_data; + struct regulator_config config = { }; + const char *rail_name = NULL; + struct regulator_dev *rdev; u8 val; - act8931 = kzalloc(sizeof(struct act8931), GFP_KERNEL); + int i, ret; + + pr_info("%s,line=%d\n", __func__, __LINE__); + + if (i2c->dev.of_node) { + match = of_match_device(act8931_of_match, &i2c->dev); + if (!match) { + pr_err("Failed to find matching dt id\n"); + return -EINVAL; + } + } + + act8931 = devm_kzalloc(&i2c->dev, sizeof(struct act8931), GFP_KERNEL); if (act8931 == NULL) { - ret = -ENOMEM; + ret = -ENOMEM; goto err; } act8931->i2c = i2c; act8931->dev = &i2c->dev; - i2c_set_clientdata(i2c, act8931); - mutex_init(&act8931->io_lock); + g_act8931 = act8931; + + mutex_init(&act8931->io_lock); - ret = act8931_reg_read(act8931,0x22); - if ((ret < 0) || (ret == 0xff)){ - printk("The device is not act8931 \n"); + ret = act8931_reg_read(act8931, 0x22); + if ((ret < 0) || (ret == 0xff)) { + pr_err("The device is not act8931\n"); return 0; } - - if (pdata) { - ret = setup_regulators(act8931, pdata); - if (ret < 0) - goto err; - } else - dev_warn(act8931->dev, "No platform init data supplied\n"); - ret = act8931_reg_read(act8931,0x01); - if (ret < 0) - goto err; - ret = act8931_set_bits(act8931, 0x01,(0x1<<5) | (0x1<<0),(0x1<<0)); + if (act8931->dev->of_node) + pdata = act8931_parse_dt(act8931); + + ret = act8931_reg_read(act8931, 0x01); + if (ret < 0) + goto err; + ret = act8931_set_bits(act8931, 0x01, (0x1<<5) | (0x1<<0), (0x1<<0)); if (ret < 0) { - printk("act8931 set 0x01 error!\n"); + pr_err("act8931 set 0x01 error!\n"); goto err; } - - g_act8931 = act8931; - - pdata->set_init(act8931); /* Initialize charge status */ - val = act8931_reg_read(act8931,0x78); - act8931_charge_det = (val & INDAT_MASK )? 1:0; - act8931_charge_ok = (val & CHGDAT_MASK )? 1:0; - DBG(charge_det? "connect! " : "disconnect! "); - DBG(charge_ok? "charge ok! \n" : "charging or discharge! \n"); - - ret = act8931_set_bits(act8931, 0x78, INSTAT_MASK | CHGSTAT_MASK, - INSTAT_MASK | CHGSTAT_MASK); + val = act8931_reg_read(act8931, 0x78); + act8931_charge_det = (val & INDAT_MASK) ? 1 : 0; + act8931_charge_ok = (val & CHGDAT_MASK) ? 1 : 0; + DBG(charge_det ? "connect!" : "disconnect!"); + DBG(charge_ok ? "charge ok!\n" : "charging or discharge!\n"); + + ret = act8931_set_bits(act8931, 0x78, INSTAT_MASK | CHGSTAT_MASK, + INSTAT_MASK | CHGSTAT_MASK); if (ret < 0) { - printk("act8931 set 0x78 error!\n"); + pr_err("act8931 set 0x78 error!\n"); goto err; } - - ret = act8931_set_bits(act8931, 0x79, INCON_MASK | CHGEOCIN_MASK | INDIS_MASK | CHGEOCOUT_MASK, - INCON_MASK | CHGEOCIN_MASK | INDIS_MASK | CHGEOCOUT_MASK); + + ret = act8931_set_bits(act8931, 0x79, INCON_MASK | CHGEOCIN_MASK + | INDIS_MASK | CHGEOCOUT_MASK, INCON_MASK + | CHGEOCIN_MASK | INDIS_MASK | CHGEOCOUT_MASK); if (ret < 0) { - printk("act8931 set 0x79 error!\n"); + pr_err("act8931 set 0x79 error!\n"); goto err; } - ret = gpio_request(i2c->irq, "act8931 gpio"); - if(ret) - { - printk("act8931 gpio request fail\n"); - gpio_free(i2c->irq); + if (pdata) { + act8931->num_regulators = ACT8931_NUM_REGULATORS; + act8931->rdev = kcalloc(ACT8931_NUM_REGULATORS, + sizeof(struct regulator_dev *), + GFP_KERNEL); + if (!act8931->rdev) + return -ENOMEM; + + /* Instantiate the regulators */ + for (i = 0; i < ACT8931_NUM_REGULATORS; i++) { + reg_data = pdata->act8931_init_data[i]; + if (!reg_data) + continue; + if (reg_data->constraints.name) + rail_name = reg_data->constraints.name; + else + rail_name = regulators[i].name; + reg_data->supply_regulator = rail_name; + + config.dev = act8931->dev; + config.driver_data = act8931; + if (act8931->dev->of_node) + config.of_node = pdata->of_node[i]; + config.init_data = reg_data; + + rdev = regulator_register(®ulators[i], &config); + if (IS_ERR(rdev)) { + pr_err("failed to register %d regulator\n", i); + continue; + } + act8931->rdev[i] = rdev; + } + } + + if (pdata->pm_off && !pm_power_off) + pm_power_off = act8931_device_shutdown; + + act8931->pwr_hold_gpio = pdata->pwr_hold_gpio; + if (act8931->pwr_hold_gpio) { + ret = gpio_request(act8931->pwr_hold_gpio, "act8931 pmic_hold"); + if (ret < 0) { + pr_err("Failed to request gpio %d with ret %d\n", + act8931->pwr_hold_gpio, ret); + goto err; + } + gpio_direction_output(act8931->pwr_hold_gpio, 1); + ret = gpio_get_value(act8931->pwr_hold_gpio); + pr_info("%s: act8931_pmic_hold=%x\n", __func__, ret); + } + + ret = gpio_request(pdata->irq_gpio, "act8931 irq"); + if (ret) { + pr_err("act8931 irq_gpio request fail\n"); + gpio_free(pdata->irq_gpio); goto err; } - - act8931->irq = gpio_to_irq(i2c->irq); - gpio_pull_updown(i2c->irq,GPIOPullUp); + gpio_direction_input(pdata->irq_gpio); + + act8931->irq = gpio_to_irq(pdata->irq_gpio); ret = request_threaded_irq(act8931->irq, NULL, act8931_irq_thread, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, i2c->dev.driver->name, act8931); - if (ret < 0) - { - printk("request act8931 irq fail\n"); + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + i2c->dev.driver->name, act8931); + if (ret < 0) { + pr_err("request act8931 irq fail\n"); goto err; - } - + } enable_irq_wake(act8931->irq); - #ifdef CONFIG_HAS_EARLYSUSPEND - act8931->act8931_suspend.suspend = act8931_early_suspend, - act8931->act8931_suspend.resume = act8931_late_resume, - act8931->act8931_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, - register_early_suspend(&act8931->act8931_suspend); - #endif + i2c_set_clientdata(i2c, act8931); return 0; err: - return ret; - + return ret; } -static int __devexit act8931_i2c_remove(struct i2c_client *i2c) +static int act8931_i2c_remove(struct i2c_client *i2c) { struct act8931 *act8931 = i2c_get_clientdata(i2c); int i; @@ -734,33 +865,31 @@ static int __devexit act8931_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id act8931_i2c_id[] = { - { "act8931", 0 }, - { } + { "act8931", 0 }, + { } }; - MODULE_DEVICE_TABLE(i2c, act8931_i2c_id); static struct i2c_driver act8931_i2c_driver = { .driver = { .name = "act8931", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(act8931_of_match), }, .probe = act8931_i2c_probe, - .remove = __devexit_p(act8931_i2c_remove), + .remove = act8931_i2c_remove, .id_table = act8931_i2c_id, }; static int __init act8931_module_init(void) { int ret; + ret = i2c_add_driver(&act8931_i2c_driver); if (ret != 0) pr_err("Failed to register I2C driver: %d\n", ret); return ret; } -//module_init(act8931_module_init); -//subsys_initcall(act8931_module_init); -//rootfs_initcall(act8931_module_init); subsys_initcall_sync(act8931_module_init); static void __exit act8931_module_exit(void) @@ -770,7 +899,5 @@ static void __exit act8931_module_exit(void) module_exit(act8931_module_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("xhc "); +MODULE_AUTHOR("dkl "); MODULE_DESCRIPTION("act8931 PMIC driver"); - - -- 2.34.1