From 48f7a1b9a34352b536220b3fe1eb420d9c301253 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Wed, 14 Sep 2011 22:33:46 -0700 Subject: [PATCH] add pmu act8891 drivers --- arch/arm/mach-rk29/board-rk29-ddr3sdk.c | 286 +++++++++++ drivers/regulator/Kconfig | 5 + drivers/regulator/Makefile | 1 + drivers/regulator/act8891.c | 637 ++++++++++++++++++++++++ include/linux/regulator/act8891.h | 48 ++ 5 files changed, 977 insertions(+) create mode 100755 drivers/regulator/act8891.c create mode 100755 include/linux/regulator/act8891.h diff --git a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c index 4c17524f75c0..b74587b1aeb3 100755 --- a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c +++ b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c @@ -50,6 +50,8 @@ #include #include +#include + #include #include #include @@ -995,6 +997,281 @@ struct bq27510_platform_data bq27510_info = { }; #endif +/*************************************PMU ACT8891****************************************/ + +#if defined (CONFIG_REGULATOR_ACT8891) + /*dcdc mode*/ +/*act8891 in REGULATOR_MODE_STANDBY mode is said DCDC is in PMF mode is can save power,when in REGULATOR_MODE_NORMAL +mode is said DCDC is in PWM mode , General default is in REGULATOR_MODE_STANDBY mode*/ + /*ldo mode */ +/*act8891 in REGULATOR_MODE_STANDBY mode is said LDO is in low power mode is can save power,when in REGULATOR_MODE_NORMAL +mode is said DCDC is in nomal mode , General default is in REGULATOR_MODE_STANDBY mode*/ +/*set dcdc and ldo voltage by regulator_set_voltage()*/ +static struct act8891 *act8891; +int act8891_set_init(struct act8891 *act8891) +{ + int tmp = 0; + struct regulator *act_ldo1,*act_ldo2,*act_ldo3,*act_ldo4; + struct regulator *act_dcdc1,*act_dcdc2,*act_dcdc3; + + /*init ldo1*/ + act_ldo1 = regulator_get(NULL, "act_ldo1"); + regulator_enable(act_ldo1); + regulator_set_voltage(act_ldo1,1800000,1800000); + tmp = regulator_get_voltage(act_ldo1); + regulator_set_mode(act_ldo1,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_ldo1,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: ldo1 vcc =%d\n",tmp); + regulator_put(act_ldo1); + + /*init ldo2*/ + act_ldo2 = regulator_get(NULL, "act_ldo2"); + regulator_enable(act_ldo2); + regulator_set_voltage(act_ldo2,1200000,1200000); + tmp = regulator_get_voltage(act_ldo2); + regulator_set_mode(act_ldo2,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_ldo2,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: ldo2 vcc =%d\n",tmp); + regulator_put(act_ldo2); + + /*init ldo3*/ + act_ldo3 = regulator_get(NULL, "act_ldo3"); + regulator_enable(act_ldo3); + regulator_set_voltage(act_ldo3,3300000,3300000); + tmp = regulator_get_voltage(act_ldo3); + regulator_set_mode(act_ldo3,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_ldo3,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: ldo3 vcc =%d\n",tmp); + regulator_put(act_ldo3); + + /*init ldo4*/ + act_ldo4 = regulator_get(NULL, "act_ldo4"); + regulator_enable(act_ldo4); + regulator_set_voltage(act_ldo4,2500000,2500000); + tmp = regulator_get_voltage(act_ldo4); + regulator_set_mode(act_ldo4,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_ldo4,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: ldo4 vcc =%d\n",tmp); + regulator_put(act_ldo4); + + /*init dcdc1*/ + act_dcdc1 = regulator_get(NULL, "act_dcdc1"); + regulator_enable(act_dcdc1); + regulator_set_voltage(act_dcdc1,3000000,3000000); + tmp = regulator_get_voltage(act_dcdc1); + regulator_set_mode(act_dcdc1,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_dcdc1,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: dcdc1 vcc =%d\n",tmp); + regulator_put(act_dcdc1); + + /*init dcdc2*/ + act_dcdc2 = regulator_get(NULL, "act_dcdc2"); + regulator_enable(act_dcdc2); + regulator_set_voltage(act_dcdc2,1500000,1500000); + tmp = regulator_get_voltage(act_dcdc2); + regulator_set_mode(act_dcdc2,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_dcdc2,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: dcdc2 vcc =%d\n",tmp); + regulator_put(act_dcdc2); + + /*init dcdc3*/ + act_dcdc3 = regulator_get(NULL, "act_dcdc3"); + regulator_enable(act_dcdc3); + regulator_set_voltage(act_dcdc3,1200000,1200000); + tmp = regulator_get_voltage(act_dcdc3); + regulator_set_mode(act_dcdc3,REGULATOR_MODE_STANDBY); + //regulator_set_mode(act_dcdc3,REGULATOR_MODE_NORMAL); + printk("***regulator_set_init: dcdc3 vcc =%d\n",tmp); + regulator_put(act_dcdc3); + + return(0); +} + +static struct regulator_consumer_supply act8891_ldo1_consumers[] = { + { + .supply = "act_ldo1", + } +}; + +static struct regulator_init_data act8891_ldo1_data = { + .constraints = { + .name = "ACT_LDO1", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_ldo1_consumers), + .consumer_supplies = act8891_ldo1_consumers, +}; + +/**/ +static struct regulator_consumer_supply act8891_ldo2_consumers[] = { + { + .supply = "act_ldo2", + } +}; + +static struct regulator_init_data act8891_ldo2_data = { + .constraints = { + .name = "ACT_LDO2", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_ldo2_consumers), + .consumer_supplies = act8891_ldo2_consumers, +}; + +/*ldo3 VCC_NAND WIFI/BT/FM_BCM4325*/ +static struct regulator_consumer_supply act8891_ldo3_consumers[] = { + { + .supply = "act_ldo3", + } +}; + +static struct regulator_init_data act8891_ldo3_data = { + .constraints = { + .name = "ACT_LDO3", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_ldo3_consumers), + .consumer_supplies = act8891_ldo3_consumers, +}; + +/*ldo4 VCCA CODEC_WM8994*/ +static struct regulator_consumer_supply act8891_ldo4_consumers[] = { + { + .supply = "act_ldo4", + } +}; + +static struct regulator_init_data act8891_ldo4_data = { + .constraints = { + .name = "ACT_LDO4", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_ldo4_consumers), + .consumer_supplies = act8891_ldo4_consumers, +}; +/*buck1 vcc Core*/ +static struct regulator_consumer_supply act8891_dcdc1_consumers[] = { + { + .supply = "act_dcdc1", + } +}; + +static struct regulator_init_data act8891_dcdc1_data = { + .constraints = { + .name = "ACT_DCDC1", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + //.always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_dcdc1_consumers), + .consumer_supplies = act8891_dcdc1_consumers +}; + +/*buck2 VDDDR MobileDDR VCC*/ +static struct regulator_consumer_supply act8891_dcdc2_consumers[] = { + { + .supply = "act_dcdc2", + } +}; + +static struct regulator_init_data act8891_dcdc2_data = { + .constraints = { + .name = "ACT_DCDC2", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + //.always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_dcdc2_consumers), + .consumer_supplies = act8891_dcdc2_consumers +}; + +/*buck3 vdd Core*/ +static struct regulator_consumer_supply act8891_dcdc3_consumers[] = { + { + .supply = "act_dcdc3", + } +}; + +static struct regulator_init_data act8891_dcdc3_data = { + .constraints = { + .name = "ACT_DCDC3", + .min_uV = 600000, + .max_uV = 3900000, + .apply_uV = 1, + //.always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL, + }, + .num_consumer_supplies = ARRAY_SIZE(act8891_dcdc3_consumers), + .consumer_supplies = act8891_dcdc3_consumers +}; + +struct act8891_regulator_subdev act8891_regulator_subdev_id[] = { + { + .id=0, + .initdata=&act8891_ldo1_data, + }, + + { + .id=1, + .initdata=&act8891_ldo2_data, + }, + + { + .id=2, + .initdata=&act8891_ldo3_data, + }, + + { + .id=3, + .initdata=&act8891_ldo4_data, + }, + + { + .id=4, + .initdata=&act8891_dcdc1_data, + }, + + { + .id=5, + .initdata=&act8891_dcdc2_data, + }, + { + .id=6, + .initdata=&act8891_dcdc3_data, + }, + +}; + +struct act8891_platform_data act8891_data={ + .set_init=act8891_set_init, + .num_regulators=7, + .regulators=act8891_regulator_subdev_id, + +}; +#endif /***************************************************************************************** * i2c devices @@ -1323,6 +1600,15 @@ static struct i2c_board_info __initdata board_i2c3_devices[] = { .platform_data = &bq27541_info, }, #endif +#if defined (CONFIG_REGULATOR_ACT8891) + { + .type = "act8891", + .addr = 0x5b, + .flags = 0, + .platform_data=&act8891_data, + }, +#endif + }; #endif diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6399e8c5482e..68f037653845 100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -173,6 +173,11 @@ config RK2818_REGULATOR_LP8725 depends on I2C help Say Y to enable support for the voltage regulators pmic lp8725 on the RK2818. +config REGULATOR_ACT8891 + tristate "Active Semi ACT8891 PMIC regulators" + depends on I2C + help + Support the voltage and current regulators of the ACT8891 series of PMIC devices. config RK29_PWM_REGULATOR tristate "rk2918 pwm voltage regulator" help diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index ec0e204b5541..cc77cab0d4f1 100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_RK29_PWM_REGULATOR) += rk29-pwm-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o +obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/act8891.c b/drivers/regulator/act8891.c new file mode 100755 index 000000000000..16b8ada0ad1a --- /dev/null +++ b/drivers/regulator/act8891.c @@ -0,0 +1,637 @@ +/* drivers/regulator/act8891.c + * + * Copyright (C) 2011 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/*******************************************************************/ +/* COPYRIGHT (C) ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED. */ +/******************************************************************* +FILE : act8891.c +DESC : act8891 PMIC driver +AUTHOR : zq +DATE : 2011-09-05 +NOTES : +$LOG: GPIO.C,V $ +REVISION 0.01 +********************************************************************/ + + +#include +#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 + +struct act8891 { + struct device *dev; + struct mutex io_lock; + struct i2c_client *i2c; + int num_regulators; + struct regulator_dev **rdev; +}; + +static u8 act8891_reg_read(struct act8891 *act8891, u8 reg); +static int act8891_set_bits(struct act8891 *act8891, u8 reg, u16 mask, u16 val); + + +#define act8891_BUCK1_SET_VOL_BASE 0x20 +#define act8891_BUCK2_SET_VOL_BASE 0x30 +#define act8891_BUCK3_SET_VOL_BASE 0x40 +#define act8891_LDO1_SET_VOL_BASE 0x50 +#define act8891_LDO2_SET_VOL_BASE 0x54 +#define act8891_LDO3_SET_VOL_BASE 0x60 +#define act8891_LDO4_SET_VOL_BASE 0x64 + +#define act8891_BUCK1_CONTR_BASE 0x22 +#define act8891_BUCK2_CONTR_BASE 0x32 +#define act8891_BUCK3_CONTR_BASE 0x42 +#define act8891_LDO1_CONTR_BASE 0x51 +#define act8891_LDO2_CONTR_BASE 0x55 +#define act8891_LDO3_CONTR_BASE 0x61 +#define act8891_LDO4_CONTR_BASE 0x65 + +#define BUCK_VOL_MASK 0x3f +#define LDO_VOL_MASK 0x3f + +#define VOL_MIN_IDX 0x00 +#define VOL_MAX_IDX 0x3f + +const static int buck_set_vol_base_addr[] = { + act8891_BUCK1_SET_VOL_BASE, + act8891_BUCK2_SET_VOL_BASE, + act8891_BUCK3_SET_VOL_BASE, +}; +const static int buck_contr_base_addr[] = { + act8891_BUCK1_CONTR_BASE, + act8891_BUCK2_CONTR_BASE, + act8891_BUCK3_CONTR_BASE, +}; +#define act8891_BUCK_SET_VOL_REG(x) (buck_set_vol_base_addr[x]) +#define act8891_BUCK_CONTR_REG(x) (buck_contr_base_addr[x]) + + +const static int ldo_set_vol_base_addr[] = { + act8891_LDO1_SET_VOL_BASE, + act8891_LDO2_SET_VOL_BASE, + act8891_LDO3_SET_VOL_BASE, + act8891_LDO4_SET_VOL_BASE, +}; +const static int ldo_contr_base_addr[] = { + act8891_LDO1_CONTR_BASE, + act8891_LDO2_CONTR_BASE, + act8891_LDO3_CONTR_BASE, + act8891_LDO4_CONTR_BASE, +}; +#define act8891_LDO_SET_VOL_REG(x) (ldo_set_vol_base_addr[x]) +#define act8891_LDO_CONTR_REG(x) (ldo_contr_base_addr[x]) + +const static 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, + 2700, 2800, 2850, 2900, 3000, 3100, 3200, + 3300, 3400, 3500, 3600, 3700, 3800, 3900, +}; + +const static 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, + 2700, 2800, 2850, 2900, 3000, 3100, 3200, + 3300, 3400, 3500, 3600, 3700, 3800, 3900, +}; + +static int act8891_ldo_list_voltage(struct regulator_dev *dev, unsigned index) +{ + return 1000 * ldo_voltage_map[index]; +} +static int act8891_ldo_is_enabled(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) -ACT8891_LDO1; + u16 val; + u16 mask=0x80; + val = act8891_reg_read(act8891, act8891_LDO_CONTR_REG(ldo)); + if (val < 0) + return val; + val=val&~0x7f; + if (val & mask) + return 1; + else + return 0; +} +static int act8891_ldo_enable(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo= rdev_get_id(dev) -ACT8891_LDO1; + u16 mask=0x80; + int ret; + return act8891_set_bits(act8891, act8891_LDO_CONTR_REG(ldo), mask, 0x80); + +} +static int act8891_ldo_disable(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo= rdev_get_id(dev) -ACT8891_LDO1; + u16 mask=0x80; + int ret; + return act8891_set_bits(act8891, act8891_LDO_CONTR_REG(ldo), mask, 0); + +} +static int act8891_ldo_get_voltage(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo= rdev_get_id(dev) -ACT8891_LDO1; + u16 reg = 0; + int val; + reg = act8891_reg_read(act8891,act8891_LDO_SET_VOL_REG(ldo)); + reg &= LDO_VOL_MASK; + val = 1000 * ldo_voltage_map[reg]; + return val; +} +static int act8891_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo= rdev_get_id(dev) -ACT8891_LDO1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + 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]) + return -EINVAL; + + for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; + val++){ + if (vol_map[val] >= min_vol) + break; } + + if (vol_map[val] > max_vol) + return -EINVAL; + + ret = act8891_set_bits(act8891, act8891_LDO_SET_VOL_REG(ldo), + LDO_VOL_MASK, val); + if (ret) + return ret; + +} +static int act8891_ldo_get_mode(struct regulator_dev *dev, unsigned index) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) -ACT8891_LDO1 ; + u16 mask = 0xcf; + u16 val; + val = act8891_reg_read(act8891, act8891_LDO_CONTR_REG(ldo)); + val=val|mask; + if (val== mask) + return REGULATOR_MODE_NORMAL; + else + return REGULATOR_MODE_STANDBY; + +} +static int act8891_ldo_set_mode(struct regulator_dev *dev, unsigned int mode) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) -ACT8891_LDO1 ; + u16 mask = 0x20; + switch(mode) + { + case REGULATOR_MODE_NORMAL: + return act8891_set_bits(act8891, act8891_LDO_CONTR_REG(ldo), mask, 0); + case REGULATOR_MODE_STANDBY: + return act8891_set_bits(act8891, act8891_LDO_CONTR_REG(ldo), mask, mask); + default: + printk("error:pmu_act8891 only lowpower and nomal mode\n"); + return -EINVAL; + } + + +} +static struct regulator_ops act8891_ldo_ops = { + .set_voltage = act8891_ldo_set_voltage, + .get_voltage = act8891_ldo_get_voltage, + .list_voltage = act8891_ldo_list_voltage, + .is_enabled = act8891_ldo_is_enabled, + .enable = act8891_ldo_enable, + .disable = act8891_ldo_disable, + .get_mode = act8891_ldo_get_mode, + .set_mode = act8891_ldo_set_mode, + +}; + +static int act8891_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) +{ + return 1000 * buck_voltage_map[index]; +} +static int act8891_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1; + u16 val; + u16 mask=0x80; + val = act8891_reg_read(act8891, act8891_BUCK_CONTR_REG(buck)); + if (val < 0) + return val; + val=val&~0x7f; + if (val & mask) + return 1; + else + return 0; +} +static int act8891_dcdc_enable(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1 ; + u16 mask=0x80; + return act8891_set_bits(act8891, act8891_BUCK_CONTR_REG(buck), mask, 0x80); + +} +static int act8891_dcdc_disable(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1 ; + u16 mask=0x80; + return act8891_set_bits(act8891, act8891_BUCK_CONTR_REG(buck), mask, 0); +} +static int act8891_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1 ; + u16 reg = 0; + int val; + reg = act8891_reg_read(act8891,act8891_BUCK_SET_VOL_REG(buck)); + reg &= BUCK_VOL_MASK; + val = 1000 * buck_voltage_map[reg]; + return val; +} +static int act8891_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1 ; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = buck_voltage_map; + u16 val; + int ret = 0; + + 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++){ + if (vol_map[val] >= min_vol) + break;} + + if (vol_map[val] > max_vol) + return -EINVAL; + ret = act8891_set_bits(act8891, act8891_BUCK_SET_VOL_REG(buck), + BUCK_VOL_MASK, val); + if (ret) + return ret; +} +static int act8891_dcdc_get_mode(struct regulator_dev *dev, unsigned index) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1 ; + u16 mask = 0xcf; + u16 val; + val = act8891_reg_read(act8891, act8891_BUCK_CONTR_REG(buck)); + val=val|mask; + if (val== mask) + return REGULATOR_MODE_STANDBY; + else + return REGULATOR_MODE_NORMAL; + +} +static int act8891_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode) +{ + struct act8891 *act8891 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) -ACT8891_DCDC1 ; + u16 mask = 0x20; + switch(mode) + { + case REGULATOR_MODE_STANDBY: + return act8891_set_bits(act8891, act8891_BUCK_CONTR_REG(buck), mask, 0); + case REGULATOR_MODE_NORMAL: + return act8891_set_bits(act8891, act8891_BUCK_CONTR_REG(buck), mask, mask); + default: + printk("error:pmu_act8891 only powersave and pwm mode\n"); + return -EINVAL; + } + + +} +static struct regulator_ops act8891_dcdc_ops = { + .set_voltage = act8891_dcdc_set_voltage, + .get_voltage = act8891_dcdc_get_voltage, + .list_voltage= act8891_dcdc_list_voltage, + .is_enabled = act8891_dcdc_is_enabled, + .enable = act8891_dcdc_enable, + .disable = act8891_dcdc_disable, + .get_mode = act8891_dcdc_get_mode, + .set_mode = act8891_dcdc_set_mode, +}; +static struct regulator_desc regulators[] = { + { + .name = "ACT_LDO1", + .id =0, + .ops = &act8891_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "ACT_LDO2", + .id = 1, + .ops = &act8891_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "ACT_LDO3", + .id = 2, + .ops = &act8891_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "ACT_LDO4", + .id = 3, + .ops = &act8891_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + + { + .name = "ACT_DCDC1", + .id = 4, + .ops = &act8891_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "ACT_DCDC2", + .id = 5, + .ops = &act8891_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "ACT_DCDC3", + .id = 6, + .ops = &act8891_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + +}; + +static int act8891_i2c_read(struct i2c_client *i2c, char reg, int count, u16 *dest) +{ + int ret; + struct i2c_adapter *adap; + struct i2c_msg msgs[2]; + + 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 = 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; +} + +static int act8891_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]; + + if(!i2c) + return ret; + if (count != 1) + return -EIO; + + 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; + + ret = i2c_transfer(adap, &msg, 1); + return ret; +} + +static u8 act8891_reg_read(struct act8891 *act8891, u8 reg) +{ + u16 val = 0; + + mutex_lock(&act8891->io_lock); + + act8891_i2c_read(act8891->i2c, reg, 1, &val); + + DBG("reg read 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff); + + mutex_unlock(&act8891->io_lock); + + return val & 0xff; +} + +static int act8891_set_bits(struct act8891 *act8891, u8 reg, u16 mask, u16 val) +{ + u16 tmp; + int ret; + + mutex_lock(&act8891->io_lock); + + ret = act8891_i2c_read(act8891->i2c, reg, 1, &tmp); + tmp = (tmp & ~mask) | val; + if (ret == 0) { + ret = act8891_i2c_write(act8891->i2c, reg, 1, tmp); + DBG("reg write 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff); + } + mutex_unlock(&act8891->io_lock); + + return ret; +} +static int __devinit setup_regulators(struct act8891 *act8891, struct act8891_platform_data *pdata) +{ + int i, err; + + act8891->num_regulators = pdata->num_regulators; + act8891->rdev = kcalloc(pdata->num_regulators, + sizeof(struct regulator_dev *), GFP_KERNEL); + if (!act8891->rdev) { + return -ENOMEM; + } + /* Instantiate the regulators */ + for (i = 0; i < pdata->num_regulators; i++) { + int id = pdata->regulators[i].id; + act8891->rdev[i] = regulator_register(®ulators[id], + act8891->dev, pdata->regulators[i].initdata, act8891); +/* + if (IS_ERR(act8891->rdev[i])) { + err = PTR_ERR(act8891->rdev[i]); + dev_err(act8891->dev, "regulator init failed: %d\n", + err); + goto error; + }*/ + } + + return 0; +error: + while (--i >= 0) + regulator_unregister(act8891->rdev[i]); + kfree(act8891->rdev); + act8891->rdev = NULL; + return err; +} + +static int __devinit act8891_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct act8891 *act8891; + struct act8891_platform_data *pdata = i2c->dev.platform_data; + int ret; + act8891 = kzalloc(sizeof(struct act8891), GFP_KERNEL); + if (act8891 == NULL) { + ret = -ENOMEM; + goto err; + } + act8891->i2c = i2c; + act8891->dev = &i2c->dev; + i2c_set_clientdata(i2c, act8891); + mutex_init(&act8891->io_lock); + + + if (pdata) { + ret = setup_regulators(act8891, pdata); + if (ret < 0) + goto err; + } else + dev_warn(act8891->dev, "No platform init data supplied\n"); + + pdata->set_init(act8891); + + return 0; + +err: + return ret; + +} + +static int __devexit act8891_i2c_remove(struct i2c_client *i2c) +{ + struct act8891 *act8891 = i2c_get_clientdata(i2c); + int i; + + for (i = 0; i < act8891->num_regulators; i++) + if (act8891->rdev[i]) + regulator_unregister(act8891->rdev[i]); + kfree(act8891->rdev); + i2c_set_clientdata(i2c, NULL); + kfree(act8891); + + return 0; +} + +static const struct i2c_device_id act8891_i2c_id[] = { + { "act8891", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, act8891_i2c_id); + +static struct i2c_driver act8891_i2c_driver = { + .driver = { + .name = "act8891", + .owner = THIS_MODULE, + }, + .probe = act8891_i2c_probe, + .remove = __devexit_p(act8891_i2c_remove), + .id_table = act8891_i2c_id, +}; + +static int __init act8891_module_init(void) +{ + int ret; + ret = i2c_add_driver(&act8891_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + return ret; +} +module_init(act8891_module_init); + +static void __exit act8891_module_exit(void) +{ + i2c_del_driver(&act8891_i2c_driver); +} +module_exit(act8891_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("zhangqing "); +MODULE_DESCRIPTION("act8891 PMIC driver"); + diff --git a/include/linux/regulator/act8891.h b/include/linux/regulator/act8891.h new file mode 100755 index 000000000000..bab564f7dc48 --- /dev/null +++ b/include/linux/regulator/act8891.h @@ -0,0 +1,48 @@ +/* include/linux/regulator/act8891.h + * + * Copyright (C) 2011 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __LINUX_REGULATOR_act8891_H +#define __LINUX_REGULATOR_act8891_H + +#include + +//#define ACT8891_START 30 + +#define ACT8891_LDO1 0 //(0+ACT8891_START) +#define ACT8891_LDO2 1 // (1+ACT8891_START) +#define ACT8891_LDO3 2 //(2+ACT8891_START) +#define ACT8891_LDO4 3 //(3+ACT8891_START) + + +#define ACT8891_DCDC1 4 //(4+ACT8891_START) +#define ACT8891_DCDC2 5 //(5+ACT8891_START) +#define ACT8891_DCDC3 6 //(6+ACT8891_START) + + +#define act8891_NUM_REGULATORS 7 +static struct act8891 *act8891; + +struct act8891_regulator_subdev { + int id; + struct regulator_init_data *initdata; +}; + +struct act8891_platform_data { + int num_regulators; + int (*set_init)(struct act8891 *act8891); + struct act8891_regulator_subdev *regulators; +}; + +#endif + -- 2.34.1