From 5d87f43f8a425d81b0dd915103c134d5175bea32 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Sun, 26 Jan 2014 09:58:37 +0800 Subject: [PATCH] rk:pmu:rk808&act8846:support dts for linux 3.1 --- arch/arm/boot/dts/act8846.dtsi | 76 ++++++ arch/arm/boot/dts/rk3188-tb.dts | 213 ++++++++++++++++ arch/arm/boot/dts/rk808.dtsi | 75 ++++++ arch/arm/configs/rockchip_defconfig | 3 + drivers/mfd/Kconfig | 9 + drivers/mfd/Makefile | 1 + drivers/mfd/rk808-irq.c | 99 +++++--- drivers/mfd/rk808.c | 375 ++++++++++++++++++++++------ drivers/regulator/Kconfig | 12 + drivers/regulator/Makefile | 1 + drivers/regulator/act8846.c | 345 ++++++++++++++++++++----- drivers/rtc/Kconfig | 6 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-rk808.c | 42 ++-- include/linux/mfd/rk808.h | 30 ++- include/linux/regulator/act8846.h | 21 +- 16 files changed, 1100 insertions(+), 209 deletions(-) create mode 100644 arch/arm/boot/dts/act8846.dtsi create mode 100644 arch/arm/boot/dts/rk808.dtsi diff --git a/arch/arm/boot/dts/act8846.dtsi b/arch/arm/boot/dts/act8846.dtsi new file mode 100644 index 000000000000..a69b8ba9b2f8 --- /dev/null +++ b/arch/arm/boot/dts/act8846.dtsi @@ -0,0 +1,76 @@ + +&act8846{ + + compatible = "act,act8846"; + + regulators { + + #address-cells = <1>; + #size-cells = <0>; + + dcdc1_reg: regulator@0{ + reg = <0>; + regulator-compatible= "act_dcdc1"; + }; + + dcdc2_reg: regulator@1 { + reg = <1>; + regulator-compatible = "act_dcdc2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1500000>; + }; + + dcdc3_reg: regulator@2 { + reg = <2>; + regulator-compatible = "act_dcdc3"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1500000>; + }; + + dcdc4_reg: regulator@3 { + reg = <3>; + regulator-compatible = "act_dcdc4"; + }; + + ldo1_reg: regulator@4 { + reg = <4>; + regulator-compatible= "act_ldo1"; + }; + + ldo2_reg: regulator@5 { + reg = <5>; + regulator-compatible = "act_ldo2"; + }; + + ldo3_reg: regulator@6 { + reg = <6>; + regulator-compatible = "act_ldo3"; + }; + + ldo4_reg:regulator@7 { + reg = <7>; + regulator-compatible = "act_ldo4"; + }; + + ldo5_reg: regulator@8 { + reg = <8>; + regulator-compatible= "act_ldo5"; + }; + + ldo6_reg: regulator@9 { + reg = <9>; + regulator-compatible = "act_ldo6"; + }; + + ldo7_reg: regulator@10 { + reg = <10>; + regulator-compatible = "act_ldo7"; + }; + + ldo8_reg: regulator@11 { + reg = <11>; + regulator-compatible = "act_ldo8"; + }; + }; + +}; \ No newline at end of file diff --git a/arch/arm/boot/dts/rk3188-tb.dts b/arch/arm/boot/dts/rk3188-tb.dts index 037dacbabfa8..1340e1334b9f 100644 --- a/arch/arm/boot/dts/rk3188-tb.dts +++ b/arch/arm/boot/dts/rk3188-tb.dts @@ -47,6 +47,15 @@ compatible = "nxp,pcf8563"; reg = <0x51>; }; + + act8846: act8846@5a { + reg = <0x5a>; + status = "okay"; + }; + rk808: rk808@1b { + reg = <0x1b>; + status = "okay"; + }; }; &i2c3 { @@ -69,5 +78,209 @@ &pwm3 { status = "okay"; }; +/include/ "act8846.dtsi" +&act8846 { + gpios =<&gpio3 GPIO_D3 GPIO_ACTIVE_LOW>; + act,pmic-dcdc-sleep-voltage = <1200000>,<1200000>,<1200000>,<3000000>; + act,pmic-ldo-sleep-voltage = <1000000>,<1200000>,<1800000>,<3300000>,<3300000>,<3300000>,<1800000>,<2800000>; + +regulators { + + dcdc1_reg: regulator@0{ + regulator-name= "act_dcdc1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + dcdc2_reg: regulator@1 { + regulator-name= "vdd_logic"; + regulator-always-on; + regulator-boot-on; + }; + + dcdc3_reg: regulator@2 { + regulator-name= "vdd_arm"; + regulator-always-on; + regulator-boot-on; + }; + + dcdc4_reg: regulator@3 { + regulator-name= "act_dcdc4"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo1_reg: regulator@4 { + regulator-name= "act_ldo1"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo2_reg: regulator@5 { + regulator-name= "act_ldo2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo3_reg: regulator@6 { + regulator-name= "act_ldo3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo4_reg:regulator@7 { + regulator-name= "act_ldo4"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo5_reg: regulator@8 { + regulator-name= "act_ldo5"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo6_reg: regulator@9 { + regulator-name= "act_ldo6"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo7_reg: regulator@10 { + regulator-name= "act_ldo7"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo8_reg: regulator@11 { + regulator-name= "act_ldo8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; +/include/ "rk808.dtsi" +&rk808{ + gpios =<&gpio0 GPIO_B3 GPIO_ACTIVE_HIGH>,<&gpio0 GPIO_A1 GPIO_ACTIVE_LOW>; + rockchip,pmic-dcdc-sleep-voltage = <900000>,<900000>,<1200000>,<3000000>; + rockchip,pmic-ldo-sleep-voltage = <3300000>,<3300000>,<1000000>,<1800000>,<2800000>,<1200000>,<1800000>,<1800000>; + +regulators { + + rk808_dcdc1_reg: regulator@0{ + regulator-name= "vdd_arm"; + regulator-always-on; + regulator-boot-on; + /* regulator-initial-mode = <2>;*/ + }; + + rk808_dcdc2_reg: regulator@1 { + regulator-name= "vdd_logic"; + regulator-always-on; + regulator-boot-on; + /* regulator-initial-mode = <2>;*/ + }; + + rk808_dcdc3_reg: regulator@2 { + regulator-name= "rk_dcdc3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_dcdc4_reg: regulator@3 { + regulator-name= "rk_dcdc4"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo1_reg: regulator@4 { + regulator-name= "rk_ldo1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo2_reg: regulator@5 { + regulator-name= "rk_ldo2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo3_reg: regulator@6 { + regulator-name= "rk_ldo3"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo4_reg:regulator@7 { + regulator-name= "rk_ldo4"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo5_reg: regulator@8 { + regulator-name= "rk_ldo5"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo6_reg: regulator@9 { + regulator-name= "rk_ldo6"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo7_reg: regulator@10 { + regulator-name= "rk_ldo7"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + rk808_ldo8_reg: regulator@11 { + regulator-name= "rk_ldo8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; diff --git a/arch/arm/boot/dts/rk808.dtsi b/arch/arm/boot/dts/rk808.dtsi new file mode 100644 index 000000000000..2ad195719137 --- /dev/null +++ b/arch/arm/boot/dts/rk808.dtsi @@ -0,0 +1,75 @@ + + +&rk808 { + compatible = "rockchip,rk808"; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + rk808_dcdc1_reg: regulator@0 { + reg = <0>; + regulator-compatible = "rk_dcdc1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1500000>; + }; + + rk808_dcdc2_reg: regulator@1 { + reg = <1>; + regulator-compatible = "rk_dcdc2"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1500000>; + }; + + rk808_dcdc3_reg: regulator@2 { + reg = <2>; + regulator-compatible = "rk_dcdc3"; + }; + + rk808_dcdc4_reg: regulator@3 { + reg = <3>; + regulator-compatible = "rk_dcdc4"; + }; + + rk808_ldo1_reg: regulator@4 { + reg = <4>; + regulator-compatible = "rk_ldo1"; + }; + + rk808_ldo2_reg: regulator@5 { + reg = <5>; + regulator-compatible = "rk_ldo2"; + }; + + rk808_ldo3_reg: regulator@6 { + reg = <6>; + regulator-compatible = "rk_ldo3"; + }; + + rk808_ldo4_reg: regulator@7{ + reg = <7>; + regulator-compatible = "rk_ldo4"; + }; + + rk808_ldo5_reg: regulator@8{ + reg = <8>; + regulator-compatible = "rk_ldo5"; + }; + + rk808_ldo6_reg: regulator@9{ + reg = <9>; + regulator-compatible = "rk_ldo6"; + }; + + rk808_ldo7_reg: regulator@10 { + reg = <10>; + regulator-compatible = "rk_ldo7"; + }; + + rk808_ldo8_reg: regulator@11{ + reg = <11>; + regulator-compatible = "rk_ldo8"; + }; + + }; +}; diff --git a/arch/arm/configs/rockchip_defconfig b/arch/arm/configs/rockchip_defconfig index fa47b6ede65e..7af47ef708cd 100644 --- a/arch/arm/configs/rockchip_defconfig +++ b/arch/arm/configs/rockchip_defconfig @@ -276,8 +276,10 @@ CONFIG_SPI=y CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_THERMAL=y +CONFIG_MFD_RK808=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_ACT8846=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_RC_SUPPORT=y @@ -395,6 +397,7 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_PCF8563=y +CONFIG_RK808_RTC=y CONFIG_STAGING=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a5e54f0d6a73..53ba537bf47c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -349,6 +349,15 @@ config MFD_MAX8998 additional drivers must be enabled in order to use the functionality of the device. +config MFD_RK808 + bool "RK808 Power Management chip" + depends on I2C=y + select MFD_CORE + select RTC_RK808 + help + if you say yes here you get support for the RK808 series of + Power Management chips. + config EZX_PCAP bool "Motorola EZXPCAP Support" depends on GENERIC_HARDIRQS && SPI_MASTER diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 3a0120315aa3..72f479c0971d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -144,6 +144,7 @@ obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o +obj-$(CONFIG_MFD_RK808) += rk808.o rk808-irq.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o diff --git a/drivers/mfd/rk808-irq.c b/drivers/mfd/rk808-irq.c index 229a968f7e71..dbae25e4dccf 100755 --- a/drivers/mfd/rk808-irq.c +++ b/drivers/mfd/rk808-irq.c @@ -21,11 +21,14 @@ #include #include #include +#include +#include + static inline int irq_to_rk808_irq(struct rk808 *rk808, int irq) { - return (irq - rk808->irq_base); + return (irq - rk808->chip_irq); } /* @@ -43,8 +46,9 @@ static irqreturn_t rk808_irq(int irq, void *irq_data) u32 irq_sts; u32 irq_mask; u8 reg; - int i; - //printk(" rk808 irq %d \n",irq); + int i, cur_irq; +// printk("%s,line=%d\n", __func__,__LINE__); + wake_lock(&rk808->irq_wake); rk808_i2c_read(rk808, RK808_INT_STS_REG1, 1, ®); irq_sts = reg; @@ -65,11 +69,12 @@ static irqreturn_t rk808_irq(int irq, void *irq_data) } for (i = 0; i < rk808->irq_num; i++) { - if (!(irq_sts & (1 << i))) continue; + cur_irq = irq_find_mapping(rk808->irq_domain, i); - handle_nested_irq(rk808->irq_base + i); + if (cur_irq) + handle_nested_irq(cur_irq); } /* Write the STS register back to clear IRQs we handled */ @@ -141,26 +146,38 @@ static struct irq_chip rk808_irq_chip = { .irq_enable = rk808_irq_enable, .irq_set_wake = rk808_irq_set_wake, }; - -int rk808_irq_init(struct rk808 *rk808, int irq,struct rk808_platform_data *pdata) +static int rk808_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) { - int ret, cur_irq; - int flags = IRQF_ONESHOT; - u8 reg; + struct rk808 *rk808 = d->host_data; - printk("%s,line=%d\n", __func__,__LINE__); + irq_set_chip_data(irq, rk808); + irq_set_chip_and_handler(irq, &rk808_irq_chip, handle_edge_irq); + irq_set_nested_thread(irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + return 0; +} +static struct irq_domain_ops rk808_irq_domain_ops = { + .map = rk808_irq_domain_map, +}; +int rk808_irq_init(struct rk808 *rk808, int irq,struct rk808_board *pdata) +{ + struct irq_domain *domain; + int ret,val; + u8 reg; + +// printk("%s,line=%d\n", __func__,__LINE__); if (!irq) { dev_warn(rk808->dev, "No interrupt support, no core IRQ\n"); return 0; } - if (!pdata || !pdata->irq_base) { - dev_warn(rk808->dev, "No interrupt support, no IRQ base\n"); - return 0; - } - /* Clear unattended interrupts */ rk808_i2c_read(rk808, RK808_INT_STS_REG1, 1, ®); rk808_i2c_write(rk808, RK808_INT_STS_REG1, 1, reg); @@ -171,35 +188,39 @@ int rk808_irq_init(struct rk808 *rk808, int irq,struct rk808_platform_data *pdat /* Mask top level interrupts */ rk808->irq_mask = 0xFFFFFF; - mutex_init(&rk808->irq_lock); wake_lock_init(&rk808->irq_wake, WAKE_LOCK_SUSPEND, "rk808_irq_wake"); - rk808->chip_irq = irq; - rk808->irq_base = pdata->irq_base; - rk808->irq_num = RK808_NUM_IRQ; - - /* Register with genirq */ - for (cur_irq = rk808->irq_base; - cur_irq < rk808->irq_num + rk808->irq_base; - cur_irq++) { - irq_set_chip_data(cur_irq, rk808); - irq_set_chip_and_handler(cur_irq, &rk808_irq_chip, - handle_edge_irq); - irq_set_nested_thread(cur_irq, 1); - - /* ARM needs us to explicitly flag the IRQ as valid - * and will set them noprobe when we do so. */ -#ifdef CONFIG_ARM - set_irq_flags(cur_irq, IRQF_VALID); -#else - irq_set_noprobe(cur_irq); -#endif + rk808->irq_gpio = pdata->irq_gpio; + if (rk808->irq_gpio && !rk808->chip_irq) { + rk808->chip_irq = gpio_to_irq(rk808->irq_gpio); + + if (rk808->irq_gpio) { + ret = gpio_request(rk808->irq_gpio, "rk808_pmic_irq"); + if (ret < 0) { + dev_err(rk808->dev, + "Failed to request gpio %d with ret:" + "%d\n", rk808->irq_gpio, ret); + return IRQ_NONE; + } + gpio_direction_input(rk808->irq_gpio); + val = gpio_get_value(rk808->irq_gpio); + gpio_free(rk808->irq_gpio); + pr_info("%s: rk808_pmic_irq=%x\n", __func__, val); + } + } + + domain = irq_domain_add_linear(NULL, RK808_NUM_IRQ, + &rk808_irq_domain_ops, rk808); + if (!domain) { + dev_err(rk808->dev, "could not create irq domain\n"); + return -ENODEV; } + rk808->irq_domain = domain; - ret = request_threaded_irq(irq, NULL, rk808_irq, flags, "rk808", rk808); + ret = request_threaded_irq(rk808->chip_irq, NULL, rk808_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rk808", rk808); - irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(rk808->chip_irq, IRQ_TYPE_LEVEL_LOW); if (ret != 0) dev_err(rk808->dev, "Failed to request IRQ: %d\n", ret); diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 80b153126e8a..f8c17039ea9f 100755 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -16,15 +16,22 @@ #include #include #include -#include #include -#include #include +#include #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif #include - +#include +#include +#include +#include +#include +#include +#include +#include +#include #if 0 #define DBG(x...) printk(KERN_INFO x) @@ -484,6 +491,7 @@ static int rk808_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode) struct rk808 *rk808 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - RK808_DCDC1; u16 mask = 0x80; + switch(mode) { case REGULATOR_MODE_FAST: @@ -633,8 +641,7 @@ static struct regulator_desc regulators[] = { int rk808_i2c_read(struct rk808 *rk808, char reg, int count,u8 *dest) { struct i2c_client *i2c = rk808->i2c; - - int ret; + int ret; struct i2c_adapter *adap; struct i2c_msg msgs[2]; @@ -648,19 +655,19 @@ static struct regulator_desc regulators[] = { msgs[0].addr = i2c->addr; msgs[0].buf = ® - msgs[0].flags = 0; + msgs[0].flags = i2c->flags; msgs[0].len = 1; - msgs[0].scl_rate = 200*1000; + msgs[0].scl_rate = 100*1000; - msgs[1].buf = dest; + msgs[1].buf = (u8 *)dest; msgs[1].addr = i2c->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = count; - msgs[1].scl_rate = 200*1000; + msgs[1].flags = i2c->flags |I2C_M_RD; + msgs[1].len = 1; + msgs[1].scl_rate = 100*1000; ret = i2c_transfer(adap, msgs, 2); - DBG("***run in %s %x % x\n",__FUNCTION__,i2c->addr,msgs[0].buf); + DBG("***run in %s %x % x\n",__FUNCTION__,i2c->addr,*(msgs[1].buf)); return 0; } @@ -685,7 +692,7 @@ int rk808_i2c_write(struct rk808 *rk808, char reg, int count, const u8 src) msg.buf = &tx_buf[0]; msg.len = 1 +1; msg.flags = i2c->flags; - msg.scl_rate = 200*1000; + msg.scl_rate = 100*1000; ret = i2c_transfer(adap, &msg, 1); return ret; @@ -766,7 +773,7 @@ out: return err; } EXPORT_SYMBOL_GPL(rk808_clear_bits); - +#if 0 int rk808_bulk_read(struct rk808 *rk808, u8 reg, int count, u8 *buf) { @@ -828,7 +835,7 @@ int rk808_bulk_write(struct rk808 *rk808, u8 reg, } EXPORT_SYMBOL_GPL(rk808_bulk_write); - +#endif #if 1 static ssize_t rk808_test_store(struct kobject *kobj, struct kobj_attribute *attr, @@ -911,47 +918,166 @@ static struct rk808_attribute rk808_attrs[] = { }; #endif -static int __devinit setup_regulators(struct rk808 *rk808, struct rk808_platform_data *pdata) -{ - int i, err; +extern void rk28_send_wakeup_key(void); +static irqreturn_t rk808_vbat_lo_irq(int irq, void *data) +{ + printk("rk808 vbat low %s:irq=%d\n",__func__,irq); + rk808_set_bits(g_rk808,0x4c,(0x1 << 1),(0x1 <<1)); +// rk28_send_wakeup_key(); + return IRQ_HANDLED; +} - rk808->num_regulators = pdata->num_regulators; - rk808->rdev = kcalloc(pdata->num_regulators, - sizeof(struct regulator_dev *), GFP_KERNEL); - if (!rk808->rdev) { - return -ENOMEM; +#ifdef CONFIG_OF +static struct of_device_id rk808_of_match[] = { + { .compatible = "rockchip,rk808"}, + { }, +}; +MODULE_DEVICE_TABLE(of, rk808_of_match); +#endif + +#ifdef CONFIG_OF +static struct of_regulator_match rk808_reg_matches[] = { + { .name = "rk_dcdc1", .driver_data = (void *)0 }, + { .name = "rk_dcdc2", .driver_data = (void *)1 }, + { .name = "rk_dcdc3", .driver_data = (void *)2 }, + { .name = "rk_dcdc4", .driver_data = (void *)3 }, + { .name = "rk_ldo1", .driver_data = (void *)4 }, + { .name = "rk_ldo2", .driver_data = (void *)5 }, + { .name = "rk_ldo3", .driver_data = (void *)6 }, + { .name = "rk_ldo4", .driver_data = (void *)7 }, + { .name = "rk_ldo5", .driver_data = (void *)8 }, + { .name = "rk_ldo6", .driver_data = (void *)9 }, + { .name = "rk_ldo7", .driver_data = (void *)10 }, + { .name = "rk_ldo8", .driver_data = (void *)11 }, +}; + +static struct rk808_board *rk808_parse_dt(struct rk808 *rk808) +{ + struct rk808_board *pdata; + struct device_node *regs,*rk808_pmic_np; + int i, count; + + rk808_pmic_np = of_node_get(rk808->dev->of_node); + if (!rk808_pmic_np) { + printk("could not find pmic sub-node\n"); + return NULL; } - /* Instantiate the regulators */ - for (i = 0; i < pdata->num_regulators; i++) { - int id = pdata->regulators[i].id; - rk808->rdev[i] = regulator_register(®ulators[id], - rk808->dev, pdata->regulators[i].initdata, rk808); -/* - if (IS_ERR(rk808->rdev[i])) { - err = PTR_ERR(rk808->rdev[i]); - dev_err(rk808->dev, "regulator init failed: %d\n", - err); - goto error; - }*/ + + regs = of_find_node_by_name(rk808_pmic_np, "regulators"); + if (!regs) + return NULL; + + count = of_regulator_match(rk808->dev, regs, rk808_reg_matches, + rk808_NUM_REGULATORS); + of_node_put(regs); + if ((count < 0) || (count > rk808_NUM_REGULATORS)) + return NULL; + + pdata = devm_kzalloc(rk808->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + for (i = 0; i < count; i++) { + if (!rk808_reg_matches[i].init_data || !rk808_reg_matches[i].of_node) + continue; + + pdata->rk808_init_data[i] = rk808_reg_matches[i].init_data; + pdata->of_node[i] = rk808_reg_matches[i].of_node; } + pdata->irq = rk808->chip_irq; + pdata->irq_base = -1; + + pdata->irq_gpio = of_get_named_gpio(rk808_pmic_np,"gpios",0); + if (!gpio_is_valid(pdata->irq_gpio)) { + printk("invalid gpio: %d\n", pdata->irq_gpio); + return NULL; + } - return 0; -error: - while (--i >= 0) - regulator_unregister(rk808->rdev[i]); - kfree(rk808->rdev); - rk808->rdev = NULL; - return err; + if (of_get_property(rk808_pmic_np, "rockchip,pmic-dcdc-sleep-voltage", NULL)) + pdata->pmic_sleep = true; + + if (of_get_property(rk808_pmic_np, "rockchip,pmic-ldo-sleep-voltage", NULL)) + pdata->pmic_sleep = true; + if (pdata->pmic_sleep){ + pdata->pmic_sleep_gpio = of_get_named_gpio(rk808_pmic_np,"gpios",1); + if (!gpio_is_valid(pdata->pmic_sleep_gpio)) { + printk("invalid gpio: %d\n", pdata->pmic_sleep_gpio); + } + } + if (of_property_read_u32_array(rk808_pmic_np, + "rockchip,pmic-dcdc-sleep-voltage", + pdata->dcdc_slp_voltage, 4)) { + printk("dcdc sleep voltages not specified\n"); + } + + if (of_property_read_u32_array(rk808_pmic_np, + "rockchip,pmic-ldo-sleep-voltage", + pdata->ldo_slp_voltage, 8)) { + printk("ldo sleep voltages not specified\n"); + } + + return pdata; +} +static int rk808_dcdc_sleep_voltage_get_val(int min_uV,int buck) +{ + u16 vsel =0; + + if (buck == 0 || buck == 1){ + if (min_uV < 700000) + vsel = 0; + else if (min_uV <= 1500000) + vsel = ((min_uV - 700000) / 12500) ; + else + return -EINVAL; + } + else if (buck ==3){ + if (min_uV < 1800000) + vsel = 0; + else if (min_uV <= 3300000) + vsel = ((min_uV - 1800000) / 100000) ; + else + return -EINVAL; + } + return vsel; } +static int rk808_ldo_sleep_voltage_get_val(int min_uV,int ldo) +{ + const int *vol_map; + int min_vol = min_uV / 1000; + int num =0; + u16 val; + + if (ldo ==2){ + vol_map = ldo3_voltage_map; + num = 15; + } + else if (ldo == 5 || ldo ==6){ + vol_map = ldo6_voltage_map; + num = 17; + } + else { + vol_map = ldo_voltage_map; + num = 16; + } + + if (min_vol < vol_map[0] || + min_vol > vol_map[num]) + return -EINVAL; -extern void rk28_send_wakeup_key(void); -static irqreturn_t rk808_vbat_lo_irq(int irq, void *data) + for (val = 0; val <= num; val++){ + if (vol_map[val] >= min_vol) + break; + } + + return val; +} +#else +static struct rk808_board *rk808_parse_dt(struct i2c_client *i2c) { - printk("rk808 vbat low %s:irq=%d\n",__func__,irq); - rk808_set_bits(g_rk808,0x4c,(0x1 << 1),(0x1 <<1)); - rk28_send_wakeup_key(); - return IRQ_HANDLED; + return NULL; } +#endif + int rk808_device_shutdown(void) { @@ -998,21 +1124,48 @@ static int rk808_resume(struct i2c_client *i2c) } #endif +static bool is_volatile_reg(struct device *dev, unsigned int reg) +{ + if ((reg >= RK808_DCDC_EN_REG) && (reg <= RK808_LDO8_SLP_VSEL_REG)) { + return true; + } + return true; +} + +static const struct regmap_config rk808_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = is_volatile_reg, + .max_register = rk808_NUM_REGULATORS - 1, + .cache_type = REGCACHE_RBTREE, +}; #ifdef CONFIG_HAS_EARLYSUSPEND __weak void rk808_early_suspend(struct early_suspend *h) {} __weak void rk808_late_resume(struct early_suspend *h) {} #endif - -static int __devinit rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static int rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct rk808 *rk808; - struct rk808_platform_data *pdata = i2c->dev.platform_data; - int ret; + struct rk808_board *pdev; + const struct of_device_id *match; + struct regulator_config config = { }; + struct regulator_dev *rk808_rdev; + struct regulator_init_data *reg_data; + const char *rail_name = NULL; + int ret,vlow_irq,i=0; printk("%s,line=%d\n", __func__,__LINE__); + if (i2c->dev.of_node) { + match = of_match_device(rk808_of_match, &i2c->dev); + if (!match) { + dev_err(&i2c->dev,"Failed to find matching dt id\n"); + return -EINVAL; + } + } + rk808 = kzalloc(sizeof(struct rk808), GFP_KERNEL); if (rk808 == NULL) { ret = -ENOMEM; @@ -1021,49 +1174,119 @@ static int __devinit rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_de rk808->i2c = i2c; rk808->dev = &i2c->dev; i2c_set_clientdata(i2c, rk808); - rk808->read = rk808_i2c_read; - rk808->write = rk808_i2c_write; - mutex_init(&rk808->io_lock); +// rk808->read = rk808_i2c_read; +// rk808->write = rk808_i2c_write; - ret = mfd_add_devices(rk808->dev, -1, - rk808s, ARRAY_SIZE(rk808s), - NULL, 0); - if (ret < 0) - goto err; + rk808->regmap = devm_regmap_init_i2c(i2c, &rk808_regmap_config); + if (IS_ERR(rk808->regmap)) { + printk("regmap initialization failed\n"); + return ret; + } + + mutex_init(&rk808->io_lock); - ret = rk808_reg_read(rk808,0x2f); if ((ret < 0) || (ret == 0xff)){ - printk("The device is not rk808\n"); + printk("The device is not rk808 %d\n",ret); return 0; } + rk808_set_bits(rk808,0x21,(1<<4),(1 <<4)); + rk808_set_bits(rk808,0x21,(7<<0),(7 <<0)); + if (ret < 0) + goto err; - if (pdata) { - ret = setup_regulators(rk808, pdata); - if (ret < 0) - goto err; - } else - dev_warn(rk808->dev, "No platform init data supplied\n"); + if (rk808->dev->of_node) + pdev = rk808_parse_dt(rk808); + + /******************************set sleep vol & dcdc mode******************/ + #ifdef CONFIG_OF + rk808->pmic_sleep_gpio = pdev->pmic_sleep_gpio; + if (rk808->pmic_sleep_gpio) { + ret = gpio_request(rk808->pmic_sleep_gpio, "rk808_pmic_sleep"); + if (ret < 0) { + dev_err(rk808->dev,"Failed to request gpio %d with ret:""%d\n", rk808->pmic_sleep_gpio, ret); + return IRQ_NONE; + } + gpio_direction_input(rk808->pmic_sleep_gpio); + ret = gpio_get_value(rk808->pmic_sleep_gpio); + gpio_free(rk808->pmic_sleep_gpio); + pr_info("%s: rk808_pmic_sleep=%x\n", __func__, ret); + } + for (i = 0;i <4 ; i ++){ + rk808->dcdc_slp_voltage[i] = pdev->dcdc_slp_voltage[i]; + if (rk808->dcdc_slp_voltage[i]){ + if (i ==2) + continue; + ret = rk808_set_bits(rk808, (rk808_BUCK_SET_VOL_REG(i) + 0x01), BUCK_VOL_MASK, rk808_dcdc_sleep_voltage_get_val(rk808->dcdc_slp_voltage[i],i)); + } + } + for (i = 0;i <8 ; i ++){ + rk808->ldo_slp_voltage[i] = pdev->ldo_slp_voltage[i]; + if (rk808->ldo_slp_voltage[i] ==0) + ret = rk808_set_bits(rk808, RK808_LDO_EN_REG, 1 << i, 0); + ret = rk808_set_bits(rk808, (rk808_LDO_SET_VOL_REG(i) + 0x01), LDO_VOL_MASK, rk808_ldo_sleep_voltage_get_val(rk808->ldo_slp_voltage[i],i)); + } + #endif + /**********************************************************/ + + if (pdev) { + rk808->num_regulators = rk808_NUM_REGULATORS; + rk808->rdev = kcalloc(rk808_NUM_REGULATORS,sizeof(struct regulator_dev *), GFP_KERNEL); + if (!rk808->rdev) { + return -ENOMEM; + } + /* Instantiate the regulators */ + for (i = 0; i < rk808_NUM_REGULATORS; i++) { + reg_data = pdev->rk808_init_data[i]; + if (!reg_data) + continue; + config.dev = rk808->dev; + config.driver_data = rk808; + config.regmap = rk808->regmap; + if (rk808->dev->of_node) + config.of_node = pdev->of_node[i]; + if (reg_data && reg_data->constraints.name) + rail_name = reg_data->constraints.name; + else + rail_name = regulators[i].name; + reg_data->supply_regulator = rail_name; + + config.init_data =reg_data; - pdata->pre_init(rk808); + rk808_rdev = regulator_register(®ulators[i],&config); + if (IS_ERR(rk808_rdev)) { + printk("failed to register %d regulator\n",i); + goto err; + } + rk808->rdev[i] = rk808_rdev; + } + } - ret = rk808_irq_init(rk808, pdata->irq, pdata); +// rk808->wakeup = pdev->wakeup; + rk808->irq_gpio = pdev->irq_gpio; + ret = rk808_irq_init(rk808, rk808->irq_gpio, pdev); if (ret < 0) goto err; + + ret = mfd_add_devices(rk808->dev, -1, + rk808s, ARRAY_SIZE(rk808s), + NULL, 0,NULL); + /********************vbat low int**************/ - ret = request_threaded_irq(rk808->irq_base + RK808_IRQ_VB_LO, NULL, rk808_vbat_lo_irq, + vlow_irq = irq_create_mapping(rk808->irq_domain, RK808_IRQ_VB_LO); + ret = request_threaded_irq(vlow_irq, NULL, rk808_vbat_lo_irq, IRQF_TRIGGER_RISING, "rk808_vbatlow", rk808); if (ret != 0) { dev_err(rk808->dev, "Failed to request periodic IRQ %d: %d\n", - rk808->irq_base + RK808_IRQ_VB_LO, ret); + vlow_irq+ RK808_IRQ_VB_LO, ret); } /*********************************************/ + g_rk808 = rk808; - pdata->set_init(rk808); #ifdef CONFIG_HAS_EARLYSUSPEND rk808->rk808_suspend.suspend = rk808_early_suspend, @@ -1073,7 +1296,6 @@ static int __devinit rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_de #endif #if 1 - int i =0; rk808_kobj = kobject_create_and_add("rk808", NULL); if (!rk808_kobj) return -ENOMEM; @@ -1093,7 +1315,7 @@ err: } -static int __devexit rk808_i2c_remove(struct i2c_client *i2c) +static int rk808_i2c_remove(struct i2c_client *i2c) { struct rk808 *rk808 = i2c_get_clientdata(i2c); int i; @@ -1119,9 +1341,10 @@ static struct i2c_driver rk808_i2c_driver = { .driver = { .name = "rk808", .owner = THIS_MODULE, + .of_match_table =of_match_ptr(rk808_of_match), }, .probe = rk808_i2c_probe, - .remove = __devexit_p(rk808_i2c_remove), + .remove = rk808_i2c_remove, .id_table = rk808_i2c_id, #ifdef CONFIG_PM .suspend = rk808_suspend, diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8bb26446037e..3d074b03a8fb 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -250,6 +250,18 @@ config REGULATOR_MAX77686 via I2C bus. The provided regulator is suitable for Exynos-4 chips to control VARM and VINT voltages. +config REGULATOR_ACT8846 + tristate "Active Semi ACT8846 PMIC regulators" + depends on I2C + help + Support the voltage and current regulators of the ACT8846 series of PMIC devices. + +config ACT8846_SUPPORT_RESET + tristate "ACT8846 PMIC SUPPORT RESET" + depends on REGULATOR_ACT8846=y + help + Support short press key to restart. + config REGULATOR_PCAP tristate "Motorola PCAP2 regulator driver" depends on EZX_PCAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 47a34ff88f98..dafe1c4cdc0e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o +obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/act8846.c b/drivers/regulator/act8846.c index 6b8aa666ea95..be07922ce36c 100755 --- a/drivers/regulator/act8846.c +++ b/drivers/regulator/act8846.c @@ -17,14 +17,22 @@ #include #include #include -#include #include -#include #include +#include #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if 0 #define DBG(x...) printk(KERN_INFO x) @@ -44,9 +52,22 @@ struct act8846 { struct i2c_client *i2c; int num_regulators; struct regulator_dev **rdev; - struct early_suspend act8846_suspend; +// struct early_suspend act8846_suspend; + int irq_base; + int chip_irq; + int pmic_sleep_gpio; /* */ + unsigned int dcdc_slp_voltage[3]; /* buckx_voltage in uV */ + bool pmic_sleep; + struct regmap *regmap; +}; + +struct act8846_regulator { + struct device *dev; + struct regulator_desc *desc; + struct regulator_dev *rdev; }; + struct act8846 *g_act8846; static u8 act8846_reg_read(struct act8846 *act8846, u8 reg); @@ -142,7 +163,7 @@ const static int buck_voltage_map[] = { 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, + 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, }; @@ -154,7 +175,7 @@ const static int ldo_voltage_map[] = { 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, + 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, }; @@ -184,7 +205,7 @@ static int act8846_ldo_enable(struct regulator_dev *dev) struct act8846 *act8846 = rdev_get_drvdata(dev); int ldo= rdev_get_id(dev) - ACT8846_LDO1; u16 mask=0x80; - + return act8846_set_bits(act8846, act8846_LDO_CONTR_REG(ldo), mask, 0x80); } @@ -217,6 +238,7 @@ static int act8846_ldo_set_voltage(struct regulator_dev *dev, 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; @@ -307,6 +329,7 @@ static int act8846_dcdc_enable(struct regulator_dev *dev) struct act8846 *act8846 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - ACT8846_DCDC1; u16 mask=0x80; + return act8846_set_bits(act8846, act8846_BUCK_CONTR_REG(buck), mask, 0x80); } @@ -329,9 +352,7 @@ static int act8846_dcdc_get_voltage(struct regulator_dev *dev) reg = act8846_reg_read(act8846,act8846_BUCK_SET_VOL_REG(buck)); #endif reg &= BUCK_VOL_MASK; - DBG("%d\n", reg); val = 1000 * buck_voltage_map[reg]; - DBG("%d\n", val); return val; } static int act8846_dcdc_set_voltage(struct regulator_dev *dev, @@ -344,7 +365,6 @@ static int act8846_dcdc_set_voltage(struct regulator_dev *dev, u16 val; int ret = 0; - 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; @@ -375,7 +395,6 @@ static int act8846_dcdc_set_sleep_voltage(struct regulator_dev *dev, u16 val; int ret = 0; - 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; @@ -417,6 +436,7 @@ static int act8846_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode) struct act8846 *act8846 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - ACT8846_DCDC1; u16 mask = 0x80; + switch(mode) { case REGULATOR_MODE_STANDBY: @@ -462,7 +482,7 @@ static struct regulator_ops act8846_dcdc_ops = { static struct regulator_desc regulators[] = { { - .name = "DCDC1", + .name = "ACT_DCDC1", .id = 0, .ops = &act8846_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), @@ -470,7 +490,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "DCDC2", + .name = "ACT_DCDC2", .id = 1, .ops = &act8846_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), @@ -478,7 +498,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "DCDC3", + .name = "ACT_DCDC3", .id = 2, .ops = &act8846_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), @@ -486,7 +506,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "DCDC4", + .name = "ACT_DCDC4", .id = 3, .ops = &act8846_dcdc_ops, .n_voltages = ARRAY_SIZE(buck_voltage_map), @@ -495,7 +515,7 @@ static struct regulator_desc regulators[] = { }, { - .name = "LDO1", + .name = "ACT_LDO1", .id =4, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -503,7 +523,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO2", + .name = "ACT_LDO2", .id = 5, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -511,7 +531,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO3", + .name = "ACT_LDO3", .id = 6, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -519,7 +539,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO4", + .name = "ACT_LDO4", .id = 7, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -528,7 +548,7 @@ static struct regulator_desc regulators[] = { }, { - .name = "LDO5", + .name = "ACT_LDO5", .id =8, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -536,7 +556,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO6", + .name = "ACT_LDO6", .id = 9, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -544,7 +564,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO7", + .name = "ACT_LDO7", .id = 10, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -552,7 +572,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO8", + .name = "ACT_LDO8", .id = 11, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -560,7 +580,7 @@ static struct regulator_desc regulators[] = { .owner = THIS_MODULE, }, { - .name = "LDO9", + .name = "ACT_LDO9", .id = 12, .ops = &act8846_ldo_ops, .n_voltages = ARRAY_SIZE(ldo_voltage_map), @@ -666,38 +686,127 @@ static int act8846_set_bits(struct act8846 *act8846, u8 reg, u16 mask, u16 val) return 0;//ret; } -static int __devinit setup_regulators(struct act8846 *act8846, struct act8846_platform_data *pdata) -{ - int i, err; - act8846->num_regulators = pdata->num_regulators; - act8846->rdev = kcalloc(pdata->num_regulators, - sizeof(struct regulator_dev *), GFP_KERNEL); - if (!act8846->rdev) { - return -ENOMEM; +#ifdef CONFIG_OF +static struct of_device_id act8846_of_match[] = { + { .compatible = "act,act8846"}, + { }, +}; +MODULE_DEVICE_TABLE(of, act8846_of_match); +#endif +#ifdef CONFIG_OF +static struct of_regulator_match act8846_reg_matches[] = { + { .name = "act_dcdc1" ,.driver_data = (void *)0}, + { .name = "act_dcdc2" ,.driver_data = (void *)1}, + { .name = "act_dcdc3", .driver_data = (void *)2 }, + { .name = "act_dcdc4", .driver_data = (void *)3 }, + { .name = "act_ldo1", .driver_data = (void *)4 }, + { .name = "act_ldo2", .driver_data = (void *)5 }, + { .name = "act_ldo3", .driver_data = (void *)6 }, + { .name = "act_ldo4", .driver_data = (void *)7 }, + { .name = "act_ldo5", .driver_data = (void *)8 }, + { .name = "act_ldo6", .driver_data = (void *)9 }, + { .name = "act_ldo7", .driver_data = (void *)10 }, + { .name = "act_ldo8", .driver_data = (void *)11 }, +}; + +static struct act8846_board *act8846_parse_dt(struct act8846 *act8846) +{ +// struct act8846 *act8846 = i2c->dev.parent; + struct act8846_board *pdata; + struct device_node *regs; + struct device_node *act8846_pmic_np; + int i, count,sleep_voltage_nr =1; + int gpio; + printk("%s,line=%d\n", __func__,__LINE__); + + act8846_pmic_np = of_node_get(act8846->dev->of_node); + if (!act8846_pmic_np) { + printk("could not find pmic sub-node\n"); + return NULL; } - /* Instantiate the regulators */ - for (i = 0; i < pdata->num_regulators; i++) { - int id = pdata->regulators[i].id; - act8846->rdev[i] = regulator_register(®ulators[id], - act8846->dev, pdata->regulators[i].initdata, act8846); -/* - if (IS_ERR(act8846->rdev[i])) { - err = PTR_ERR(act8846->rdev[i]); - dev_err(act8846->dev, "regulator init failed: %d\n", - err); - goto error; - }*/ + + regs = of_find_node_by_name(act8846_pmic_np, "regulators"); + if (!regs) + return NULL; + + count = of_regulator_match(act8846->dev, regs, act8846_reg_matches,act8846_NUM_REGULATORS); + of_node_put(regs); + + if ((count < 0) || (count > act8846_NUM_REGULATORS)) + return NULL; + + pdata = devm_kzalloc(act8846->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + for (i = 0; i < count; i++) { + if (!act8846_reg_matches[i].init_data || !act8846_reg_matches[i].of_node) + continue; + pdata->act8846_init_data[i] = act8846_reg_matches[i].init_data; + pdata->of_node[i] = act8846_reg_matches[i].of_node; } + pdata->irq = act8846->chip_irq; + pdata->irq_base = -1; - return 0; -error: - while (--i >= 0) - regulator_unregister(act8846->rdev[i]); - kfree(act8846->rdev); - act8846->rdev = NULL; - return err; + if (of_get_property(act8846_pmic_np, "act,pmic-dcdc-sleep-voltage", NULL)) + pdata->pmic_sleep = true; + + if (of_get_property(act8846_pmic_np, "act,pmic-ldo-sleep-voltage", NULL)) + pdata->pmic_sleep = true; + + gpio = of_get_named_gpio(act8846_pmic_np,"gpios", 0); + if (!gpio_is_valid(gpio)) + printk("invalid gpio: %d\n",gpio); + pdata->pmic_sleep_gpio = gpio; + + if (of_property_read_u32_array(act8846_pmic_np, + "act,pmic-dcdc-sleep-voltage", + pdata->dcdc_slp_voltage, sleep_voltage_nr)) { + printk("dcdc sleep voltages not specified\n"); + } + + return pdata; } +static int act8846_dcdc_sleep_voltage_get_val(int min_uV,int buck) +{ + int min_vol = min_uV / 1000, max_vol = min_uV / 1000; + const int *vol_map = buck_voltage_map; + u16 val; + + 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) + printk("WARNING:this voltage is not support!voltage set is %d mv\n",vol_map[val]); + return val; +} +static int act8846_dts_dcdc_set_mode(unsigned int mode,int buck) +{ + struct act8846 *act8846 = g_act8846; + u16 mask = 0x80; + switch(mode) + { + case REGULATOR_MODE_STANDBY: + return act8846_set_bits(act8846, act8846_BUCK_CONTR_REG(buck), mask, 0); + case REGULATOR_MODE_NORMAL: + return act8846_set_bits(act8846, act8846_BUCK_CONTR_REG(buck), mask, mask); + default: + printk("error:pmu_act8846 only powersave and pwm mode\n"); + return -EINVAL; + } +} +#else +static struct act8846_board *act8846_parse_dt(struct i2c_client *i2c) +{ + return NULL; +} +#endif int act8846_device_shutdown(void) @@ -751,11 +860,43 @@ __weak void act8846_early_suspend(struct early_suspend *h) {} __weak void act8846_late_resume(struct early_suspend *h) {} #endif -static int __devinit act8846_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static bool is_volatile_reg(struct device *dev, unsigned int reg) +{ + + if ((reg >= act8846_BUCK1_SET_VOL_BASE) && (reg <= act8846_LDO8_CONTR_BASE)) { + return true; + } + return true; +} + +static const struct regmap_config act8846_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = is_volatile_reg, + .max_register = act8846_NUM_REGULATORS - 1, + .cache_type = REGCACHE_RBTREE, +}; +static int act8846_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct act8846 *act8846; - struct act8846_platform_data *pdata = i2c->dev.platform_data; - int ret; + struct act8846_board *pdev ; + const struct of_device_id *match; + struct regulator_config config = { }; + struct regulator_dev *act_rdev; + struct regulator_init_data *reg_data; + const char *rail_name = NULL; + int ret,i=0; + + printk("%s,line=%d\n", __func__,__LINE__); + + if (i2c->dev.of_node) { + match = of_match_device(act8846_of_match, &i2c->dev); + if (!match) { + printk("Failed to find matching dt id\n"); + return -EINVAL; + } + } + act8846 = kzalloc(sizeof(struct act8846), GFP_KERNEL); if (act8846 == NULL) { ret = -ENOMEM; @@ -764,11 +905,20 @@ static int __devinit act8846_i2c_probe(struct i2c_client *i2c, const struct i2c_ act8846->i2c = i2c; act8846->dev = &i2c->dev; i2c_set_clientdata(i2c, act8846); + g_act8846 = act8846; + + act8846->regmap = devm_regmap_init_i2c(i2c, &act8846_regmap_config); + if (IS_ERR(act8846->regmap)) { + ret = PTR_ERR(act8846->regmap); + printk("regmap initialization failed: %d\n", ret); + return ret; + } + mutex_init(&act8846->io_lock); ret = act8846_reg_read(act8846,0x22); if ((ret < 0) || (ret == 0xff)){ - printk("The device is not act8846 \n"); + printk("The device is not act8846 %x \n",ret); return 0; } @@ -777,24 +927,80 @@ static int __devinit act8846_i2c_probe(struct i2c_client *i2c, const struct i2c_ printk("act8846 set 0xf4 error!\n"); goto err; } - - if (pdata) { - ret = setup_regulators(act8846, pdata); - if (ret < 0) - goto err; - } else - dev_warn(act8846->dev, "No platform init data supplied\n"); - - g_act8846 = act8846; - pdata->set_init(act8846); + if (act8846->dev->of_node) + pdev = act8846_parse_dt(act8846); + + /******************************set sleep vol & dcdc mode******************/ + #ifdef CONFIG_OF + act8846->pmic_sleep_gpio = pdev->pmic_sleep_gpio; + if (act8846->pmic_sleep_gpio) { + ret = gpio_request(act8846->pmic_sleep_gpio, "act8846_pmic_sleep"); + if (ret < 0) { + dev_err(act8846->dev,"Failed to request gpio %d with ret:""%d\n", act8846->pmic_sleep_gpio, ret); + return IRQ_NONE; + } + gpio_direction_input(act8846->pmic_sleep_gpio); + ret = gpio_get_value(act8846->pmic_sleep_gpio); + gpio_free(act8846->pmic_sleep_gpio); + printk("%s: act8846_pmic_sleep=%x\n", __func__, ret); + } + for (i = 0;i <4 ; i ++){ + act8846->dcdc_slp_voltage[i] = pdev->dcdc_slp_voltage[i]; + if (act8846->dcdc_slp_voltage[i]){ + if (i ==0) + continue; + + #ifdef CONFIG_ACT8846_SUPPORT_RESET + ret = act8846_set_bits(act8846, act8846_BUCK_SET_VOL_REG(i) ,BUCK_VOL_MASK, act8846_dcdc_sleep_voltage_get_val(act8846->dcdc_slp_voltage[i],i)); + #else + ret = act8846_set_bits(act8846, (act8846_BUCK_SET_VOL_REG(i) +0x01),BUCK_VOL_MASK, act8846_dcdc_sleep_voltage_get_val(act8846->dcdc_slp_voltage[i],i)); + #endif + } + } + #endif + + if (pdev) { + act8846->num_regulators = act8846_NUM_REGULATORS; + act8846->rdev = kcalloc(act8846_NUM_REGULATORS,sizeof(struct regulator_dev *), GFP_KERNEL); + if (!act8846->rdev) { + return -ENOMEM; + } + /* Instantiate the regulators */ + for (i = 0; i < act8846_NUM_REGULATORS; i++) { + reg_data = pdev->act8846_init_data[i]; + if (!reg_data) + continue; + config.dev = act8846->dev; + config.driver_data = act8846; + config.regmap = act8846->regmap; + if (act8846->dev->of_node) + config.of_node = pdev->of_node[i]; + + if (reg_data && reg_data->constraints.name) + rail_name = reg_data->constraints.name; + else + rail_name = regulators[i].name; + reg_data->supply_regulator = rail_name; + + config.init_data =reg_data; + + act_rdev = regulator_register(®ulators[i],&config); + if (IS_ERR(act_rdev)) { + printk("failed to register %d regulator\n",i); + goto err; + } + act8846->rdev[i] = act_rdev; + } + } + #ifdef CONFIG_HAS_EARLYSUSPEND act8846->act8846_suspend.suspend = act8846_early_suspend, act8846->act8846_suspend.resume = act8846_late_resume, act8846->act8846_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, register_early_suspend(&act8846->act8846_suspend); - #endif - + #endif + return 0; err: @@ -802,7 +1008,7 @@ err: } -static int __devexit act8846_i2c_remove(struct i2c_client *i2c) +static int act8846_i2c_remove(struct i2c_client *i2c) { struct act8846 *act8846 = i2c_get_clientdata(i2c); int i; @@ -828,9 +1034,10 @@ static struct i2c_driver act8846_i2c_driver = { .driver = { .name = "act8846", .owner = THIS_MODULE, + .of_match_table =of_match_ptr(act8846_of_match), }, .probe = act8846_i2c_probe, - .remove = __devexit_p(act8846_i2c_remove), + .remove = act8846_i2c_remove, .id_table = act8846_i2c_id, #ifdef CONFIG_PM .suspend = act8846_suspend, diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b9838130a7b0..33d86af2a60d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -414,6 +414,12 @@ config RTC_DRV_TPS65910 This driver can also be built as a module. If so, the module will be called rtc-tps65910. +config RK808_RTC + tristate "rk808 rtc for rk" + depends on MFD_RK808 + help + enable rk808 rtc for system + config RTC_DRV_TPS80031 tristate "TI TPS80031/TPS80032 RTC driver" depends on MFD_TPS80031 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c33f86f1a69b..d90aa263eec0 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -126,5 +126,6 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o +obj-$(CONFIG_RK808_RTC) += rtc-rk808.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index adaec3302db5..b79fed58a9c5 100755 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c @@ -23,6 +23,7 @@ #include #include #include +#include /* RTC Definitions */ @@ -76,7 +77,6 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); struct rk808 *rk808 = rk808_rtc->rk808; int ret; - int count = 0; unsigned char rtc_data[ALL_TIME_REGS + 1]; u8 rtc_ctl; @@ -514,12 +514,23 @@ static int rk808_rtc_freeze(struct device *dev) #define rk808_rtc_resume NULL #define rk808_rtc_freeze NULL #endif - +extern struct rk808 *g_rk808; struct platform_device *rk808_pdev; +struct rtc_time tm_def = { // 2012.1.1 12:00:00 Saturday + .tm_wday = 6, + .tm_year = 112, + .tm_mon = 0, + .tm_mday = 1, + .tm_hour = 12, + .tm_min = 0, + .tm_sec = 0, +}; + static int rk808_rtc_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); struct rk808_rtc *rk808_rtc; + struct rtc_time tm; int per_irq; int alm_irq; int ret = 0; @@ -527,26 +538,12 @@ static int rk808_rtc_probe(struct platform_device *pdev) printk("%s,line=%d\n", __func__,__LINE__); - - struct rtc_time tm; - struct rtc_time tm_def = { // 2012.1.1 12:00:00 Saturday - .tm_wday = 6, - .tm_year = 112, - .tm_mon = 0, - .tm_mday = 1, - .tm_hour = 12, - .tm_min = 0, - .tm_sec = 0, - }; - rk808_rtc = kzalloc(sizeof(*rk808_rtc), GFP_KERNEL); if (rk808_rtc == NULL) return -ENOMEM; platform_set_drvdata(pdev, rk808_rtc); rk808_rtc->rk808 = rk808; - per_irq = rk808->irq_base + RK808_IRQ_RTC_PERIOD; - alm_irq = rk808->irq_base + RK808_IRQ_RTC_ALARM; /* Take rtc out of reset */ /* @@ -611,9 +608,12 @@ static int rk808_rtc_probe(struct platform_device *pdev) ret = PTR_ERR(rk808_rtc->rtc); goto err; } + + per_irq = irq_create_mapping(rk808->irq_domain, RK808_IRQ_RTC_PERIOD); + alm_irq = irq_create_mapping(rk808->irq_domain, RK808_IRQ_RTC_ALARM); /*request rtc and alarm irq of rk808*/ - ret = request_threaded_irq(per_irq, NULL, rk808_per_irq, + ret = devm_request_threaded_irq(rk808->dev,per_irq, NULL, rk808_per_irq, IRQF_TRIGGER_RISING, "RTC period", rk808_rtc); if (ret != 0) { @@ -621,7 +621,7 @@ static int rk808_rtc_probe(struct platform_device *pdev) per_irq, ret); } - ret = request_threaded_irq(alm_irq, NULL, rk808_alm_irq, + ret = devm_request_threaded_irq(rk808->dev,alm_irq, NULL, rk808_alm_irq, IRQF_TRIGGER_RISING, "RTC alarm", rk808_rtc); if (ret != 0) { @@ -637,7 +637,7 @@ static int rk808_rtc_probe(struct platform_device *pdev) rk808_set_bits(rk808_rtc->rk808, RK808_INT_STS_MSK_REG1,(0x3 <<5),0); */ - enable_irq_wake(alm_irq); // so rk808 alarm irq can wake up system +// enable_irq_wake(alm_irq); // so rk808 alarm irq can wake up system rk808_pdev = pdev; printk("%s:ok\n",__func__); @@ -649,7 +649,7 @@ err: return ret; } -static int __devexit rk808_rtc_remove(struct platform_device *pdev) +static int rk808_rtc_remove(struct platform_device *pdev) { struct rk808_rtc *rk808_rtc = platform_get_drvdata(pdev); int per_irq = rk808_rtc->rk808->irq_base + RK808_IRQ_RTC_PERIOD; @@ -676,7 +676,7 @@ static const struct dev_pm_ops rk808_rtc_pm_ops = { static struct platform_driver rk808_rtc_driver = { .probe = rk808_rtc_probe, - .remove = __devexit_p(rk808_rtc_remove), + .remove = rk808_rtc_remove, .driver = { .name = "rk808-rtc", .pm = &rk808_rtc_pm_ops, diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index 7ede72c9e456..66bfbc240404 100755 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -15,8 +15,10 @@ #include #include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND #include - +#endif //#define RK808_START 30 #define RK808_DCDC1 0 //(0+RK808_START) @@ -105,6 +107,19 @@ #define rk808_NUM_REGULATORS 12 struct rk808; +struct rk808_board { + int irq; + int irq_base; + int irq_gpio; + int wakeup; + struct regulator_init_data *rk808_init_data[rk808_NUM_REGULATORS]; + struct device_node *of_node[rk808_NUM_REGULATORS]; + int pmic_sleep_gpio; /* */ + unsigned int dcdc_slp_voltage[3]; /* buckx_voltage in uV */ + bool pmic_sleep; + unsigned int ldo_slp_voltage[7]; +}; + struct rk808_regulator_subdev { int id; struct regulator_init_data *initdata; @@ -117,14 +132,22 @@ struct rk808 { int num_regulators; struct regulator_dev **rdev; struct wake_lock irq_wake; - struct early_suspend rk808_suspend; +// struct early_suspend rk808_suspend; struct mutex irq_lock; int irq_base; int irq_num; int chip_irq; + int irq_gpio; + int wakeup; u32 irq_mask; + struct regmap *regmap; + struct irq_domain *irq_domain; int (*read)(struct rk808 *rk808, u8 reg, int size, void *dest); int (*write)(struct rk808 *rk808, u8 reg, int size, void *src); + int pmic_sleep_gpio; /* */ + unsigned int dcdc_slp_voltage[3]; /* buckx_voltage in uV */ + bool pmic_sleep; + unsigned int ldo_slp_voltage[7]; }; struct rk808_platform_data { @@ -134,9 +157,10 @@ struct rk808_platform_data { struct rk808_regulator_subdev *regulators; int irq; int irq_base; + struct irq_domain *irq_domain; }; -int rk808_irq_init(struct rk808 *rk808, int irq,struct rk808_platform_data *pdata); +int rk808_irq_init(struct rk808 *rk808, int irq,struct rk808_board *pdata); int rk808_i2c_read(struct rk808 *rk808, char reg, int count,u8 *dest); //int rk808_i2c_read(struct i2c_client *i2c, char reg, int count,u16 *dest); // int rk808_i2c_read(struct rk808 *rk808 , u8 reg, int bytes,void *dest); diff --git a/include/linux/regulator/act8846.h b/include/linux/regulator/act8846.h index 9914372b3297..24f2ae969e0c 100755 --- a/include/linux/regulator/act8846.h +++ b/include/linux/regulator/act8846.h @@ -24,20 +24,39 @@ #define ACT8846_LDO1 4 //(4+ACT8846_START) -#define act8846_NUM_REGULATORS 13 +#define act8846_NUM_REGULATORS 12 struct act8846; int act8846_device_shutdown(void); +struct act8846_board { + int irq; + int irq_base; + struct regulator_init_data *act8846_init_data[act8846_NUM_REGULATORS]; + struct device_node *of_node[act8846_NUM_REGULATORS]; + int pmic_sleep_gpio; /* */ + unsigned int dcdc_slp_voltage[3]; /* buckx_voltage in uV */ + unsigned int dcdc_mode[3]; /* buckx_voltage in uV */ + bool pmic_sleep; + unsigned int ldo_slp_voltage[7]; +}; + struct act8846_regulator_subdev { int id; struct regulator_init_data *initdata; + struct device_node *reg_node; }; struct act8846_platform_data { + int ono; int num_regulators; int (*set_init)(struct act8846 *act8846); struct act8846_regulator_subdev *regulators; + + int pmic_sleep_gpio; /* */ + unsigned int dcdc_slp_voltage[3]; /* buckx_voltage in uV */ + bool pmic_sleep; + unsigned int ldo_slp_voltage[7]; }; #endif -- 2.34.1