rk312x:rt5025:support pmic rt5025

This commit is contained in:
张晴 2014-08-22 10:01:21 +08:00
parent 75bdc645ca
commit 476cbef830
35 changed files with 5152 additions and 2994 deletions

View File

@ -0,0 +1,74 @@
Richtek RT5025 Multi-functional device
The RT5025 are Integrated Power Management Chips.
These chips are connected to an i2c bus.
Required properties:
- compatible : Must be "rt,rt5025";
- interrupts : This i2c device has an IRQ line connected to the main SoC
- interrupt-parent : The parent interrupt controller.
Optional node:
- Child nodes contain in the RT5025. The twl family is made of several variants
that support a different number of features.
Example:
rt5025@35 {
compatible = "rt,rt5025";
reg = <0x35>;
interrupt-parent = <&msmgpio>;
interrupts = <73 0>;
rt5025_dcdc1: regulator_0 {
compatible = "rt,rt5025-dcdc1";
cell-index = <0>;
regulator-name = "rt5025-dcdc1";
regulator-min-microvolt = < 700000>;
regulator-max-microvolt = <2275000>;
rt,ramp_sel = <0x00>;
rt,allow_mode_mask;
qcom,comsumer-supplies = "rt5025-dcdc1", "";
};
rt5025-charger {
compatible = "rt,rt5025-charger";
rt,te_en;
//rt,screenon_adjust;
rt,iprec = <0x00>;
rt,ieoc = <0x00>;
rt,vprec = <0x05>;
rt,vdpm = <0x02>;
rt,chg_volt = <4200>;
rt,acchg_icc = <2000>;
rt,usbtachg_icc = <2000>;
rt,usbchg_icc = <500>;
rt,screenon_icc = <500>;
rt,temp = <0 150 500 600>;
rt,temp_scalar = <0x30 0x2b 0x28 0x22 0x15 0x10 0x10 0x0d>;
};
rt5025_gpiop: rt5025-gpio {
compatible = "rt,rt5025-gpio";
gpio-controller;
#gpio-cells = <2>;
rt,ngpio = <3>;
};
rt5025-irq {
compatible = "rt,rt5025-irq";
rt,irq-gpio = <&msmgpio 73 0x00>;
};
rt5025-misc {
compatible = "rt,rt5025-misc";
rt,system_lv = <0x02>;
rt,shdn_lpress = <0x01>;
rt,start_lpress = <0x00>;
rt,syslv_enshutdown;
};
rt5025-debug {
compatible = "rt,rt5025-debug";
};

View File

@ -0,0 +1,14 @@
Richtek RT5025 battery/fuelgauge function
The RT5025 battery is responsible to report the battery voltage/current
, capacity, etc.
Required properties:
- compatible : Must be "rt,rt5025-battery".
Example:
rt5025-battery {
compatible = "rt,rt5025-battery";
};

View File

@ -0,0 +1,41 @@
Richtek RT5025 Charger part
The RT5025 charger part is responsible to change the charging current/voltage, etc.
Required properties:
- compatible : Must be "rt,rt5025-charger".
- rt,chg_volt : default charging voltage.
- rt,ieoc : 0x0 is 10%, 0x1 is 20%.
- rt,vdpm : 0x0 is 4V, 0x1 is 4.25V, 0x2 is 4.5V, 0x3 is disable.
- rt,vprec: precharge voltage.
- rt,iprec: precharge current.
- rt,acchg_icc: rt-power ac charge current.
- rt,usbtachg_icc: rt-power usbta charge current.
- rt,ustchg_icc: rt-power normal usb charge current.
- rt,screenon_icc: screen on charge current.
- rt,te_en: enable terminate function.
- rt,screenon_adjust: enable screen on lower charge current,
screen off recovery to the default charge current.
- rt,temp: jeita temperature, unit 0.1'c
- rt,temp_scalar: jeita temperature scalar according to NTC spec.
Example:
rt5025-charger {
compatible = "rt,rt5025-charger";
rt,te_en;
//rt,screenon_adjust;
rt,iprec = <0x00>;
rt,ieoc = <0x00>;
rt,vprec = <0x05>;
rt,vdpm = <0x02>;
rt,chg_volt = <4200>;
rt,acchg_icc = <2000>;
rt,usbtachg_icc = <2000>;
rt,usbchg_icc = <500>;
rt,screenon_icc = <500>;
rt,temp = <0 150 500 600>;
rt,temp_scalar = <0x30 0x2b 0x28 0x22 0x15 0x10 0x10 0x0d>;
};

View File

@ -0,0 +1,27 @@
Richtek RT5025 of regulators
Required properties:
For rt5025 regulators/LDOs
- compatible:
- "rt,rt5025-dcdc1" for Buck1
- "rt,rt5025-dcdc2" for Buck2
- "rt,rt5025-dcdc3" for Buck3
- "rt,rt5025-dcdc4" for Buck4/Boost
- "rt,rt5025-ldo1" for Ldo1
- "rt,rt5025-ldo2" for Ldo2
- "rt,rt5025-ldo3" for Ldo3
- "rt,rt5025-ldo4" for Ldo4
- "rt,rt5025-ldo5" for Ldo5
- "rt,rt5025-ldo6" for Ldo6
Example:
rt5025-dcdc1: regulator_0@0 {
compatible = "rt,rt5025-dcdc1";
cell-index = <0>;
regulator-min-microvolt = < 700000>;
regulator-max-microvolt = <2275000>;
rt,ramp_sel = <0x00>;
rt,allow_mode_mask;
qcom,consumer-supplies = "rt5025-dcdc1", "";
};

View File

@ -168,6 +168,11 @@ rk818: rk818@1c {
reg = <0x1c>;
status = "okay";
};
rt5025: rt5025@35 {
compatible = "rt,rt5025";
reg = <0x35>;
status = "okay";
};
};
&i2c2 {
status = "okay";
@ -201,6 +206,106 @@ &hdmi {
status = "okay";
};
/include/ "rt5025.dtsi"
&rt5025 {
rt5025_dcdc1: regulator_0 {
regulator-name = "vdd_arm";
regulator-min-microvolt = < 700000>;
regulator-max-microvolt = <1500000>;
qcom,comsumer-supplies = "vdd_arm", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_dcdc2: regulator_1 {
regulator-name = "vdd_logic";
regulator-min-microvolt = < 700000>;
regulator-max-microvolt = <1500000>;
qcom,comsumer-supplies = "vdd_logic", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_dcdc3: regulator_2 {
regulator-name = "rt5025-dcdc3";
regulator-min-microvolt = < 1800000>;
regulator-max-microvolt = <3300000>;
qcom,comsumer-supplies = "rt5025-dcdc3", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_dcdc4: regulator_3 {
regulator-name = "rt5025-dcdc4";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
qcom,comsumer-supplies = "rt5025-dcdc4", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_ldo1: regulator_4 {
regulator-name = "rt5025-ldo1";
regulator-min-microvolt = < 1800000>;
regulator-max-microvolt = <1800000>;
qcom,comsumer-supplies = "rt5025-ldo1", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_ldo2: regulator_5 {
regulator-name = "rt5025-ldo2";
regulator-min-microvolt = < 1200000>;
regulator-max-microvolt = <1200000>;
qcom,comsumer-supplies = "rt5025-ldo2", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_ldo3: regulator_6 {
regulator-name = "rt5025-ldo3";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
qcom,comsumer-supplies = "rt5025-ldo3", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_ldo4: regulator_7 {
regulator-name = "rt5025-ldo4";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
qcom,comsumer-supplies = "rt5025-ldo4", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_ldo5: regulator_8 {
regulator-name = "rt5025-ldo5";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,comsumer-supplies = "rt5025-ldo5", "";
regulator-always-on;
regulator-boot-on;
};
rt5025_ldo6: regulator_9 {
regulator-name = "rt5025-ldo6";
regulator-min-microvolt = <330000>;
regulator-max-microvolt = <3300000>;
qcom,comsumer-supplies = "rt5025-ldo6", "";
regulator-always-on;
regulator-boot-on;
};
rt5025-irq {
compatible = "rt,rt5025-irq";
rt,irq-gpio = <&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>;
};
};
/include/ "rk818.dtsi"
&rk818 {
gpios =<&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>,<&gpio1 GPIO_A1 GPIO_ACTIVE_LOW>;

113
arch/arm/boot/dts/rt5025.dtsi Executable file
View File

@ -0,0 +1,113 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
&rt5025 {
compatible = "rt,rt5025";
// reg = <0x35>;
rt5025_dcdc1: regulator_0 {
compatible = "rt,rt5025-dcdc1";
cell-index = <0>;
rt,ramp_sel = <0x00>;
rt,allow_mode_mask;
};
rt5025_dcdc2: regulator_1 {
compatible = "rt,rt5025-dcdc2";
cell-index = <1>;
rt,ramp_sel = <0x00>;
rt,allow_mode_mask;
};
rt5025_dcdc3: regulator_2 {
compatible = "rt,rt5025-dcdc3";
cell-index = <2>;
rt,ramp_sel = <0x00>;
rt,allow_mode_mask;
};
rt5025_dcdc4: regulator_3 {
compatible = "rt,rt5025-dcdc4";
cell-index = <3>;
};
rt5025_ldo1: regulator_4 {
compatible = "rt,rt5025-ldo1";
cell-index = <4>;
};
rt5025_ldo2: regulator_5 {
compatible = "rt,rt5025-ldo2";
cell-index = <5>;
};
rt5025_ldo3: regulator_6 {
compatible = "rt,rt5025-ldo3";
cell-index = <6>;
};
rt5025_ldo4: regulator_7 {
compatible = "rt,rt5025-ldo4";
cell-index = <7>;
};
rt5025_ldo5: regulator_8 {
compatible = "rt,rt5025-ldo5";
cell-index = <8>;
};
rt5025_ldo6: regulator_9 {
compatible = "rt,rt5025-ldo6";
cell-index = <9>;
};
rt5025-charger {
compatible = "rt,rt5025-charger";
rt,te_en;
//rt,screenon_adjust;
rt,iprec = <0x00>;
rt,ieoc = <0x00>;
rt,vprec = <0x05>;
rt,vdpm = <0x02>;
rt,chg_volt = <4200>;
rt,acchg_icc = <2000>;
rt,usbtachg_icc = <2000>;
rt,usbchg_icc = <500>;
rt,screenon_icc = <500>;
rt,temp = <0 150 500 600>;
rt,temp_scalar = <0x30 0x2b 0x28 0x22 0x15 0x10 0x10 0x0d>;
};
rt5025-battery {
compatible = "rt,rt5025-battery";
};
rt5025_gpio: rt5025-gpio {
compatible = "rt,rt5025-gpio";
gpio-controller;
#gpio-cells = <2>;
rt,ngpio = <3>;
};
rt5025-misc {
compatible = "rt,rt5025-misc";
rt,vsyslv = <0x02>;
rt,shdnlpress_time = <0x01>;
rt,startlpress_time = <0x00>;
rt,vsyslv_enshdn;
rt,system-power-controller;
};
rt5025-debug {
compatible = "rt,rt5025-debug";
};
};

View File

@ -209,6 +209,13 @@ config GPIO_RCAR
help
Say yes here to support GPIO on Renesas R-Car SoCs.
config GPIO_RT5025
bool "Richtek RT5025 GPIO support"
depends on MFD_RT5025
default n
help
This is the gpio driver for RT5025 PMIC.
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR

View File

@ -87,3 +87,4 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_RT5025) += gpio-rt5025.o

View File

@ -2,12 +2,13 @@
* drivers/gpio/rt5025-gpio.c
* Driver foo Richtek RT5025 PMIC GPIO
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2014 Richtek Technologh Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
@ -16,8 +17,8 @@
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/mfd/rt5025.h>
#include <linux/mfd/rt5025-gpio.h>
@ -26,21 +27,22 @@ struct rt5025_gpio_info {
struct i2c_client *i2c;
unsigned gpio_base;
unsigned irq_base;
int ngpio;
struct gpio_chip gpio_chip;
};
static inline int find_rt5025_gpioreg(unsigned off, int *gpio_reg)
{
int ret = 0;
switch (off)
{
case 0:
case 1:
case 2:
*gpio_reg = RT5025_REG_GPIO0 + off;
break;
default:
ret = -EINVAL;
switch (off) {
case 0:
case 1:
case 2:
*gpio_reg = RT5025_REG_GPIO0 + off;
break;
default:
ret = -EINVAL;
}
return ret;
}
@ -50,17 +52,15 @@ static int rt5025_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
int gpio_reg = 0;
int ret = 0;
ret = find_rt5025_gpioreg(offset , &gpio_reg);
if (ret < 0)
{
if (ret < 0) {
dev_err(chip->dev, "not a valid gpio index\n");
return ret;
}
ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRMASK);
if (ret<0)
{
if (ret < 0) {
dev_err(chip->dev, "set gpio input fail\n");
return ret;
}
@ -68,40 +68,40 @@ static int rt5025_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
return 0;
}
static int rt5025_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
static int rt5025_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
int gpio_reg = 0;
int ret = 0;
ret = find_rt5025_gpioreg(offset, &gpio_reg);
if (ret < 0)
{
if (ret < 0) {
dev_err(chip->dev, "not a valid gpio index\n");
return ret;
}
ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRSHIFT);
if (ret<0)
{
if (ret < 0) {
dev_err(chip->dev, "clr gpio direction fail\n");
return ret;
}
ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OUTPUT<<RT5025_GPIO_DIRSHIFT);
if (ret<0)
{
ret = rt5025_set_bits(gi->i2c, gpio_reg,
RT5025_GPIO_OUTPUT<<RT5025_GPIO_DIRSHIFT);
if (ret < 0) {
dev_err(chip->dev, "set gpio output dir fail\n");
return ret;
}
if (value)
ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
ret = rt5025_set_bits(gi->i2c, gpio_reg,
RT5025_GPIO_OVALUEMASK);
else
ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
ret = rt5025_clr_bits(gi->i2c, gpio_reg,
RT5025_GPIO_OVALUEMASK);
if (ret<0)
{
if (ret < 0) {
dev_err(chip->dev, "set gpio output value fail\n");
return ret;
}
@ -114,62 +114,88 @@ static int rt5025_gpio_get_value(struct gpio_chip *chip, unsigned offset)
struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
int gpio_reg = 0;
int ret = 0;
ret = find_rt5025_gpioreg(offset, &gpio_reg);
if (ret < 0)
{
if (ret < 0) {
dev_err(chip->dev, "not a valid gpio index\n");
return ret;
}
ret = rt5025_reg_read(gi->i2c, gpio_reg);
if (ret<0)
{
if (ret < 0) {
dev_err(chip->dev, "read gpio register fail\n");
return ret;
}
return (ret&RT5025_GPIO_IVALUEMASK)?1:0;
return (ret&RT5025_GPIO_IVALUEMASK)?1 : 0;
}
static void rt5025_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
static void rt5025_gpio_set_value(struct gpio_chip *chip,
unsigned offset, int value)
{
struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev);
int gpio_reg = 0;
int ret = 0;
ret = find_rt5025_gpioreg(offset, &gpio_reg);
if (ret < 0)
{
if (ret < 0) {
dev_err(chip->dev, "not a valid gpio index\n");
return;
}
if (value)
ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
ret = rt5025_set_bits(gi->i2c, gpio_reg,
RT5025_GPIO_OVALUEMASK);
else
ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
ret = rt5025_clr_bits(gi->i2c, gpio_reg,
RT5025_GPIO_OVALUEMASK);
if (ret<0)
{
if (ret < 0)
dev_err(chip->dev, "read gpio register fail\n");
}
}
static int __devinit rt5025_gpio_probe(struct platform_device *pdev)
static int rt_parse_dt(struct rt5025_gpio_info *gi, struct device *dev)
{
#ifdef CONFIG_OF
struct device_node *np = dev->of_node;
of_property_read_u32(np, "rt,ngpio", &gi->ngpio);
#endif /* #ifdef CONFIG_OF */
return 0;
}
static int rt_parse_pdata(struct rt5025_gpio_info *gi, struct device *dev)
{
struct rt5025_gpio_data *gpio_pdata = dev->platform_data;
gi->ngpio = gpio_pdata->ngpio;
return 0;
}
static int rt5025_gpio_probe(struct platform_device *pdev)
{
struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct rt5025_platform_data *pdata = chip->dev->platform_data;
struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data;
struct rt5025_gpio_info *gi;
int ret = 0;
bool use_dt = pdev->dev.of_node;
int rc = 0;
gi = kzalloc(sizeof(*gi), GFP_KERNEL);
gi = devm_kzalloc(&pdev->dev, sizeof(*gi), GFP_KERNEL);
if (!gi)
return -ENOMEM;
gi->i2c = chip->i2c;
gi->gpio_base = pdata->gpio_data->gpio_base;
gi->irq_base = pdata->gpio_data->irq_base;
if (use_dt) {
rt_parse_dt(gi, &pdev->dev);
} else {
if (!pdata) {
rc = -EINVAL;
goto out_dev;
}
pdev->dev.platform_data = pdata->gpio_pdata;
rt_parse_pdata(gi, &pdev->dev);
}
gi->gpio_chip.direction_input = rt5025_gpio_direction_input;
gi->gpio_chip.direction_output = rt5025_gpio_direction_output;
@ -177,59 +203,62 @@ static int __devinit rt5025_gpio_probe(struct platform_device *pdev)
gi->gpio_chip.set = rt5025_gpio_set_value;
gi->gpio_chip.can_sleep = 0;
gi->gpio_chip.base = gi->gpio_base;
gi->gpio_chip.ngpio = RT5025_GPIO_NR;
gi->gpio_chip.base = -1;
gi->gpio_chip.ngpio = gi->ngpio;
gi->gpio_chip.label = pdev->name;
gi->gpio_chip.dev = &pdev->dev;
gi->gpio_chip.owner = THIS_MODULE;
ret = gpiochip_add(&gi->gpio_chip);
if (ret)
rc = gpiochip_add(&gi->gpio_chip);
if (rc)
goto out_dev;
platform_set_drvdata(pdev, gi);
return ret;
dev_info(&pdev->dev, "driver successfully loaded\n");
return rc;
out_dev:
kfree(gi);
return ret;
return rc;
}
static int __devexit rt5025_gpio_remove(struct platform_device *pdev)
static int rt5025_gpio_remove(struct platform_device *pdev)
{
int ret;
int rc = 0;
struct rt5025_gpio_info *gi = platform_get_drvdata(pdev);
ret = gpiochip_remove(&gi->gpio_chip);
kfree(gi);
platform_set_drvdata(pdev, NULL);
rc = gpiochip_remove(&gi->gpio_chip);
dev_info(&pdev->dev, "\n");
return 0;
}
static struct platform_driver rt5025_gpio_driver =
{
.driver = {
.name = RT5025_DEVICE_NAME "-gpio",
.owner = THIS_MODULE,
},
.probe = rt5025_gpio_probe,
.remove = __devexit_p(rt5025_gpio_remove),
static struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt5025-gpio",},
{},
};
static int __init rt5025_gpio_init(void)
static struct platform_driver rt5025_gpio_driver = {
.driver = {
.name = RT5025_DEV_NAME "-gpio",
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt5025_gpio_probe,
.remove = rt5025_gpio_remove,
};
static int rt5025_gpio_init(void)
{
return platform_driver_register(&rt5025_gpio_driver);
}
subsys_initcall_sync(rt5025_gpio_init);
fs_initcall_sync(rt5025_gpio_init);
static void __exit rt5025_gpio_exit(void)
static void rt5025_gpio_exit(void)
{
platform_driver_unregister(&rt5025_gpio_driver);
}
module_exit(rt5025_gpio_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("GPIO driver for RT5025");
MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-gpio");
MODULE_ALIAS("platform:" RT5025_DEV_NAME "-gpio");
MODULE_VERSION(RT5025_DRV_VER);

View File

@ -169,6 +169,42 @@ config MFD_MC13XXX_I2C
help
Select this if your MC13xxx is connected via an I2C bus.
config MFD_RT5025
bool "RT5025 PMIC Chip Core driver"
depends on I2C
select MFD_CORE
default n
help
Enable RT5025 core driver.
config MISC_RT5025
bool "RT5025 PMIC chip misc configuration"
depends on MFD_RT5025
default n
help
Enable RT5025 Misc configuration.
config IRQ_RT5025
bool "RT5025_PMIC chip irq driver"
depends on MFD_RT5025
default n
help
Enable RT5025 IRQ configuration and interrupt.
config DEBUG_RT5025
bool "RT5025 PMIC Chip Core Debug"
depends on MFD_RT5025 && DEBUG_FS
default n
help
Enable RT5025 core debug driver.
config MFD_RT_SHOW_INFO
bool "RT5025 PMIC Debug log Flag"
depends on MFD_RT5025
default n
help
Enable the RT5025 PMIC debug log.
config HTC_EGPIO
bool "HTC EGPIO support"
depends on GENERIC_HARDIRQS && GPIOLIB && ARM

View File

@ -55,6 +55,11 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o
obj-$(CONFIG_MFD_RT5025) += rt5025-i2c.o rt5025-core.o
obj-$(CONFIG_MISC_RT5025) += rt5025-misc.o
obj-$(CONFIG_IRQ_RT5025) += rt5025-irq.o
obj-$(CONFIG_DEBUG_RT5025) += rt5025-debug.o
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o

207
drivers/mfd/rt5025-core.c Normal file → Executable file
View File

@ -2,12 +2,13 @@
* drivers/mfd/rt5025-core.c
* Driver for Richtek RT5025 Core PMIC
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
@ -15,101 +16,144 @@
#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rt5025.h>
#ifdef CONFIG_REGULATOR_RT5025
#define RT5025_VR_DEVS(_id) \
#ifdef CONFIG_OF
#define RT5025_BUCKVR_DEVS(_id, _idx) \
{ \
.name = RT5025_DEVICE_NAME "-regulator", \
.name = RT5025_DEV_NAME "-regulator", \
.num_resources = 0, \
.of_compatible = "rt," RT5025_DEV_NAME "-dcdc" #_idx , \
.id = RT5025_ID_##_id, \
}
#define RT5025_LDOVR_DEVS(_id, _idx) \
{ \
.name = RT5025_DEV_NAME "-regulator", \
.num_resources = 0, \
.of_compatible = "rt," RT5025_DEV_NAME "-ldo" #_idx , \
.id = RT5025_ID_##_id, \
}
#else
#define RT5025_BUCKVR_DEVS(_id, _idx) \
{ \
.name = RT5025_DEV_NAME "-regulator", \
.num_resources = 0, \
.id = RT5025_ID_##_id, \
}
#define RT5025_LDOVR_DEVS(_id, _idx) \
{ \
.name = RT5025_DEV_NAME "-regulator", \
.num_resources = 0, \
.id = RT5025_ID_##_id, \
}
#endif /* #ifdef CONFIG_OF */
static struct mfd_cell regulator_devs[] = {
RT5025_VR_DEVS(DCDC1),
RT5025_VR_DEVS(DCDC2),
RT5025_VR_DEVS(DCDC3),
RT5025_VR_DEVS(DCDC4),
RT5025_VR_DEVS(LDO1),
RT5025_VR_DEVS(LDO2),
RT5025_VR_DEVS(LDO3),
RT5025_VR_DEVS(LDO4),
RT5025_VR_DEVS(LDO5),
RT5025_VR_DEVS(LDO6),
RT5025_BUCKVR_DEVS(DCDC1, 1),
RT5025_BUCKVR_DEVS(DCDC2, 2),
RT5025_BUCKVR_DEVS(DCDC3, 3),
RT5025_BUCKVR_DEVS(DCDC4, 4),
RT5025_LDOVR_DEVS(LDO1, 1),
RT5025_LDOVR_DEVS(LDO2, 2),
RT5025_LDOVR_DEVS(LDO3, 3),
RT5025_LDOVR_DEVS(LDO4, 4),
RT5025_LDOVR_DEVS(LDO5, 5),
RT5025_LDOVR_DEVS(LDO6, 6),
};
#endif /* CONFIG_REGULATOR_RT5025 */
#endif /* #ifdef CONFIG_REGULATOR_RT5025 */
#ifdef CONFIG_POWER_RT5025
static struct mfd_cell power_devs[] = {
#ifdef CONFIG_CHARGER_RT5025
static struct mfd_cell chg_devs[] = {
{
.name = RT5025_DEVICE_NAME "-power",
.id = -1,
.num_resources = 0,
},
{
.name = RT5025_DEVICE_NAME "-swjeita",
.id = -1,
.num_resources = 0,
},
{
.name = RT5025_DEVICE_NAME "-battery",
.name = RT5025_DEV_NAME "-charger",
.id = -1,
.num_resources = 0,
#ifdef CONFIG_OF
.of_compatible = "rt," RT5025_DEV_NAME "-charger" ,
#endif /*#ifdef CONFIG_OF */
},
};
#endif /* CONFIG_POWER_RT5025 */
#endif /* #ifdef CONFIG_CHARGER_RT5025 */
#ifdef CONFIG_BATTERY_RT5025
static struct mfd_cell fg_devs[] = {
{
.name = RT5025_DEV_NAME "-battery",
.id = -1,
.num_resources = 0,
#ifdef CONFIG_OF
.of_compatible = "rt," RT5025_DEV_NAME "-battery" ,
#endif /*#ifdef CONFIG_OF */
},
};
#endif /* #ifdef CONFIG_BATTERY_RT5025 */
#ifdef CONFIG_GPIO_RT5025
static struct mfd_cell gpio_devs[] = {
{
.name = RT5025_DEVICE_NAME "-gpio",
.name = RT5025_DEV_NAME "-gpio",
.id = -1,
.num_resources = 0,
#ifdef CONFIG_OF
.of_compatible = "rt," RT5025_DEV_NAME "-gpio" ,
#endif /*#ifdef CONFIG_OF */
},
};
#endif /* CONFIG_GPIO_RT5025 */
#endif /* #ifdef CONFIG_GPIO_RT5025 */
#ifdef CONFIG_MFD_RT5025_MISC
#ifdef CONFIG_MISC_RT5025
static struct mfd_cell misc_devs[] = {
{
.name = RT5025_DEVICE_NAME "-misc",
.name = RT5025_DEV_NAME "-misc",
.id = -1,
.num_resources = 0,
#ifdef CONFIG_OF
.of_compatible = "rt," RT5025_DEV_NAME "-misc" ,
#endif /*#ifdef CONFIG_OF */
},
};
#endif /* CONFIG_MFD_RT5025_MISC */
#endif /* #ifdef CONFIG_MISC_RT5025 */
#ifdef CONFIG_MFD_RT5025_IRQ
#ifdef CONFIG_IRQ_RT5025
static struct mfd_cell irq_devs[] = {
{
.name = RT5025_DEVICE_NAME "-irq",
.name = RT5025_DEV_NAME "-irq",
.id = -1,
.num_resources = 0,
#ifdef CONFIG_OF
.of_compatible = "rt," RT5025_DEV_NAME "-irq" ,
#endif /*#ifdef CONFIG_OF */
},
};
#endif /* CONFIG_MFD_RT5025_IRQ */
#endif /* #ifdef CONFIG_IRQ_RT5025 */
#ifdef CONFIG_MFD_RT5025_DEBUG
#ifdef CONFIG_DEBUG_RT5025
static struct mfd_cell debug_devs[] = {
{
.name = RT5025_DEVICE_NAME "-debug",
.name = RT5025_DEV_NAME "-debug",
.id = -1,
.num_resources = 0,
#ifdef CONFIG_OF
.of_compatible = "rt," RT5025_DEV_NAME "-debug" ,
#endif /*#ifdef CONFIG_OF */
},
};
#endif /* CONFIG_MFD_RT5025_DEBUG */
#endif /* #ifdef CONFIG_DEBUG_RT5025 */
int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_data *pdata)
int rt5025_core_init(struct rt5025_chip *chip,
struct rt5025_platform_data *pdata)
{
int ret = 0;
bool use_dt = chip->dev->of_node;
RTINFO("Start to initialize all device\n");
#ifdef CONFIG_REGULATOR_RT5025
if (pdata && pdata->regulator[0]) {
if (use_dt || (pdata && pdata->regulator[0])) {
RTINFO("mfd add regulators dev\n");
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
ARRAY_SIZE(regulator_devs),
NULL, 0, NULL);
@ -117,24 +161,43 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
ARRAY_SIZE(regulator_devs),
NULL, 0);
#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
#endif /* LINUX_VERSION_CODE >= KERNL_VERSION(3,6,0) */
if (ret < 0) {
dev_err(chip->dev, "Failed to add regulator subdev\n");
goto out_dev;
}
}
#endif /* CONFIG_REGULATOR_RT5025 */
#endif /* #ifdef CONFIG_REGULATOR_RT5025 */
#ifdef CONFIG_POWER_RT5025
if (pdata && pdata->power_data && pdata->jeita_data) {
RTINFO("mfd add power dev\n");
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
ARRAY_SIZE(power_devs),
NULL, 0,NULL);
#ifdef CONFIG_CHARGER_RT5025
if (use_dt || (pdata && pdata->chg_pdata)) {
RTINFO("mfd add charger dev\n");
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &chg_devs[0],
ARRAY_SIZE(chg_devs),
NULL, 0, NULL);
#else
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
ARRAY_SIZE(power_devs),
ret = mfd_add_devices(chip->dev, 0, &chg_devs[0],
ARRAY_SIZE(chg_devs),
NULL, 0);
#endif
if (ret < 0) {
dev_err(chip->dev, "Failed to add power supply subdev\n");
goto out_dev;
}
}
#endif /* #ifdef CONFIG_CHARGER_RT5025 */
#ifdef CONFIG_BATTERY_RT5025
if (use_dt || (pdata)) {
RTINFO("mfd add fuelgauge dev\n");
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &fg_devs[0],
ARRAY_SIZE(fg_devs),
NULL, 0, NULL);
#else
ret = mfd_add_devices(chip->dev, 0, &fg_devs[0],
ARRAY_SIZE(fg_devs),
NULL, 0);
#endif
if (ret < 0) {
@ -143,13 +206,13 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
goto out_dev;
}
}
#endif /* CONFIG_MFD_RT5025 */
#endif /* #ifdef CONFIG_BATTERY_RT5025 */
//Initialize the RT5025_GPIO
/*Initialize the RT5025_GPIO*/
#ifdef CONFIG_GPIO_RT5025
if (pdata && pdata->gpio_data) {
if (use_dt || (pdata && pdata->gpio_pdata)) {
RTINFO("mfd add gpios dev\n");
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &gpio_devs[0],
ARRAY_SIZE(gpio_devs),
NULL, 0, NULL);
@ -163,12 +226,12 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
goto out_dev;
}
}
#endif /* CONFIG_GPIO_RT5025 */
#endif /* #ifdef CONFIG_GPIO_RT5025 */
#ifdef CONFIG_MFD_RT5025_MISC
if (pdata && pdata->misc_data) {
#ifdef CONFIG_MISC_RT5025
if (use_dt || (pdata && pdata->misc_pdata)) {
RTINFO("mfd add misc dev\n");
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &misc_devs[0],
ARRAY_SIZE(misc_devs),
NULL, 0, NULL);
@ -182,12 +245,12 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
goto out_dev;
}
}
#endif /* CONFIG_MFD_RT5025_MISC */
#endif /* #ifdef CONFIG_MISC_RT5025 */
#ifdef CONFIG_MFD_RT5025_IRQ
if (pdata && pdata->irq_data) {
#ifdef CONFIG_IRQ_RT5025
if (use_dt || (pdata && pdata->irq_pdata)) {
RTINFO("mfd add irq dev\n");
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &irq_devs[0],
ARRAY_SIZE(irq_devs),
NULL, 0, NULL);
@ -201,11 +264,11 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
goto out_dev;
}
}
#endif /* CONFIG_MFD_RT5025_IRQ */
#endif /* #ifdef CONFIG_IRQ_RT5025 */
#ifdef CONFIG_MFD_RT5025_DEBUG
#ifdef CONFIG_DEBUG_RT5025
RTINFO("mfd add debug dev\n");
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
ret = mfd_add_devices(chip->dev, 0, &debug_devs[0],
ARRAY_SIZE(debug_devs),
NULL, 0, NULL);
@ -218,7 +281,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
dev_err(chip->dev, "Failed to add debug subdev\n");
goto out_dev;
}
#endif /* CONFIG_MFD_RT5025_DEBUG */
#endif /* CONFIG_DEBUG_RT5025 */
RTINFO("Initialize all device successfully\n");
return ret;
@ -228,7 +291,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_
}
EXPORT_SYMBOL(rt5025_core_init);
int __devexit rt5025_core_deinit(struct rt5025_chip *chip)
int rt5025_core_deinit(struct rt5025_chip *chip)
{
mfd_remove_devices(chip->dev);
return 0;

232
drivers/mfd/rt5025-debug.c Normal file → Executable file
View File

@ -2,12 +2,13 @@
* drivers/mfd/rt5025-debug.c
* Driver foo Richtek RT5025 PMIC Debug
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2013 Richtek Technologh Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
@ -15,26 +16,33 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/mfd/rt5025.h>
struct rt5025_debug_info {
struct i2c_client *i2c;
struct device *dev;
unsigned char reg_addr;
unsigned char reg_data;
};
static struct i2c_client *client;
static struct dentry *debugfs_rt_dent;
static struct dentry *debugfs_peek;
static struct dentry *debugfs_poke;
static struct dentry *debugfs_regs;
static struct dentry *debugfs_reset_b;
struct rt_debug_st {
void *info;
int id;
};
static unsigned char read_data[10];
enum {
RT5025_DBG_REG,
RT5025_DBG_DATA,
RT5025_DBG_REGS,
RT5025_DBG_MAX
};
static struct dentry *debugfs_rt_dent;
static struct dentry *debugfs_file[RT5025_DBG_MAX];
static struct rt_debug_st rtdbg_data[RT5025_DBG_MAX];
static int reg_debug_open(struct inode *inode, struct file *file)
{
@ -60,37 +68,60 @@ static int get_parameters(char *buf, long int *param1, int num_of_par)
return -EINVAL;
token = strsep(&buf, " ");
}
else
} else {
return -EINVAL;
}
}
return 0;
}
#define LOG_FORMAT "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n"
static ssize_t reg_debug_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
char *access_str = filp->private_data;
char lbuf[150];
if (!strcmp(access_str, "regs"))
{
RTINFO("read regs file\n");
/* read regs */
snprintf(lbuf, sizeof(lbuf), LOG_FORMAT LOG_FORMAT, read_data[0], \
read_data[1], read_data[2], read_data[3], read_data[4], read_data[5], \
read_data[6], read_data[7], read_data[8], read_data[9]);
struct rt_debug_st *st = filp->private_data;
struct rt5025_debug_info *di = st->info;
char lbuf[1000];
int i = 0, j = 0;
lbuf[0] = '\0';
switch (st->id) {
case RT5025_DBG_REG:
snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_addr);
break;
case RT5025_DBG_DATA:
di->reg_data = (unsigned char)rt5025_reg_read(di->i2c,
di->reg_addr);
snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_data);
break;
case RT5025_DBG_REGS:
for (i = RT5025_REG_RANGE1START;
i <= RT5025_REG_RANGE1END; i++)
j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \
rt5025_reg_read(di->i2c, i));
for (i = RT5025_REG_RANGE2START;
i <= RT5025_REG_RANGE2END; i++)
j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \
rt5025_reg_read(di->i2c, i));
for (i = RT5025_REG_RANGE3START;
i <= RT5025_REG_RANGE3END; i++)
j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \
rt5025_reg_read(di->i2c, i));
for (i = RT5025_REG_RANGE4START;
i <= RT5025_REG_RANGE4END; i++)
j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \
rt5025_reg_read(di->i2c, i));
break;
default:
return -EINVAL;
}
else
snprintf(lbuf, sizeof(lbuf), "0x%02x\n", read_data[0]);
return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf));
}
static ssize_t reg_debug_write(struct file *filp,
const char __user *ubuf, size_t cnt, loff_t *ppos)
{
char *access_str = filp->private_data;
struct rt_debug_st *st = filp->private_data;
struct rt5025_debug_info *di = st->info;
char lbuf[32];
int rc;
long int param[5];
@ -104,56 +135,37 @@ static ssize_t reg_debug_write(struct file *filp,
lbuf[cnt] = '\0';
if (!strcmp(access_str, "poke")) {
/* write */
rc = get_parameters(lbuf, param, 2);
if ((param[0] <= 0xFF) && (param[1] <= 0xFF) && (rc == 0))
{
rt5025_reg_write(client, param[0], (unsigned char)param[1]);
switch (st->id) {
case RT5025_DBG_REG:
rc = get_parameters(lbuf, param, 1);
if ((param[0] < RT5025_REG_MAX) && (rc == 0)) {
if ((param[0] >= RT5025_REG_RANGE1START && param[0]
<= RT5025_REG_RANGE1END) || \
(param[0] >= RT5025_REG_RANGE2START && param[0]
<= RT5025_REG_RANGE2END) || \
(param[0] >= RT5025_REG_RANGE3START && param[0]
<= RT5025_REG_RANGE3END) || \
(param[0] >= RT5025_REG_RANGE4START && param[0]
<= RT5025_REG_RANGE4END))
di->reg_addr = (unsigned char)param[0];
else
rc = -EINVAL;
} else {
rc = -EINVAL;
}
break;
case RT5025_DBG_DATA:
rc = get_parameters(lbuf, param, 1);
if ((param[0] <= 0xff) && (rc == 0))
rt5025_reg_write(di->i2c, di->reg_addr, param[0]);
else
rc = -EINVAL;
} else if (!strcmp(access_str, "peek")) {
/* read */
rc = get_parameters(lbuf, param, 1);
if ((param[0] <= 0xFF) && (rc == 0))
{
read_data[0] = rt5025_reg_read(client, param[0]);
}
else
rc = -EINVAL;
} else if (!strcmp(access_str, "regs")) {
/* read */
rc = get_parameters(lbuf, param, 1);
if ((param[0] <= 0xFF) && (rc == 0))
{
rt5025_reg_block_read(client, param[0], 10, read_data);
RTINFO("regs 0 = 0x%02x\n", read_data[0]);
RTINFO("regs 1 = 0x%02x\n", read_data[1]);
RTINFO("regs 2 = 0x%02x\n", read_data[2]);
RTINFO("regs 3 = 0x%02x\n", read_data[3]);
RTINFO("regs 4 = 0x%02x\n", read_data[4]);
RTINFO("regs 5 = 0x%02x\n", read_data[5]);
RTINFO("regs 6 = 0x%02x\n", read_data[6]);
RTINFO("regs 7 = 0x%02x\n", read_data[7]);
RTINFO("regs 8 = 0x%02x\n", read_data[8]);
RTINFO("regs 9 = 0x%02x\n", read_data[9]);
}
else
rc = -EINVAL;
} else if (!strcmp(access_str, "reset_b")) {
/* read */
rc = get_parameters(lbuf, param, 1);
if (param[0] == 1 && rc == 0)
{
memset(lbuf, 0, 15);
rt5025_reg_block_write(client, 0x21, 15, lbuf);
}
break;
default:
return -EINVAL;
}
if (rc == 0)
rc = cnt;
return rc;
}
@ -163,78 +175,84 @@ static const struct file_operations reg_debug_ops = {
.read = reg_debug_read
};
static int __devinit rt5025_debug_probe(struct platform_device *pdev)
static int rt5025_debug_probe(struct platform_device *pdev)
{
struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct rt5025_debug_info *di;
int ret = 0;
di = kzalloc(sizeof(*di), GFP_KERNEL);
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
if (!di)
return -ENOMEM;
di->i2c = chip->i2c;
di->dev = &pdev->dev;
RTINFO("add debugfs for core RT5025");
client = chip->i2c;
RTINFO("add debugfs for RT5025");
debugfs_rt_dent = debugfs_create_dir("rt5025_dbg", 0);
if (!IS_ERR(debugfs_rt_dent)) {
debugfs_peek = debugfs_create_file("peek",
rtdbg_data[0].info = di;
rtdbg_data[0].id = RT5025_DBG_REG;
debugfs_file[0] = debugfs_create_file("reg",
S_IFREG | S_IRUGO, debugfs_rt_dent,
(void *) "peek", &reg_debug_ops);
(void *) &rtdbg_data[0], &reg_debug_ops);
debugfs_poke = debugfs_create_file("poke",
rtdbg_data[1].info = di;
rtdbg_data[1].id = RT5025_DBG_DATA;
debugfs_file[1] = debugfs_create_file("data",
S_IFREG | S_IRUGO, debugfs_rt_dent,
(void *) "poke", &reg_debug_ops);
(void *) &rtdbg_data[1], &reg_debug_ops);
debugfs_regs = debugfs_create_file("regs",
rtdbg_data[2].info = di;
rtdbg_data[2].id = RT5025_DBG_REGS;
debugfs_file[2] = debugfs_create_file("regs",
S_IFREG | S_IRUGO, debugfs_rt_dent,
(void *) "regs", &reg_debug_ops);
debugfs_reset_b = debugfs_create_file("reset_b",
S_IFREG | S_IRUGO, debugfs_rt_dent,
(void *) "reset_b", &reg_debug_ops);
(void *) &rtdbg_data[2], &reg_debug_ops);
} else {
dev_err(&pdev->dev, "create debugfs failed\n");
ret = -EINVAL;
goto err_init;
}
platform_set_drvdata(pdev, di);
return 0;
err_init:
return ret;
}
static int __devexit rt5025_debug_remove(struct platform_device *pdev)
static int rt5025_debug_remove(struct platform_device *pdev)
{
struct rt5025_debug_info *di = platform_get_drvdata(pdev);
if (!IS_ERR(debugfs_rt_dent))
debugfs_remove_recursive(debugfs_rt_dent);
kfree(di);
return 0;
}
static struct platform_driver rt5025_debug_driver =
{
.driver = {
.name = RT5025_DEVICE_NAME "-debug",
.owner = THIS_MODULE,
},
.probe = rt5025_debug_probe,
.remove = __devexit_p(rt5025_debug_remove),
static const struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt5025-debug",},
{},
};
static int __init rt5025_debug_init(void)
static struct platform_driver rt5025_debug_driver = {
.driver = {
.name = RT5025_DEV_NAME "-debug",
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt5025_debug_probe,
.remove = rt5025_debug_remove,
};
static int rt5025_debug_init(void)
{
return platform_driver_register(&rt5025_debug_driver);
}
module_init(rt5025_debug_init);
static void __exit rt5025_debug_exit(void)
static void rt5025_debug_exit(void)
{
platform_driver_unregister(&rt5025_debug_driver);
}
module_exit(rt5025_debug_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
MODULE_DESCRIPTION("Debug driver for RT5025");
MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-debug");
MODULE_ALIAS("platform:" RT5025_DEV_NAME "-debug");
MODULE_VERSION(RT5025_DRV_VER);

254
drivers/mfd/rt5025-i2c.c Normal file → Executable file
View File

@ -2,51 +2,33 @@
* I2C Driver for Richtek RT5025
* Multi function device - multi functional baseband PMIC
*
* Copyright (C) 2013
* Copyright (C) 2014 Richtek Technology Corp.
* Author: CY Huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/mfd/rt5025.h>
#define ROCKCHIP_I2C_RATE (200*1000)
static inline int rt5025_read_device(struct i2c_client *i2c,
int reg, int bytes, void *dest)
{
#if 1
int ret;
unsigned char reg_addr = reg;
struct i2c_msg i2c_msg[2];
i2c_msg[0].addr = i2c->addr;
i2c_msg[0].flags = i2c->flags;
i2c_msg[0].len = 1;
i2c_msg[0].buf = &reg_addr;
i2c_msg[0].scl_rate = ROCKCHIP_I2C_RATE;
i2c_msg[1].addr = i2c->addr;
i2c_msg[1].flags = i2c->flags | I2C_M_RD;
i2c_msg[1].len = bytes;
i2c_msg[1].buf = dest;
i2c_msg[1].scl_rate = ROCKCHIP_I2C_RATE;
ret = i2c_transfer(i2c->adapter, i2c_msg, 2);
#else
int ret;
if (bytes > 1)
if (bytes > 1) {
ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
else {
} else {
ret = i2c_smbus_read_byte_data(i2c, reg);
if (ret < 0)
return ret;
*(unsigned char *)dest = (unsigned char)ret;
}
#endif
return ret;
}
@ -60,30 +42,15 @@ EXPORT_SYMBOL(rt5025_reg_block_read);
static inline int rt5025_write_device(struct i2c_client *i2c,
int reg, int bytes, void *dest)
{
#if 1
int ret;
struct i2c_msg i2c_msg;
char *tx_buf = (char*)kmalloc(bytes+1, GFP_KERNEL);
tx_buf[0] = reg;
memcpy(tx_buf+1, dest, bytes);
i2c_msg.addr = i2c->addr;
i2c_msg.flags = i2c->flags;
i2c_msg.len = bytes + 1;
i2c_msg.buf = tx_buf;
i2c_msg.scl_rate = ROCKCHIP_I2C_RATE;
ret = i2c_transfer(i2c->adapter, &i2c_msg, 1);
kfree(tx_buf);
#else
int ret;
if (bytes > 1)
if (bytes > 1) {
ret = i2c_smbus_write_i2c_block_data(i2c, reg, bytes, dest);
else {
ret = i2c_smbus_write_byte_data(i2c, reg, dest);
} else {
ret = i2c_smbus_write_byte_data(i2c, reg, *(u8 *)dest);
if (ret < 0)
return ret;
*(unsigned char *)dest = (unsigned char)ret;
}
#endif
return ret;
}
@ -96,65 +63,28 @@ EXPORT_SYMBOL(rt5025_reg_block_write);
int rt5025_reg_read(struct i2c_client *i2c, int reg)
{
struct rt5025_chip* chip = i2c_get_clientdata(i2c);
struct rt5025_chip *chip = i2c_get_clientdata(i2c);
int ret;
#if 1
unsigned char reg_addr = reg;
unsigned char reg_data = 0;
struct i2c_msg i2c_msg[2];
RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n",
(unsigned int)i2c,(unsigned int)reg);
mutex_lock(&chip->io_lock);
i2c_msg[0].addr = i2c->addr;
i2c_msg[0].flags = i2c->flags;
i2c_msg[0].len = 1;
i2c_msg[0].buf = &reg_addr;
i2c_msg[0].scl_rate = ROCKCHIP_I2C_RATE;
i2c_msg[1].addr = i2c->addr;
i2c_msg[1].flags = i2c->flags | I2C_M_RD;
i2c_msg[1].len = 1;
i2c_msg[1].buf = &reg_data;
i2c_msg[1].scl_rate = ROCKCHIP_I2C_RATE;
ret = i2c_transfer(i2c->adapter, i2c_msg, 2);
mutex_unlock(&chip->io_lock);
#else
RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n",
(unsigned int)i2c,(unsigned int)reg);
(unsigned int) i2c, (unsigned int) reg);
mutex_lock(&chip->io_lock);
ret = i2c_smbus_read_byte_data(i2c, reg);
mutex_unlock(&chip->io_lock);
#endif
return reg_data;
return ret;
}
EXPORT_SYMBOL(rt5025_reg_read);
int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data)
{
struct rt5025_chip* chip = i2c_get_clientdata(i2c);
struct rt5025_chip *chip = i2c_get_clientdata(i2c);
int ret;
#if 1
unsigned char xfer_data[2];
struct i2c_msg i2c_msg;
RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n",
(unsigned int)i2c,(unsigned int)reg,(unsigned int)data);
xfer_data[0] = reg;
xfer_data[1] = data;
mutex_lock(&chip->io_lock);
i2c_msg.addr = i2c->addr;
i2c_msg.flags = i2c->flags;
i2c_msg.len = 2;
i2c_msg.buf = xfer_data;
i2c_msg.scl_rate = ROCKCHIP_I2C_RATE;
ret = i2c_transfer(i2c->adapter, &i2c_msg, 1);
mutex_unlock(&chip->io_lock);
#else
RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n",
(unsigned int)i2c,(unsigned int)reg,(unsigned int)data);
(unsigned int) i2c, (unsigned int) reg, (unsigned int) data);
mutex_lock(&chip->io_lock);
ret = i2c_smbus_write_byte_data(i2c, reg, data);
mutex_unlock(&chip->io_lock);
#endif
return ret;
}
EXPORT_SYMBOL(rt5025_reg_write);
@ -165,25 +95,7 @@ int rt5025_assign_bits(struct i2c_client *i2c, int reg,
struct rt5025_chip *chip = i2c_get_clientdata(i2c);
unsigned char value;
int ret;
#if 1
struct i2c_msg i2c_msg;
u8 xfer_data[2] = {0};
mutex_lock(&chip->io_lock);
ret = rt5025_read_device(i2c, reg, 1, &value);
if (ret < 0)
goto out;
value &= ~mask;
value |= (data&mask);
xfer_data[0] = reg;
xfer_data[1] = value;
i2c_msg.addr = i2c->addr;
i2c_msg.flags = i2c->flags;
i2c_msg.len = 2;
i2c_msg.buf = xfer_data;
i2c_msg.scl_rate = ROCKCHIP_I2C_RATE;
ret = i2c_transfer(i2c->adapter, &i2c_msg, 1);
#else
mutex_lock(&chip->io_lock);
ret = rt5025_read_device(i2c, reg, 1, &value);
@ -192,8 +104,7 @@ int rt5025_assign_bits(struct i2c_client *i2c, int reg,
goto out;
value &= ~mask;
value |= (data&mask);
ret = i2c_smbus_write_byte_data(i2c,reg,value);
#endif
ret = i2c_smbus_write_byte_data(i2c, reg, value);
out:
mutex_unlock(&chip->io_lock);
return ret;
@ -203,90 +114,101 @@ EXPORT_SYMBOL(rt5025_assign_bits);
int rt5025_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask)
{
return rt5025_assign_bits(i2c,reg,mask,mask);
return rt5025_assign_bits(i2c, reg, mask, mask);
}
EXPORT_SYMBOL(rt5025_set_bits);
int rt5025_clr_bits(struct i2c_client *i2c, int reg,
unsigned char mask)
{
return rt5025_assign_bits(i2c,reg,mask,0);
return rt5025_assign_bits(i2c, reg, mask, 0);
}
EXPORT_SYMBOL(rt5025_clr_bits);
static int __devinit rt5025_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int rt_parse_dt(struct rt5025_chip *chip, struct device *dev)
{
return 0;
}
static int rt_parse_pdata(struct rt5025_chip *chip, struct device *dev)
{
return 0;
}
static int rt5025_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rt5025_platform_data *pdata = client->dev.platform_data;
struct rt5025_chip *chip;
bool use_dt = client->dev.of_node;
int ret = 0;
u8 val;
u8 val = 0;
if (!pdata)
return -EINVAL;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->irq = client->irq;
if (use_dt) {
rt_parse_dt(chip, &client->dev);
} else {
if (!pdata) {
ret = -EINVAL;
goto err_init;
}
rt_parse_pdata(chip, &client->dev);
}
chip->i2c = client;
chip->dev = &client->dev;
#if 0
if (pdata->event_callback)
{
chip->event_callback = kzalloc(sizeof(struct rt5025_event_callback), GFP_KERNEL);
memcpy(chip->event_callback, pdata->event_callback, sizeof(struct rt5025_event_callback));
}
#endif /* #if 0 */
i2c_set_clientdata(client, chip);
mutex_init(&chip->io_lock);
rt5025_read_device(client,0x00,1,&val);
if (val != 0x81){
printk("The PMIC is not RT5025\n");
i2c_set_clientdata(client, chip);
/* off event */
rt5025_read_device(client, 0x20, 1, &val);
RTINFO("off event = %d\n", val);
rt5025_read_device(client, 0x00, 1, &val);
if (val != 0x81) {
dev_info(&client->dev, "The PMIC is not RT5025\n");
return -ENODEV;
}
ret = rt5025_core_init(chip, pdata);
if (ret < 0)
dev_err(chip->dev, "rt5025_core_init_fail\n");
else
pr_info("RT5025 Initialize successfully\n");
ret = rt5025_core_init(chip, pdata);
if (ret < 0) {
dev_err(&client->dev, "rt5025_core_init_fail\n");
goto err_init;
}
dev_info(&client->dev, "driver successfully probed\n");
if (pdata && pdata->pre_init) {
ret = pdata->pre_init(chip);
if (ret != 0) {
if (ret != 0)
dev_err(chip->dev, "pre_init() failed: %d\n", ret);
}
}
if (pdata && pdata->post_init) {
ret = pdata->post_init();
if (ret != 0) {
dev_err(chip->dev, "post_init() failed: %d\n", ret);
}
}
if (pdata && pdata->post_init) {
ret = pdata->post_init();
if (ret != 0)
dev_err(chip->dev, "post_init() failed: %d\n", ret);
}
return 0;
err_init:
return ret;
}
static int __devexit rt5025_i2c_remove(struct i2c_client *client)
static int rt5025_i2c_remove(struct i2c_client *client)
{
struct rt5025_chip *chip = i2c_get_clientdata(client);
rt5025_core_deinit(chip);
#if 0
if (chip->event_callback)
kfree(chip->event_callback);
#endif
kfree(chip);
dev_info(&client->dev, "%s\n", __func__);
return 0;
}
static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct rt5025_chip *chip = i2c_get_clientdata(client);
chip->suspend = 1;
RTINFO("\n");
return 0;
@ -295,47 +217,49 @@ static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
static int rt5025_i2c_resume(struct i2c_client *client)
{
struct rt5025_chip *chip = i2c_get_clientdata(client);
chip->suspend = 0;
RTINFO("\n");
return 0;
}
static const struct i2c_device_id rt5025_id_table[] = {
{ RT5025_DEVICE_NAME, 0 },
{ RT5025_DEV_NAME, 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, rt5025_id_table);
static struct i2c_driver rt5025_driver = {
static struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt5025",},
{},
};
static struct i2c_driver rt5025_i2c_driver = {
.driver = {
.name = RT5025_DEVICE_NAME,
.name = RT5025_DEV_NAME,
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt5025_i2c_probe,
.remove = __devexit_p(rt5025_i2c_remove),
.remove = rt5025_i2c_remove,
.suspend = rt5025_i2c_suspend,
.resume = rt5025_i2c_resume,
.id_table = rt5025_id_table,
};
static int __init rt5025_i2c_init(void)
static int rt5025_i2c_init(void)
{
int ret;
ret = i2c_add_driver(&rt5025_driver);
if (ret != 0)
pr_err("Failed to register RT5025 I2C driver: %d\n", ret);
return ret;
return i2c_add_driver(&rt5025_i2c_driver);
}
subsys_initcall_sync(rt5025_i2c_init);
static void __exit rt5025_i2c_exit(void)
static void rt5025_i2c_exit(void)
{
i2c_del_driver(&rt5025_driver);
i2c_del_driver(&rt5025_i2c_driver);
}
module_exit(rt5025_i2c_exit);
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("I2C Driver for Richtek RT5025");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
MODULE_VERSION(RT5025_DRV_VER);

428
drivers/mfd/rt5025-irq.c Normal file → Executable file
View File

@ -1,336 +1,204 @@
/*
* drivers/mfd/rt5025-irq.c
* Driver foo Richtek RT5025 PMIC irq
* Driver for Richtek RT5025 PMIC IRQ driver
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/wakelock.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/mfd/rt5025.h>
#include <linux/mfd/rt5025-irq.h>
struct rt5025_irq_info {
struct i2c_client *i2c;
struct device *dev;
struct rt5025_chip *chip;
struct workqueue_struct *wq;
struct rt5025_event_callback *event_cb;
struct delayed_work delayed_work;
struct wake_lock irq_wake_lock;
int intr_pin;
struct device *dev;
int irq;
int suspend;
int acin_cnt;
int usbin_cnt;
unsigned char suspend:1;
struct delayed_work irq_delayed_work;
};
static void rt5025_work_func(struct work_struct *work)
static irqreturn_t rt5025_irq_handler(int irqno, void *param)
{
struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work);
struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(delayed_work, struct rt5025_irq_info, delayed_work);
unsigned char irq_stat[6] = {0};
unsigned char irq_enable[6] = {0};
uint32_t chg_event = 0, pwr_event = 0;
struct rt5025_irq_info *ii = param;
unsigned char regval[6];
unsigned int irq_event = 0;
int ret = 0;
//Add this to prevent i2c xfer before i2c chip is in suspend mode
if (ii->suspend)
{
queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(1));
return;
if (ii->suspend) {
schedule_delayed_work(&ii->irq_delayed_work,
msecs_to_jiffies(10));
goto irq_fin;
}
#ifdef CONFIG_POWER_RT5025
if (!ii->chip->power_info || !ii->chip->jeita_info || !ii->chip->battery_info)
{
queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(1));
return;
ret = rt5025_reg_read(ii->i2c, RT5025_REG_IRQFLG);
if (ret < 0) {
dev_err(ii->dev, "read gauge irq event fail\n");
} else {
irq_event = ret;
RTINFO("gauge event %02x\n", irq_event);
#ifdef CONFIG_BATTERY_RT5025
if (irq_event)
rt5025_gauge_irq_handler(ii->chip->battery_info,
irq_event&(~RT5025_TALRT_MASK));
#endif /* #ifdef CONFIG_RTC_RT5025 */
}
#endif
#if 0
if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0)
{
#endif
/* backup the irq enable bit */
irq_enable[0] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN1);
irq_enable[1] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN2);
irq_enable[2] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN3);
irq_enable[3] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN4);
irq_enable[4] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN5);
irq_enable[5] = rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQEN);
#if 1
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]&(~RT5025_CHTERMI_MASK));
ret = rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 6, regval);
if (ret < 0) {
dev_err(ii->dev, "read charger irq event fail\n");
} else {
#ifdef CONFIG_BATTERY_RT5025
/*combine gauge talrt irq into charger event*/
irq_event = irq_event&RT5025_TALRT_MASK;
irq_event <<= 24;
irq_event |= (regval[1] << 16 | regval[3] << 8 | regval[5]);
#else
/* disable all irq enable bit first */
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_enable[0]&RT5025_ADAPIRQ_MASK);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, 0x00);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, 0x00);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, 0x00);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, 0x00);
rt5025_reg_write(ii->i2c, RT5025_REG_GAUGEIRQEN, 0x00);
#endif //#if 0
/* read irq status bit */
irq_stat[0] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS1);
irq_stat[1] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS2);
irq_stat[2] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS3);
irq_stat[3] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS4);
irq_stat[4] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS5);
irq_stat[5] = rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQFLG);
RTINFO("irq1->0x%02x, irq2->0x%02x, irq3->0x%02x\n", irq_stat[0], irq_stat[1], irq_stat[2]);
RTINFO("irq4->0x%02x, irq5->0x%02x, irq6->0x%02x\n", irq_stat[3], irq_stat[4], irq_stat[5]);
RTINFO("stat value = %02x\n", rt5025_reg_read(ii->i2c, RT5025_REG_CHGSTAT));
chg_event = irq_stat[0]<<16 | irq_stat[1]<<8 | irq_stat[2];
pwr_event = irq_stat[3]<<8 | irq_stat[4];
#ifdef CONFIG_POWER_RT5025
if ((chg_event & CHARGER_DETECT_MASK))
{
if (chg_event & CHG_EVENT_CHTERMI)
{
ii->chip->power_info->chg_term++;
if (ii->chip->power_info->chg_term > 3)
ii->chip->power_info->chg_term = 4;
}
if (chg_event & CHG_EVENT_CHRCHGI)
ii->chip->power_info->chg_term = 0;
if (chg_event & (CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB))
{
ii->chip->power_info->chg_term = 0;
if (chg_event & CHG_EVENT_CHSLPI_INAC)
ii->acin_cnt = 0;
if (chg_event & CHG_EVENT_CHSLPI_INUSB)
ii->usbin_cnt = 0;
}
if (chg_event & (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN))
{
RTINFO("acin_cnt %d, usbin_cnt %d\n", ii->acin_cnt, ii->usbin_cnt);
if (ii->acin_cnt == 0 && ii->usbin_cnt == 0)
{
#if 1
rt5025_charger_reset_and_reinit(ii->chip->power_info);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_enable[0]);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]&(~RT5025_CHTERMI_MASK));
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_enable[2]);
#else
rt5025_set_charging_buck(ii->i2c, 0);
mdelay(50);
rt5025_set_charging_buck(ii->i2c, 1);
mdelay(100);
rt5025_set_charging_buck(ii->i2c, 0);
mdelay(50);
rt5025_set_charging_buck(ii->i2c, 1);
mdelay(400);
#endif /* #if 1 */
}
if (chg_event & CHG_EVENT_INAC_PLUGIN)
ii->acin_cnt = 1;
if (chg_event & CHG_EVENT_INUSB_PLUGIN)
ii->usbin_cnt = 1;
RTINFO("acin_cnt %d, usbin_cnt %d\n", ii->acin_cnt, ii->usbin_cnt);
}
if (ii->chip->power_info->chg_term <= 3)
rt5025_power_charge_detect(ii->chip->power_info);
}
#endif /* CONFIG_POWER_RT5025 */
if (ii->event_cb)
{
if (chg_event)
ii->event_cb->charger_event_callback(chg_event);
if (pwr_event)
ii->event_cb->power_event_callkback(pwr_event);
}
#if 0
irq_event = regval[1] << 16 | regval[3] << 8 | regval[5];
#endif
RTINFO("chg event %08x\n", irq_event);
#ifdef CONFIG_CHARGER_RT5025
if (irq_event)
rt5025_charger_irq_handler(ii->chip->charger_info,
irq_event);
#endif /* #ifdef CONFIG_CHARGER_RT5025 */
}
else
dev_err(ii->dev, "read irq stat io fail\n");
#endif
#ifdef CONFIG_POWER_RT5025
if (irq_stat[5] & RT5025_FLG_TEMP)
rt5025_swjeita_irq_handler(ii->chip->jeita_info, irq_stat[5] & RT5025_FLG_TEMP);
if (irq_stat[5] & RT5025_FLG_VOLT)
rt5025_gauge_irq_handler(ii->chip->battery_info, irq_stat[5] & RT5025_FLG_VOLT);
#endif /* CONFIG_POWER_RT5025 */
#if 1
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]);
#else
/* restore all irq enable bit */
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_enable[0]);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_enable[2]);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, irq_enable[3]);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, irq_enable[4]);
if (rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQEN) == 0)
rt5025_reg_write(ii->i2c, RT5025_REG_GAUGEIRQEN, irq_enable[5]);
#endif //#if 0
//enable_irq(ii->irq);
}
static irqreturn_t rt5025_interrupt(int irqno, void *param)
{
struct rt5025_irq_info *ii = (struct rt5025_irq_info *)param;
//disable_irq_nosync(ii->irq);
wake_lock_timeout(&ii->irq_wake_lock, 1*HZ);
queue_delayed_work(ii->wq, &ii->delayed_work, 0);
ret = rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN4, 4, regval);
if (ret < 0) {
dev_err(ii->dev, "read misc irq event fail\n");
} else {
irq_event = regval[1] << 8 | regval[3];
RTINFO("misc event %04x\n", irq_event);
#ifdef CONFIG_MISC_RT5025
if (irq_event)
rt5025_misc_irq_handler(ii->chip->misc_info, irq_event);
#endif /* #ifdef CONFIG_MISC_RT5025 */
}
irq_fin:
return IRQ_HANDLED;
}
static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii)
static void rt5025_irq_delayed_work(struct work_struct *work)
{
int ret = 0;
struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(work,
struct rt5025_irq_info, irq_delayed_work.work);
RTINFO("\n");
ii->wq = create_workqueue("rt5025_wq");
INIT_DELAYED_WORK(&ii->delayed_work, rt5025_work_func);
#if 0
if (gpio_is_valid(ii->intr_pin))
{
ret = gpio_request(ii->intr_pin, "rt5025_interrupt");
if (ret)
return ret;
ret = gpio_direction_input(ii->intr_pin);
if (ret)
return ret;
#endif
if (request_irq(ii->irq, rt5025_interrupt, IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED, "RT5025_IRQ", ii))
{
dev_err(ii->dev, "couldn't allocate IRQ_NO(%d) !\n", ii->irq);
return -EINVAL;
}
enable_irq_wake(ii->irq);
queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(100));
#if 0
if (!gpio_get_value(ii->intr_pin))
{
//disable_irq_nosync(ii->irq);
queue_delayed_work(ii->wq, &ii->delayed_work, 0);
}
}
else
return -EINVAL;
#endif
return ret;
rt5025_irq_handler(ii->irq, ii);
}
static void __devexit rt5025_interrupt_deinit(struct rt5025_irq_info* ii)
static int rt_parse_dt(struct rt5025_irq_info *ii, struct device *dev)
{
if (ii->irq)
free_irq(ii->irq, ii);
#ifdef CONFIG_OF
struct device_node *np = dev->of_node;
int val;
if (ii->wq)
{
cancel_delayed_work_sync(&ii->delayed_work);
flush_workqueue(ii->wq);
destroy_workqueue(ii->wq);
val = of_get_named_gpio(np, "rt,irq-gpio", 0);
if (gpio_is_valid(val)) {
if (gpio_request(val, "rt5025-irq") >= 0) {
gpio_direction_input(val);
ii->irq = gpio_to_irq(val);
} else {
ii->irq = -1;
}
} else {
ii->irq = -1;
}
}
static int __devinit rt5025_irq_reg_init(struct rt5025_irq_info* ii, struct rt5025_irq_data* irq_data)
{
#endif /* #ifdef CONFIG_OF */
RTINFO("\n");
// will just enable the interrupt that we want
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_data->irq_enable1.val);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_data->irq_enable2.val);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_data->irq_enable3.val);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, irq_data->irq_enable4.val);
rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, irq_data->irq_enable5.val);
return 0;
}
static int __devinit rt5025_irq_probe(struct platform_device *pdev)
static int rt_parse_pdata(struct rt5025_irq_info *ii, struct device *dev)
{
struct rt5025_irq_data *pdata = dev->platform_data;
if (gpio_is_valid(pdata->irq_gpio)) {
if (gpio_request(pdata->irq_gpio, "rt5025-irq") >= 0) {
gpio_direction_input(pdata->irq_gpio);
ii->irq = gpio_to_irq(pdata->irq_gpio);
} else {
ii->irq = -1;
}
} else {
ii->irq = -1;
}
RTINFO("\n");
return 0;
}
static int rt5025_irq_probe(struct platform_device *pdev)
{
struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct rt5025_platform_data *pdata = chip->dev->platform_data;
struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data;
struct rt5025_irq_info *ii;
bool use_dt = pdev->dev.of_node;
int ret;
RTINFO("\n");
ii = kzalloc(sizeof(*ii), GFP_KERNEL);
ii = devm_kzalloc(&pdev->dev, sizeof(*ii), GFP_KERNEL);
if (!ii)
return -ENOMEM;
ii->i2c = chip->i2c;
ii->dev = &pdev->dev;
ii->chip = chip;
ii->intr_pin = pdata->intr_pin;
ii->irq = chip->irq;//gpio_to_irq(pdata->intr_pin);
if (pdata->cb)
ii->event_cb = pdata->cb;
wake_lock_init(&ii->irq_wake_lock, WAKE_LOCK_SUSPEND, "rt_irq_wake");
ii->dev = &pdev->dev;
if (use_dt) {
rt_parse_dt(ii, &pdev->dev);
} else {
if (!pdata)
goto out_dev;
pdev->dev.platform_data = pdata->irq_pdata;
rt_parse_pdata(ii, &pdev->dev);
dev_info(&pdev->dev, "ii->irq %d\n", ii->irq);
}
rt5025_irq_reg_init(ii, pdata->irq_data);
rt5025_interrupt_init(ii);
INIT_DELAYED_WORK(&ii->irq_delayed_work, rt5025_irq_delayed_work);
platform_set_drvdata(pdev, ii);
RTINFO("\n");
return 0;
}
static int __devexit rt5025_irq_remove(struct platform_device *pdev)
{
struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
wake_lock_destroy(&ii->irq_wake_lock);
rt5025_interrupt_deinit(ii);
platform_set_drvdata(pdev, NULL);
kfree(ii);
RTINFO("\n");
return 0;
}
static void rt5025_irq_shutdown(struct platform_device *pdev)
{
struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
if (ii->irq)
free_irq(ii->irq, ii);
if (ii->wq)
{
cancel_delayed_work_sync(&ii->delayed_work);
flush_workqueue(ii->wq);
if (ii->irq >= 0) {
ret = devm_request_irq(&pdev->dev, ii->irq, rt5025_irq_handler,
IRQF_TRIGGER_FALLING|IRQF_NO_SUSPEND, "rt5025-irq", ii);
if (ret != 0) {
dev_err(&pdev->dev, "request threaded irq fail\n");
goto out_dev;
}
enable_irq_wake(ii->irq);
schedule_delayed_work(&ii->irq_delayed_work, 1*HZ);
}
RTINFO("\n");
dev_info(&pdev->dev, "driver successfully loaded\n");
return 0;
out_dev:
return -EINVAL;
}
static int rt5025_irq_remove(struct platform_device *pdev)
{
struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
if (ii->irq >= 0)
devm_free_irq(&pdev->dev, ii->irq, ii);
return 0;
}
static int rt5025_irq_suspend(struct platform_device *pdev, pm_message_t state)
{
struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
RTINFO("\n");
ii->suspend = 1;
return 0;
}
@ -339,38 +207,42 @@ static int rt5025_irq_resume(struct platform_device *pdev)
{
struct rt5025_irq_info *ii = platform_get_drvdata(pdev);
RTINFO("\n");
ii->suspend = 0;
return 0;
}
static struct platform_driver rt5025_irq_driver =
{
static const struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt5025-irq",},
{},
};
static struct platform_driver rt5025_irq_driver = {
.driver = {
.name = RT5025_DEVICE_NAME "-irq",
.name = RT5025_DEV_NAME "-irq",
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt5025_irq_probe,
.remove = __devexit_p(rt5025_irq_remove),
.shutdown = rt5025_irq_shutdown,
.remove = rt5025_irq_remove,
.suspend = rt5025_irq_suspend,
.resume = rt5025_irq_resume,
};
static int __init rt5025_irq_init(void)
static int rt5025_irq_init(void)
{
return platform_driver_register(&rt5025_irq_driver);
}
module_init(rt5025_irq_init);
device_initcall(rt5025_irq_init);
static void __exit rt5025_irq_exit(void)
static void rt5025_irq_exit(void)
{
platform_driver_unregister(&rt5025_irq_driver);
}
module_exit(rt5025_irq_exit);
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
MODULE_DESCRIPTION("IRQ driver for RT5025");
MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-irq");
MODULE_ALIAS("platform:"RT5025_DEV_NAME "-irq");
MODULE_VERSION(RT5025_DRV_VER);

310
drivers/mfd/rt5025-misc.c Normal file → Executable file
View File

@ -2,12 +2,13 @@
* drivers/mfd/rt5025-misc.c
* Driver foo Richtek RT5025 PMIC Misc Part
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
@ -15,105 +16,306 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/power_supply.h>
#include <linux/mfd/rt5025.h>
#include <linux/mfd/rt5025-misc.h>
struct rt5025_misc_info {
struct i2c_client *i2c;
static unsigned char misc_init_regval[] = {
0x2A, /* reg 0x15 */
0x00, /* reg 0x16 */
0x60, /* reg 0x17 */
0x16, /* reg 0x19 */
0x60, /* reg 0x1A */
0x0C, /* reg 0x1B */
0xF3, /* reg 0x36 */
0x90, /* reg 0x38 */
};
static struct i2c_client *g_shdn;
void rt5025_power_off(void)
static bool rt_pm_off;
static void rt5025_power_off(void)
{
rt5025_reg_write(g_shdn, RT5025_CHENH_REG, 0x00);
rt5025_reg_write(g_shdn, RT5025_CHENL_REG, 0x80);
rt5025_set_bits(g_shdn, RT5025_SHDNCTRL_REG, RT5025_SHDNCTRL_MASK);
rt5025_reg_write(g_shdn, RT5025_REG_CHANNELH, 0x00);
rt5025_reg_write(g_shdn, RT5025_REG_CHANNELL, 0x80);
rt5025_set_bits(g_shdn, RT5025_REG_MISC3, RT5025_SHDNCTRL_MASK);
}
EXPORT_SYMBOL(rt5025_power_off);
int rt5025_cable_exist(void)
{
int ret = 0;
ret = rt5025_reg_read(g_shdn, 0x01);
if (ret < 0)
return 0;
else
{
if (ret&0x3)
return 1;
return 0;
#ifdef CONFIG_CHARGER_RT5025
struct power_supply *psy = power_supply_get_by_name("rt-charger");
union power_supply_propval pval;
if (!psy) {
pr_err(" couldn't get charger power supply\n");
} else {
ret = psy->get_property(psy,
POWER_SUPPLY_PROP_CHARGE_NOW, &pval);
if (ret < 0) {
ret = 0;
} else {
if (pval.intval > POWER_SUPPLY_TYPE_BATTERY)
ret = 1;
else
ret = 0;
}
}
#else
ret = rt5025_reg_read(g_shdn, RT5025_REG_CHGCTL1);
if (ret < 0) {
pr_err("couldn't get cable status\n");
ret = 0;
} else {
if (ret & RT5025_CABLEIN_MASK)
ret = 1;
else
ret = 0;
}
#endif /* #ifdef CONFIG_CHARGER_RT5025 */
return ret;
}
EXPORT_SYMBOL(rt5025_cable_exist);
static int __devinit rt5025_misc_reg_init(struct i2c_client *client, struct rt5025_misc_data *md)
static void rt5025_general_irq_handler(void *info, int eventno)
{
int ret = 0;
rt5025_reg_write(client, RT5025_RESETCTRL_REG, md->RSTCtrl.val);
rt5025_assign_bits(client, RT5025_VSYSULVO_REG, RT5025_VSYSOFF_MASK, md->VSYSCtrl.val);
rt5025_reg_write(client, RT5025_PWRONCTRL_REG, md->PwrOnCfg.val);
rt5025_reg_write(client, RT5025_SHDNCTRL_REG, md->SHDNCtrl.val);
rt5025_reg_write(client, RT5025_PWROFFEN_REG, md->PwrOffCond.val);
struct rt5025_misc_info *mi = info;
return ret;
RTINFO("eventno=%02d\n", eventno);
switch (eventno) {
case MISCEVENT_RESETB:
dev_warn(mi->dev, "RESETB event trigger\n");
break;
case MISCEVENT_KPSHDN:
dev_warn(mi->dev, "PwrKey force shdn\n");
break;
case MISCEVENT_SYSLV:
dev_warn(mi->dev, "syslv event trigger\n");
break;
case MISCEVENT_DCDC4LVHV:
dev_warn(mi->dev, "DCDC4LVHV event trigger\n");
break;
case MISCEVENT_DCDC3LV:
dev_warn(mi->dev, "DCDC3LV event trigger\n");
break;
case MISCEVENT_DCDC2LV:
dev_warn(mi->dev, "DCDC2LV event trigger\n");
break;
case MISCEVENT_DCDC1LV:
dev_warn(mi->dev, "DCDC2LV event trigger\n");
break;
case MISCEVENT_OT:
dev_warn(mi->dev, "Over temperature event trigger\n");
break;
default:
break;
}
}
static int __devinit rt5025_misc_probe(struct platform_device *pdev)
static rt_irq_handler rt_miscirq_handler[MISCEVENT_MAX] = {
[MISCEVENT_GPIO0_IE] = rt5025_general_irq_handler,
[MISCEVENT_GPIO1_IE] = rt5025_general_irq_handler,
[MISCEVENT_GPIO2_IE] = rt5025_general_irq_handler,
[MISCEVENT_RESETB] = rt5025_general_irq_handler,
[MISCEVENT_PWRONF] = rt5025_general_irq_handler,
[MISCEVENT_PWRONR] = rt5025_general_irq_handler,
[MISCEVENT_KPSHDN] = rt5025_general_irq_handler,
[MISCEVENT_SYSLV] = rt5025_general_irq_handler,
[MISCEVENT_DCDC4LVHV] = rt5025_general_irq_handler,
[MISCEVENT_PWRONLP_IRQ] = rt5025_general_irq_handler,
[MISCEVENT_PWRONSP_IRQ] = rt5025_general_irq_handler,
[MISCEVENT_DCDC3LV] = rt5025_general_irq_handler,
[MISCEVENT_DCDC2LV] = rt5025_general_irq_handler,
[MISCEVENT_DCDC1LV] = rt5025_general_irq_handler,
[MISCEVENT_OT] = rt5025_general_irq_handler,
};
void rt5025_misc_irq_handler(struct rt5025_misc_info *ci, unsigned int irqevent)
{
int i;
unsigned int enable_irq_event = (misc_init_regval[6] << 8) |
misc_init_regval[7];
unsigned int final_irq_event = irqevent&enable_irq_event;
for (i = 0; i < MISCEVENT_MAX; i++) {
if ((final_irq_event&(1 << i)) && rt_miscirq_handler[i])
rt_miscirq_handler[i](ci, i);
}
}
EXPORT_SYMBOL(rt5025_misc_irq_handler);
static int rt5025_misc_reginit(struct i2c_client *client)
{
rt5025_reg_write(client, RT5025_REG_MISC1, misc_init_regval[0]);
rt5025_reg_write(client, RT5025_REG_ONEVENT, misc_init_regval[1]);
rt5025_assign_bits(client, RT5025_REG_DCDCONOFF,
RT5025_VSYSOFF_MASK, misc_init_regval[2]);
rt5025_reg_write(client, RT5025_REG_MISC2, misc_init_regval[3]);
rt5025_reg_write(client, RT5025_REG_MISC3, misc_init_regval[4]);
rt5025_reg_write(client, RT5025_REG_MISC4, misc_init_regval[5]);
/*set all to be masked*/
rt5025_reg_write(client, RT5025_REG_IRQEN4, 0x00);
rt5025_reg_write(client, RT5025_REG_IRQEN5, 0x00);
/*clear the old irq status*/
rt5025_reg_read(client, RT5025_REG_IRQSTAT4);
rt5025_reg_read(client, RT5025_REG_IRQSTAT5);
/*set enable irqs as we want*/
rt5025_reg_write(client, RT5025_REG_IRQEN4, misc_init_regval[6]);
rt5025_reg_write(client, RT5025_REG_IRQEN5, misc_init_regval[7]);
return 0;
}
static int rt_parse_dt(struct rt5025_misc_info *mi, struct device *dev)
{
int rc;
#ifdef CONFIG_OF
struct device_node *np = dev->of_node;
unsigned int val;
rc = of_property_read_u32(np, "rt,vsyslv", &val);
if (rc < 0) {
dev_info(dev, "no system lv value, use default value\n");
} else {
if (val > RT5025_VOFF_MAX)
val = RT5025_VOFF_MAX;
misc_init_regval[2] &= ~RT5025_VSYSOFF_MASK;
misc_init_regval[2] |= val << RT5025_VSYSOFF_SHFT;
}
rc = of_property_read_u32(np, "rt,shdnlpress_time", &val);
if (rc < 0) {
dev_info(dev, "no shdnlpress time, use default value\n");
} else {
if (val > RT5025_SHDNPRESS_MAX)
val = RT5025_SHDNPRESS_MAX;
misc_init_regval[3] &= ~RT5025_SHDNLPRESS_MASK;
misc_init_regval[3] |= val << RT5025_SHDNLPRESS_SHFT;
}
rc = of_property_read_u32(np, "rt,startlpress_time", &val);
if (rc < 0) {
dev_err(dev, "no start_lpress, use default value\n");
} else {
if (val > RT5025_STARTIME_MAX)
val = RT5025_STARTIME_MAX;
misc_init_regval[3] &= ~RT5025_STARTLPRESS_MASK;
misc_init_regval[3] |= val << RT5025_STARTLPRESS_SHFT;
}
if (of_property_read_bool(np, "rt,vsyslv_enshdn"))
misc_init_regval[5] |= RT5025_VSYSLVSHDN_MASK;
else
misc_init_regval[5] &= ~RT5025_VSYSLVSHDN_MASK;
#endif
rt_pm_off = of_property_read_bool(np, "rt,system-power-controller");
/* #ifdef CONFIG_OF */
rc = rt5025_misc_reginit(mi->i2c);
return rc;
}
static int rt_parse_pdata(struct rt5025_misc_info *mi, struct device *dev)
{
struct rt5025_misc_data *pdata = dev->platform_data;
int rc = 0;
/*system low voltage*/
misc_init_regval[2] &= ~RT5025_VSYSOFF_MASK;
misc_init_regval[2] |= (pdata->vsyslv << RT5025_VSYSOFF_SHFT);
/*shutdown long press time*/
misc_init_regval[3] &= ~RT5025_SHDNLPRESS_MASK;
misc_init_regval[3] |= (pdata->shdnlpress_time <<
RT5025_SHDNLPRESS_SHFT);
/*start long press time*/
misc_init_regval[3] &= ~RT5025_STARTLPRESS_MASK;
misc_init_regval[3] |= (pdata->startlpress_time <<
RT5025_STARTLPRESS_SHFT);
/*systemlv enable shutdown*/
misc_init_regval[5] &= ~RT5025_VSYSLVSHDN_MASK;
misc_init_regval[5] |= (pdata->vsyslv_enshdn <<
RT5025_VSYSLVSHDN_SHFT);
rc = rt5025_misc_reginit(mi->i2c);
return rc;
}
static int rt5025_misc_probe(struct platform_device *pdev)
{
struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct rt5025_platform_data *pdata = chip->dev->platform_data;
struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data;
struct rt5025_misc_info *mi;
bool use_dt = pdev->dev.of_node;
int ret = 0;
mi = kzalloc(sizeof(*mi), GFP_KERNEL);
mi = devm_kzalloc(&pdev->dev, sizeof(*mi), GFP_KERNEL);
if (!mi)
return -ENOMEM;
mi->i2c = chip->i2c;
rt5025_misc_reg_init(mi->i2c, pdata->misc_data);
//for shutdown control
mi->dev = &pdev->dev;
if (use_dt) {
rt_parse_dt(mi, &pdev->dev);
} else {
if (!pdata) {
dev_err(&pdev->dev, "no initial platform data\n");
ret = -EINVAL;
goto err_init;
}
pdev->dev.platform_data = pdata->misc_pdata;
rt_parse_pdata(mi, &pdev->dev);
}
/*for shutdown control*/
g_shdn = chip->i2c;
if (rt_pm_off && !pm_power_off)
pm_power_off = rt5025_power_off;
platform_set_drvdata(pdev, mi);
chip->misc_info = mi;
dev_info(&pdev->dev, "driver successfully loaded\n");
return 0;
err_init:
return ret;
}
static int rt5025_misc_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "%s\n", __func__);
return 0;
}
static int __devexit rt5025_misc_remove(struct platform_device *pdev)
{
struct rt5025_misc_info *mi = platform_get_drvdata(pdev);
kfree(mi);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver rt5025_misc_driver =
{
.driver = {
.name = RT5025_DEVICE_NAME "-misc",
.owner = THIS_MODULE,
},
.probe = rt5025_misc_probe,
.remove = __devexit_p(rt5025_misc_remove),
static struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt5025-misc",},
{},
};
static int __init rt5025_misc_init(void)
static struct platform_driver rt5025_misc_driver = {
.driver = {
.name = RT5025_DEV_NAME "-misc",
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt5025_misc_probe,
.remove = rt5025_misc_remove,
};
static int rt5025_misc_init(void)
{
return platform_driver_register(&rt5025_misc_driver);
}
module_init(rt5025_misc_init);
subsys_initcall(rt5025_misc_init);
static void __exit rt5025_misc_exit(void)
static void rt5025_misc_exit(void)
{
platform_driver_unregister(&rt5025_misc_driver);
}
module_exit(rt5025_misc_exit);
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
MODULE_DESCRIPTION("Misc driver for RT5025");
MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-misc");
MODULE_ALIAS("platform:" RT5025_DEV_NAME "-misc");
MODULE_VERSION(RT5025_DRV_VER);

View File

@ -64,6 +64,43 @@ config WM8350_POWER
Say Y here to enable support for the power management unit
provided by the Wolfson Microelectronics WM8350 PMIC.
config CHARGER_RT5025
bool "RT5025 Charger Driver"
depends on MFD_RT5025
default n
help
Enable RT5025 Charger driver.
config RT_POWER
bool "RT5025 PMIC cable report"
depends on CHARGER_RT5025
default n
help
Enable AC/USB report.
config RT_SUPPORT_ACUSB_DUALIN
bool "RT AC/USB Dualin Option"
depends on RT_POWER
default n
help
Say Y here to enable dualin, otherwise
N is just singlein.
config BATTERY_RT5025
bool "RT5025 PMIC ADC Type gauge driver"
depends on MFD_RT5025
default n
help
Enable the RT5025 ADC Fuelgauge driver.
config RT_JEITA_REMOVE
bool "RT Jeita function remobe"
depends on CHARGER_RT5025 && BATTERY_RT5025
default n
help
Say Y here to remove Jeita function.
config BATTERY_RICOH619
tristate "Ricoh RC5T619 PMIC battery driver"
depends on MFD_RICOH619 && I2C && GENERIC_HARDIRQS

View File

@ -60,3 +60,6 @@ obj-$(CONFIG_BATTERY_RICOH619) += ricoh619-battery.o
obj-$(CONFIG_CHARGER_DISPLAY) += rk29_charger_display.o
obj-$(CONFIG_POWER_RESET) += reset/
obj-$(CONFIG_BATTERY_RK818) += rk818_battery.o
obj-$(CONFIG_CHARGER_RT5025) += rt5025-charger.o
obj-$(CONFIG_RT_POWER) += rt-power.o
obj-$(CONFIG_BATTERY_RT5025) += rt5025-battery.o

407
drivers/power/rt-power.c Executable file
View File

@ -0,0 +1,407 @@
/*
* drivers/power/rt-power.c
* Driver for Richtek RT PMIC Power driver
*
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/workqueue.h>
#include <linux/wakelock.h>
#include <linux/power/rt-power.h>
struct rt_power_info {
struct device *dev;
struct power_supply ac_psy;
struct power_supply usb_psy;
struct wake_lock usbdet_wakelock;
struct delayed_work usbdet_work;
int chg_volt;
int acchg_icc;
int usbtachg_icc;
int usbchg_icc;
unsigned char ac_online:1;
unsigned char usbta_online:1;
unsigned char usb_online:1;
unsigned char suspend:1;
unsigned char usbcnt;
};
#define RT_USBCNT_MAX 60
static char *rtpower_supply_list[] = {
"battery",
};
static enum power_supply_property rtpower_props[] = {
POWER_SUPPLY_PROP_ONLINE,
};
static int rtpower_set_charger(struct rt_power_info *pi)
{
struct power_supply *chg_psy;
union power_supply_propval pval;
int rc = 0, is_chg_on = 0;
chg_psy = power_supply_get_by_name("rt-charger");
if (chg_psy) {
rc = chg_psy->get_property(chg_psy, POWER_SUPPLY_PROP_ONLINE, &pval);
if (rc < 0)
dev_err(pi->dev, "get chg online prop fail\n");
else
is_chg_on = pval.intval;
if (pi->ac_online) {
pval.intval = pi->acchg_icc;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set acchg aicr fail\n");
pval.intval = 500;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set acchg icc fail\n");
pval.intval = POWER_SUPPLY_TYPE_MAINS;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charge cable fail\n");
if (!is_chg_on) {
pval.intval = pi->chg_volt;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set chg voltage fail\n");
pval.intval = 1;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger online fail\n");
}
pval.intval = 1;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger present fail\n");
} else if (pi->usbta_online) {
pval.intval = pi->usbtachg_icc;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set usbtachg aicr fail\n");
pval.intval = 500;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set usbtachg icc fail\n");
pval.intval = POWER_SUPPLY_TYPE_USB_DCP;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charge cable fail\n");
if (!is_chg_on) {
pval.intval = pi->chg_volt;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set chg voltage fail\n");
pval.intval = 1;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger online fail\n");
}
pval.intval = 1;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger present fail\n");
} else if (pi->usb_online) {
pval.intval = pi->usbchg_icc;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set usbchg aicr fail\n");
pval.intval = 500;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set usbchg icc fail\n");
pval.intval = POWER_SUPPLY_TYPE_USB;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charge cable fail\n");
if (!is_chg_on) {
pval.intval = pi->chg_volt;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set chg voltage fail\n");
pval.intval = 1;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger online fail\n");
}
pval.intval = 1;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger present fail\n");
} else {
pval.intval = 0;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charger online fail\n");
pval.intval = 0;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set charge cable fail\n");
pval.intval = pi->chg_volt;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set chg voltage fail\n");
pval.intval = 500;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set chg aicr fail\n");
pval.intval = 500;
rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\
&pval);
if (rc < 0)
dev_err(pi->dev, "set chg icc fail\n");
}
power_supply_changed(chg_psy);
} else {
rc = -EINVAL;
dev_err(pi->dev, "cannot get rt-charger psy\n");
}
return rc;
}
static int rtpower_get_property(struct power_supply *psy, enum power_supply_property psp, \
union power_supply_propval *val)
{
struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent);
int rc = 0;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
if (psy->type == POWER_SUPPLY_TYPE_MAINS)
val->intval = (pi->ac_online || pi->usbta_online)?1 : 0;
else if (psy->type == POWER_SUPPLY_TYPE_USB)
val->intval = pi->usb_online;
else
rc = -EINVAL;
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
static int rtpower_set_property(struct power_supply *psy, enum power_supply_property psp, \
const union power_supply_propval *val)
{
struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent);
int rc = 0;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
if (pi->ac_online != val->intval) {
pi->ac_online = val->intval;
rc = rtpower_set_charger(pi);
}
} else if (psy->type == POWER_SUPPLY_TYPE_USB) {
if (pi->usb_online != val->intval) {
pi->usb_online = val->intval;
if (val->intval) {
pi->usbcnt = 0;
wake_lock(&pi->usbdet_wakelock);
schedule_delayed_work(&pi->usbdet_work, 1*HZ);
} else {
pi->usbcnt = RT_USBCNT_MAX;
schedule_delayed_work(&pi->usbdet_work, 0);
if (pi->usbta_online) {
pi->usbta_online = 0;
power_supply_changed(&pi->ac_psy);
}
}
rc = rtpower_set_charger(pi);
}
} else {
rc = -EINVAL;
}
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
extern int dwc_otg_check_dpdm(bool wait);
static void usbdet_work_func(struct work_struct *work)
{
struct rt_power_info *pi = container_of(work, struct rt_power_info, \
usbdet_work.work);
int usb_det = dwc_otg_check_dpdm(0);
switch (usb_det) {
case 2:
dev_info(pi->dev, "usb ta checked\n");
if (pi->usb_online) {
pi->usbta_online = 1;
rtpower_set_charger(pi);
power_supply_changed(&pi->ac_psy);
}
pi->usbcnt = RT_USBCNT_MAX;
break;
case 1:
case 0:
dev_info(pi->dev, "normal usb\n");
break;
default:
break;
}
if (pi->usbcnt < RT_USBCNT_MAX) {
pi->usbcnt++;
schedule_delayed_work(&pi->usbdet_work, 1*HZ);
} else {
wake_unlock(&pi->usbdet_wakelock);
}
}
static int rt_power_probe(struct platform_device *pdev)
{
struct rt_power_info *pi;
struct rt_power_data *rt_power_pdata = pdev->dev.platform_data;
int ret = 0;
pi = devm_kzalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL);
if (!pi)
return -ENOMEM;
pi->dev = &pdev->dev;
wake_lock_init(&pi->usbdet_wakelock, WAKE_LOCK_SUSPEND, "rt-usb-det");
INIT_DELAYED_WORK(&pi->usbdet_work, usbdet_work_func);
pi->chg_volt = rt_power_pdata->chg_volt;
pi->acchg_icc = rt_power_pdata->acchg_icc;
pi->usbtachg_icc = rt_power_pdata->usbtachg_icc;
pi->usbchg_icc = rt_power_pdata->usbchg_icc;
platform_set_drvdata(pdev, pi);
/* ac power supply register*/
pi->ac_psy.name = RT_AC_NAME;
pi->ac_psy.type = POWER_SUPPLY_TYPE_MAINS;
pi->ac_psy.supplied_to = rtpower_supply_list;
pi->ac_psy.properties = rtpower_props;
pi->ac_psy.num_properties = ARRAY_SIZE(rtpower_props);
pi->ac_psy.get_property = rtpower_get_property;
pi->ac_psy.set_property = rtpower_set_property;
ret = power_supply_register(&pdev->dev, &pi->ac_psy);
if (ret < 0) {
dev_err(&pdev->dev, " create ac power supply fail\n");
goto err_init;
}
/*usb power supply register*/
pi->usb_psy.name = RT_USB_NAME;
pi->usb_psy.type = POWER_SUPPLY_TYPE_USB;
pi->usb_psy.supplied_to = rtpower_supply_list;
pi->usb_psy.properties = rtpower_props;
pi->usb_psy.num_properties = ARRAY_SIZE(rtpower_props);
pi->usb_psy.get_property = rtpower_get_property;
pi->usb_psy.set_property = rtpower_set_property;
ret = power_supply_register(&pdev->dev, &pi->usb_psy);
if (ret < 0) {
dev_err(&pdev->dev, " create usb power supply fail\n");
goto err_acpsy;
}
return 0;
err_acpsy:
power_supply_unregister(&pi->ac_psy);
err_init:
wake_lock_destroy(&pi->usbdet_wakelock);
return ret;
}
static int rt_power_remove(struct platform_device *pdev)
{
struct rt_power_info *pi = platform_get_drvdata(pdev);
power_supply_unregister(&pi->usb_psy);
power_supply_unregister(&pi->ac_psy);
wake_lock_destroy(&pi->usbdet_wakelock);
return 0;
}
static int rt_power_suspend(struct platform_device *pdev, pm_message_t state)
{
struct rt_power_info *pi = platform_get_drvdata(pdev);
pi->suspend = 1;
return 0;
}
static int rt_power_resume(struct platform_device *pdev)
{
struct rt_power_info *pi = platform_get_drvdata(pdev);
pi->suspend = 0;
return 0;
}
static const struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt-power",},
{},
};
static struct platform_driver rt_power_driver = {
.driver = {
.name = "rt-power",
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt_power_probe,
.remove = rt_power_remove,
.suspend = rt_power_suspend,
.resume = rt_power_resume,
};
static int rt_power_init(void)
{
return platform_driver_register(&rt_power_driver);
}
subsys_initcall(rt_power_init);
static void rt_power_exit(void)
{
platform_driver_unregister(&rt_power_driver);
}
module_exit(rt_power_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("RT Power driver");
MODULE_ALIAS("platform:rt-power");
MODULE_VERSION("1.0.0_G");

2470
drivers/power/rt5025-battery.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

1224
drivers/power/rt5025-charger.c Executable file

File diff suppressed because it is too large Load Diff

0
drivers/power/rt5025-power.c Normal file → Executable file
View File

330
drivers/power/rt5025-swjeita.c Normal file → Executable file
View File

@ -22,11 +22,12 @@
#include <linux/mfd/rt5025.h>
#include <linux/power/rt5025-swjeita.h>
#define TEMP_TOLERANCE 30 // 'c*10 gap for tolerance
#define TEMP_TOLERANCE 30 /*'c*10 gap for tolerance*/
static int rt5025_set_charging_cc_switch (struct i2c_client *i2c, int onoff)
{
int ret;
RTINFO("onoff = %d\n", onoff);
if (onoff)
ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCCEN_MASK);
@ -44,9 +45,9 @@ static int rt5025_set_charging_cc(struct i2c_client *i2c, int cur_value)
if (cur_value < 500)
data = 0;
else if (cur_value > 2000)
data = 0xf<<RT5025_CHGICC_SHIFT;
data = 0xf << RT5025_CHGICC_SHIFT;
else
data = ((cur_value-500)/100)<<RT5025_CHGICC_SHIFT;
data = ((cur_value - 500) / 100) << RT5025_CHGICC_SHIFT;
ret = rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGICC_MASK, data);
@ -67,9 +68,9 @@ static int rt5025_set_charging_cv(struct i2c_client *i2c, int voltage)
if (voltage < 3500)
data = 0;
else if (voltage > 4440)
data = 0x2f<<RT5025_CHGCV_SHIFT;
data = 0x2f << RT5025_CHGCV_SHIFT;
else
data = ((voltage-3500)/20)<<RT5025_CHGCV_SHIFT;
data = ((voltage - 3500) / 20) << RT5025_CHGCV_SHIFT;
ret = rt5025_assign_bits(i2c, RT5025_REG_CHGCTL3, RT5025_CHGCV_MASK, data);
return ret;
@ -101,53 +102,52 @@ static int rt5025_get_external_temp_index(struct rt5025_swjeita_info *swji)
u8 data[2];
long int temp;
int sect_index;
RTINFO("\n");
if (rt5025_reg_block_read(swji->i2c, RT5025_REG_AINH, 2, data) < 0)
pr_err("%s: failed to read ext_temp register\n", __func__);
temp = (data[0]*256+data[1])*61/100;
temp = (temp * (-91738) +81521000)/100000;
temp = (data[0] * 256 + data[1]) * 61 / 100;
temp = (temp * (-91738) + 81521000) / 100000;
swji->cur_temp = temp;
RTINFO("cur_section = %d, cur_temp = %d\n", swji->cur_section, swji->cur_temp);
switch (swji->cur_section)
{
case 0:
if (temp < swji->temp[0]+TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 1:
if (temp <= swji->temp[0]-TEMP_TOLERANCE || temp >= swji->temp[1]+TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 2:
if (temp <= swji->temp[1]-TEMP_TOLERANCE || temp >= swji->temp[2]+TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 3:
if (temp <= swji->temp[2]-TEMP_TOLERANCE || temp >= swji->temp[3]+TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 4:
if (temp <= swji->temp[3]-TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
default:
sect_index = swji->cur_section;
break;
switch (swji->cur_section) {
case 0:
if (temp < swji->temp[0] + TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 1:
if (temp <= swji->temp[0] - TEMP_TOLERANCE || temp >= swji->temp[1] + TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 2:
if (temp <= swji->temp[1] - TEMP_TOLERANCE || temp >= swji->temp[2] + TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 3:
if (temp <= swji->temp[2] - TEMP_TOLERANCE || temp >= swji->temp[3] + TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
case 4:
if (temp <= swji->temp[3] - TEMP_TOLERANCE)
sect_index = rt5025_sel_external_temp_index(swji);
else
sect_index = swji->cur_section;
break;
default:
sect_index = swji->cur_section;
break;
}
RTINFO("sect_index = %d\n", sect_index);
return sect_index;
@ -185,26 +185,25 @@ static int rt5025_set_exttemp_alert(struct rt5025_swjeita_info *swji, int index)
RTINFO("index = %d\n", index);
switch (index)
{
case 0:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[1]);
break;
case 1:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[0]);
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[3]);
break;
case 2:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[2]);
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[5]);
break;
case 3:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[4]);
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[7]);
break;
case 4:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[6]);
break;
switch (index) {
case 0:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[1]);
break;
case 1:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[0]);
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[3]);
break;
case 2:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[2]);
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[5]);
break;
case 3:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[4]);
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[7]);
break;
case 4:
rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[6]);
break;
}
return ret;
@ -212,38 +211,34 @@ static int rt5025_set_exttemp_alert(struct rt5025_swjeita_info *swji, int index)
static int rt5025_exttemp_alert_switch(struct rt5025_swjeita_info *swji, int onoff)
{
if (!onoff)
{
if (!onoff) {
rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
}
else
{
switch (swji->cur_section)
{
case 0:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 1:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 2:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 3:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 4:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
break;
} else {
switch (swji->cur_section) {
case 0:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 1:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 2:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 3:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK);
break;
case 4:
rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK);
break;
}
}
RTINFO("index=%d, onoff=%d\n", swji->cur_section, onoff);
return 0;
return 0;
}
int rt5025_notify_charging_cable(struct rt5025_swjeita_info *swji, int cable_type)
@ -256,34 +251,32 @@ int rt5025_notify_charging_cable(struct rt5025_swjeita_info *swji, int cable_typ
rt5025_exttemp_alert_switch(swji, 0);
sect_index = rt5025_get_external_temp_index(swji);
if (swji->cur_section != sect_index || swji->init_once == 0)
{
if (swji->cur_section != sect_index || swji->init_once == 0) {
rt5025_set_exttemp_alert(swji, sect_index);
swji->cur_section = sect_index;
swji->init_once = 1;
}
switch (cable_type)
{
case JEITA_NORMAL_USB:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\
- swji->dec_current);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
case JEITA_USB_TA:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\
- swji->dec_current);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
case JEITA_AC_ADAPTER:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\
- swji->dec_current);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
case JEITA_NO_CHARGE:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
switch (cable_type) {
case JEITA_NORMAL_USB:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\
- swji->dec_current);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
case JEITA_USB_TA:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\
- swji->dec_current);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
case JEITA_AC_ADAPTER:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\
- swji->dec_current);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
case JEITA_NO_CHARGE:
rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]);
rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]);
break;
}
swji->cur_cable = cable_type;
@ -298,7 +291,7 @@ int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *swji, unsigned char e
int ret = 0;
RTINFO("event = 0x%02x\n", event);
if (event&(RT5025_TMXEN_MASK|RT5025_TMNEN_MASK))
if (event&(RT5025_TMXEN_MASK | RT5025_TMNEN_MASK))
rt5025_notify_charging_cable(swji, swji->cur_cable);
return ret;
@ -309,54 +302,51 @@ static void rt5025_get_internal_temp(struct rt5025_swjeita_info *swji)
{
u8 data[2];
s32 temp;
if (rt5025_reg_block_read(swji->i2c, RT5025_REG_INTTEMP_MSB, 2, data) < 0){
if (rt5025_reg_block_read(swji->i2c, RT5025_REG_INTTEMP_MSB, 2, data) < 0)
pr_err("%s: Failed to read internal TEMPERATURE\n", __func__);
}
temp = ((data[0]&0x1F)<<8) + data[1];
temp = ((data[0] & 0x1F) << 8) + data[1];
temp *= 15625;
temp /= 100000;
temp = (data[0]&0x20)?-temp:temp;
temp = (data[0] & 0x20) ? -temp : temp;
swji->cur_inttemp = temp;
RTINFO("internal temperature: %d\n", temp);
}
static void thermal_reg_work_func(struct work_struct *work)
{
struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work);
struct rt5025_swjeita_info *swji = (struct rt5025_swjeita_info *)container_of(delayed_work, struct rt5025_swjeita_info, thermal_reg_work);
int therm_region = 0;
RTINFO("%s ++", __func__);
rt5025_get_internal_temp(swji);
#if 1
switch (swji->cur_therm_region)
{
case 0:
if (swji->cur_inttemp >=820)
therm_region = 1;
else
therm_region = 0;
break;
case 1:
if (swji->cur_inttemp <= 780)
therm_region = 0;
else if (swji->cur_inttemp >= 1020)
therm_region = 2;
else
therm_region = 1;
break;
case 2:
if (swji->cur_inttemp <= 980)
therm_region = 1;
else
therm_region = 2;
break;
}
switch (swji->cur_therm_region) {
case 0:
if (swji->cur_inttemp >= 820)
therm_region = 1;
else
therm_region = 0;
break;
case 1:
if (swji->cur_inttemp <= 780)
therm_region = 0;
else if (swji->cur_inttemp >= 1020)
therm_region = 2;
else
therm_region = 1;
break;
case 2:
if (swji->cur_inttemp <= 980)
therm_region = 1;
else
therm_region = 2;
break;
}
#else
if (swji->cur_inttemp < 800)
therm_region = 0;
@ -366,19 +356,17 @@ static void thermal_reg_work_func(struct work_struct *work)
therm_region = 2;
#endif /* #if 1*/
if (therm_region != swji->cur_therm_region)
{
switch (therm_region)
{
case 0:
swji->dec_current = 0;
break;
case 1:
swji->dec_current = 300;
break;
case 2:
swji->dec_current = 800;
break;
if (therm_region != swji->cur_therm_region) {
switch (therm_region) {
case 0:
swji->dec_current = 0;
break;
case 1:
swji->dec_current = 300;
break;
case 2:
swji->dec_current = 800;
break;
}
swji->cur_therm_region = therm_region;
rt5025_notify_charging_cable(swji, swji->cur_cable);
@ -390,10 +378,10 @@ static void thermal_reg_work_func(struct work_struct *work)
RTINFO("%s --", __func__);
}
static int __devinit rt5025_swjeita_probe(struct platform_device *pdev)
static int rt5025_swjeita_probe(struct platform_device *pdev)
{
struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct rt5025_platform_data *pdata = chip->dev->platform_data;
struct rt5025_platform_data *pdata = chip->dev->platform_data;
struct rt5025_swjeita_info *swji;
int ret = 0;
@ -401,23 +389,20 @@ static int __devinit rt5025_swjeita_probe(struct platform_device *pdev)
if (!swji)
return -ENOMEM;
#if 0 // for debug pdata->jeita_data
for (ret=0; ret<4; ret++)
#if 0 /* for debug pdata->jeita_data*/
for (ret = 0; ret < 4; ret++)
RTINFO("jeita temp value %d\n", pdata->jeita_data->temp[ret]);
for (ret=0; ret<4; ret++)
{
for (ret = 0; ret < 4; ret++) {
RTINFO("jeita temp_cc value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cc[ret][0], \
pdata->jeita_data->temp_cc[ret][1], pdata->jeita_data->temp_cc[ret][2], \
pdata->jeita_data->temp_cc[ret][3], pdata->jeita_data->temp_cc[ret][4]);
}
for (ret=0; ret<4; ret++)
{
for (ret = 0; ret < 4; ret++) {
RTINFO("jeita temp_cv value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cv[ret][0], \
pdata->jeita_data->temp_cv[ret][1], pdata->jeita_data->temp_cv[ret][2], \
pdata->jeita_data->temp_cv[ret][3], pdata->jeita_data->temp_cv[ret][4]);
}
for (ret=0; ret<8; ret++)
{
for (ret = 0; ret < 8; ret++) {
RTINFO("temp_scalar[%d] = 0x%02x\n", ret, pdata->jeita_data->temp_scalar[ret]);
}
ret = 0;
@ -425,7 +410,8 @@ static int __devinit rt5025_swjeita_probe(struct platform_device *pdev)
swji->i2c = chip->i2c;
swji->chip = chip;
swji->cur_section = 2; //initial as the normal temperature
swji->cur_section = 2;
/*initial as the normal temperature*/
swji->cur_cable = JEITA_NO_CHARGE;
swji->temp = pdata->jeita_data->temp;
swji->temp_scalar = pdata->jeita_data->temp_scalar;
@ -445,7 +431,7 @@ static int __devinit rt5025_swjeita_probe(struct platform_device *pdev)
return ret;
}
static int __devexit rt5025_swjeita_remove(struct platform_device *pdev)
static int rt5025_swjeita_remove(struct platform_device *pdev)
{
struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev);
@ -458,6 +444,7 @@ static int __devexit rt5025_swjeita_remove(struct platform_device *pdev)
static int rt5025_swjeita_suspend(struct platform_device *pdev, pm_message_t state)
{
struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev);
swji->suspend = 1;
cancel_delayed_work_sync(&swji->thermal_reg_work);
swji->cur_therm_region = swji->dec_current = 0;
@ -476,8 +463,7 @@ static int rt5025_swjeita_resume(struct platform_device *pdev)
return 0;
}
static struct platform_driver rt5025_swjeita_driver =
{
static struct platform_driver rt5025_swjeita_driver = {
.driver = {
.name = RT5025_DEVICE_NAME "-swjeita",
.owner = THIS_MODULE,
@ -488,13 +474,13 @@ static struct platform_driver rt5025_swjeita_driver =
.resume = rt5025_swjeita_resume,
};
static int __init rt5025_swjeita_init(void)
static int rt5025_swjeita_init(void)
{
return platform_driver_register(&rt5025_swjeita_driver);
}
module_init(rt5025_swjeita_init);
static void __exit rt5025_swjeita_exit(void)
static void rt5025_swjeita_exit(void)
{
platform_driver_unregister(&rt5025_swjeita_driver);
}

View File

@ -262,6 +262,13 @@ config ACT8846_SUPPORT_RESET
help
Support short press key to restart.
config REGULATOR_RT5025
bool "Richtek RT5025 PMIC Voltage regulstors"
depends on MFD_RT5025
default n
help
This driver supports voltage regulator in RT5025 PMIC chips.
config ROCKCHIP_PWM_REGULATOR
tristate "rockchip pwm voltage regulator for discrete dcdc or ldo"
help

View File

@ -76,6 +76,7 @@ obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
obj-$(CONFIG_REGULATOR_SYR82X) += syr82x.o
obj-$(CONFIG_REGULATOR_RICOH619) += ricoh619-regulator.o
obj-$(CONFIG_REGULATOR_RT5025) += rt5025-regulator.o
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip_io_vol_domain.o

View File

@ -2,12 +2,13 @@
* drivers/regulator/rt5025-regulator.c
* Driver foo Richtek RT5025 PMIC Regulator
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include <linux/module.h>
@ -18,6 +19,10 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/driver.h>
#include <linux/version.h>
#ifdef CONFIG_OF
#include <linux/regulator/of_regulator.h>
#endif /* #ifdef CONFIG_OF */
#include <linux/mfd/rt5025.h>
#include <linux/regulator/rt5025-regulator.h>
@ -25,7 +30,6 @@ struct rt5025_regulator_info {
struct regulator_desc desc;
struct regulator_dev *regulator;
struct i2c_client *i2c;
struct rt5025_chip *chip;
const unsigned int *vol_output_list;
const int vol_output_size;
int min_uV;
@ -37,11 +41,12 @@ struct rt5025_regulator_info {
int enable_reg;
int mode_bit;
int mode_reg;
int ramp_bit;
int ramp_reg;
};
//for DCDC1
static const unsigned int rt5025_vol_output_list1[] =
{
/*for DCDC1*/
static const unsigned int rt5025_vol_output_list1[] = {
700*1000, 725*1000, 750*1000, 775*1000, 800*1000, 825*1000, 850*1000, 875*1000,
900*1000, 925*1000, 950*1000, 975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000,
1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000,
@ -53,9 +58,8 @@ static const unsigned int rt5025_vol_output_list1[] =
};
#define rt5025_vol_output_size1 ARRAY_SIZE(rt5025_vol_output_list1)
//DCDC2, LDO1, LDO2
static const unsigned int rt5025_vol_output_list2[] =
{
/*DCDC2, LDO1, LDO2*/
static const unsigned int rt5025_vol_output_list2[] = {
700*1000, 725*1000, 750*1000, 775*1000, 800*1000, 825*1000, 850*1000, 875*1000,
900*1000, 925*1000, 950*1000, 975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000,
1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000,
@ -75,9 +79,8 @@ static const unsigned int rt5025_vol_output_list2[] =
};
#define rt5025_vol_output_size2 ARRAY_SIZE(rt5025_vol_output_list2)
//DCDC3
static const unsigned int rt5025_vol_output_list3[] =
{
/*DCDC3*/
static const unsigned int rt5025_vol_output_list3[] = {
700*1000, 750*1000, 800*1000, 850*1000, 900*1000, 950*1000, 1000*1000, 1050*1000,
1100*1000, 1150*1000, 1200*1000, 1250*1000, 1300*1000, 1350*1000, 1400*1000, 1450*1000,
1500*1000, 1550*1000, 1600*1000, 1650*1000, 1700*1000, 1750*1000, 1800*1000, 1850*1000,
@ -89,17 +92,15 @@ static const unsigned int rt5025_vol_output_list3[] =
};
#define rt5025_vol_output_size3 ARRAY_SIZE(rt5025_vol_output_list3)
//DCDC4
static const unsigned int rt5025_vol_output_list4[] =
{
/*DCDC4*/
static const unsigned int rt5025_vol_output_list4[] = {
4500*1000, 4600*1000, 4700*1000, 4800*1000, 4900*1000, 5000*1000, 5100*1000, 5200*1000,
5300*1000, 5400*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000,
};
#define rt5025_vol_output_size4 ARRAY_SIZE(rt5025_vol_output_list4)
//LDO3, LDO4, LDO5, LDO6
static const unsigned int rt5025_vol_output_list5[] =
{
/*LDO3, LDO4, LDO5, LDO6*/
static const unsigned int rt5025_vol_output_list5[] = {
1000*1000, 1100*1000, 1200*1000, 1300*1000, 1400*1000, 1500*1000, 1600*1000, 1700*1000,
1800*1000, 1900*1000, 2000*1000, 2100*1000, 2200*1000, 2300*1000, 2400*1000, 2500*1000,
2600*1000, 2700*1000, 2800*1000, 2900*1000, 3000*1000, 3100*1000, 3200*1000, 3300*1000,
@ -121,29 +122,29 @@ static int rt5025_list_voltage(struct regulator_dev *rdev, unsigned index)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
return (index>=info->vol_output_size)? \
-EINVAL: \
info->vol_output_list[index];
return (index >= info->vol_output_size) ? -EINVAL : info->vol_output_list[index];
}
#if 0 //(LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38))
static int rt5025_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data;
const int count = info->vol_output_size;
if (selector>count)
if (selector > count)
return -EINVAL;
data = (unsigned char)selector;
data <<= info->vol_shift;
return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data);
return rt5025_assign_bits(info->i2c, info->vol_reg,
info->vol_mask, data);
}
static int rt5025_get_voltage_sel(struct regulator_dev *rdev)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
ret = rt5025_reg_read(info->i2c, info->vol_reg);
if (ret < 0)
return ret;
@ -154,12 +155,12 @@ static int rt5025_find_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
int i=0;
int i = 0;
const int count = info->vol_output_size;
for (i=0;i<count;i++)
{
if ((info->vol_output_list[i]>=min_uV)
&& (info->vol_output_list[i]<=max_uV))
for (i = 0; i < count; i++) {
if ((info->vol_output_list[i] >= min_uV)
&& (info->vol_output_list[i] <= max_uV))
return i;
}
return -EINVAL;
@ -167,20 +168,20 @@ static int rt5025_find_voltage(struct regulator_dev *rdev,
static int rt5025_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV, unsigned *selector)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data;
if (check_range(info, min_uV, max_uV)) {
dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n",
dev_err(&rdev->dev, "invalid voltage range (%d, %d) uV\n",
min_uV, max_uV);
return -EINVAL;
}
data = rt5025_find_voltage(rdev,min_uV,max_uV);
data = rt5025_find_voltage(rdev, min_uV, max_uV);
data <<= info->vol_shift;
return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data);
return rt5025_assign_bits(info->i2c, info->vol_reg,
info->vol_mask, data);
}
@ -188,6 +189,7 @@ static int rt5025_get_voltage(struct regulator_dev *rdev)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
ret = rt5025_reg_read(info->i2c, info->vol_reg);
if (ret < 0)
return ret;
@ -220,29 +222,29 @@ static int rt5025_is_enabled(struct regulator_dev *rdev)
ret = rt5025_reg_read(info->i2c, info->enable_reg);
if (ret < 0)
return ret;
return (ret & (info->enable_bit))?1:0;
return (ret & (info->enable_bit))?1 : 0;
}
static int rt5025_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct rt5025_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
if (!info->mode_bit)
if (!info->mode_bit) {
ret = 0;
else
{
switch (mode)
{
case REGULATOR_MODE_NORMAL:
ret = rt5025_set_bits(info->i2c, info->mode_reg, info->mode_bit);
break;
case REGULATOR_MODE_FAST:
ret = rt5025_clr_bits(info->i2c, info->mode_reg, info->mode_bit);
break;
default:
ret = -EINVAL;
break;
} else {
switch (mode) {
case REGULATOR_MODE_NORMAL:
ret = rt5025_set_bits(info->i2c, info->mode_reg,
info->mode_bit);
break;
case REGULATOR_MODE_FAST:
ret = rt5025_clr_bits(info->i2c, info->mode_reg,
info->mode_bit);
break;
default:
ret = -EINVAL;
break;
}
}
return ret;
@ -254,19 +256,18 @@ static unsigned int rt5025_get_mode(struct regulator_dev *rdev)
unsigned int mode;
int data;
if (!info->mode_bit)
if (!info->mode_bit) {
mode = REGULATOR_MODE_NORMAL;
else
{
} else {
data = rt5025_reg_read(info->i2c, info->mode_reg);
mode = (data & info->mode_bit)?REGULATOR_MODE_NORMAL:REGULATOR_MODE_FAST;
mode = (data & info->mode_bit)?REGULATOR_MODE_NORMAL : REGULATOR_MODE_FAST;
}
return mode;
}
static struct regulator_ops rt5025_regulator_ops = {
.list_voltage = rt5025_list_voltage,
#if 0 //(LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38))
.get_voltage_sel = rt5025_get_voltage_sel,
.set_voltage_sel = rt5025_set_voltage_sel,
#else
@ -306,24 +307,26 @@ static struct regulator_ops rt5025_regulator_ops = {
#define RT5025_DCDC(_id, min, max) \
{ \
.desc = { \
.name = "rt5025-dcdc" #_id, \
.name = "rt5025-dcdc" #_id, \
.n_voltages = RT5025_DCDCVOUT_SIZE##_id, \
.ops = &rt5025_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = RT5025_ID_DCDC##_id, \
.owner = THIS_MODULE, \
}, \
.vol_output_list= RT5025_DCDCVOUT_LIST##_id, \
.vol_output_size= RT5025_DCDCVOUT_SIZE##_id, \
.min_uV = min , \
.max_uV = max , \
.vol_output_list = RT5025_DCDCVOUT_LIST##_id, \
.vol_output_size = RT5025_DCDCVOUT_SIZE##_id, \
.min_uV = min * 1000, \
.max_uV = max * 1000, \
.vol_reg = RT5025_DCDCVOUT##_id, \
.vol_shift = RT5025_DCDCVOUT_SHIFT##_id, \
.vol_mask = RT5025_DCDCVOUT_MASK##_id, \
.enable_reg = RT5025_DCDC_OUTPUT_EN, \
.enable_reg = RT5025_REG_DCDCONOFF, \
.enable_bit = RT5025_DCDCEN_MASK##_id, \
.mode_reg = RT5025_REG_DCDCVRC, \
.mode_bit = RT5025_DCDCMODE_MASK##_id \
.mode_reg = RT5025_DCDCMODE_REG##_id, \
.mode_bit = RT5025_DCDCMODE_MASK##_id, \
.ramp_reg = RT5025_DCDCVOUT##_id, \
.ramp_bit = RT5025_DCDCRAMP_MASK##_id, \
}
#define RT5025_LDO(_id, min, max) \
@ -336,34 +339,31 @@ static struct regulator_ops rt5025_regulator_ops = {
.id = RT5025_ID_LDO##_id, \
.owner = THIS_MODULE, \
}, \
.vol_output_list= RT5025_LDOVOUT_LIST##_id, \
.vol_output_size= RT5025_LDOVOUT_SIZE##_id, \
.min_uV = min , \
.max_uV = max, \
.vol_output_list = RT5025_LDOVOUT_LIST##_id, \
.vol_output_size = RT5025_LDOVOUT_SIZE##_id, \
.min_uV = min * 1000, \
.max_uV = max * 1000, \
.vol_reg = RT5025_LDOVOUT##_id, \
.vol_shift = RT5025_LDOVOUT_SHIFT##_id, \
.vol_mask = RT5025_LDOVOUT_MASK##_id, \
.enable_reg = RT5025_LDO_OUTPUT_EN, \
.enable_reg = RT5025_REG_LDOONOFF, \
.enable_bit = RT5025_LDOEN_MASK##_id, \
.mode_reg = RT5025_REG_LDOVRC, \
.mode_bit = RT5025_LDOMODE_MASK##_id, \
}
static struct rt5025_regulator_info rt5025_regulator_info[] =
{
RT5025_DCDC(1, 700000, 2275000),
RT5025_DCDC(2, 700000, 3500000),
RT5025_DCDC(3, 700000, 3500000),
RT5025_DCDC(4, 4500000, 5500000),
RT5025_LDO( 1, 700000, 3500000),
RT5025_LDO( 2, 700000, 3500000),
RT5025_LDO( 3, 1000000, 3300000),
RT5025_LDO( 4, 1000000, 3300000),
RT5025_LDO( 5, 1000000, 3300000),
RT5025_LDO( 6, 1000000, 3300000),
static struct rt5025_regulator_info rt5025_regulator_info[] = {
RT5025_DCDC(1, 700, 2275),
RT5025_DCDC(2, 700, 3500),
RT5025_DCDC(3, 700, 3500),
RT5025_DCDC(4, 4500, 5500),
RT5025_LDO(1, 700, 3500),
RT5025_LDO(2, 700, 3500),
RT5025_LDO(3, 1000, 3300),
RT5025_LDO(4, 1000, 3300),
RT5025_LDO(5, 1000, 3300),
RT5025_LDO(6, 1000, 3300),
};
static struct rt5025_regulator_info * __devinit find_regulator_info(int id)
static struct rt5025_regulator_info *find_regulator_info(int id)
{
struct rt5025_regulator_info *ri;
int i;
@ -375,43 +375,87 @@ static struct rt5025_regulator_info * __devinit find_regulator_info(int id)
}
return NULL;
}
inline struct regulator_dev* rt5025_regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, struct regulator_init_data *init_data,
void *driver_data)
struct regulator_dev *rt5025_regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, struct regulator_init_data *init_data,
void *driver_data)
{
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0))
struct regulator_config config = {
.dev = dev,
.init_data = init_data,
.driver_data = driver_data,
};
return regulator_register(&regulator_desc, &config);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
struct regulator_config config = {
.dev = dev,
.init_data = init_data,
.driver_data = driver_data,
.of_node = dev->of_node,
};
return regulator_register(regulator_desc, &config);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 37))
return regulator_register(regulator_desc, dev, init_data,
driver_data, dev->of_node);
#else
return regulator_register(regulator_desc,dev,init_data,driver_data);
return regulator_register(regulator_desc, dev, init_data, driver_data);
#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) */
}
static int __devinit rt5025_regulator_probe(struct platform_device *pdev)
static struct regulator_init_data *of_parse_dt(struct rt5025_regulator_info *ri,
struct device *dev)
{
struct regulator_init_data *init_data = NULL;
#ifdef CONFIG_OF
struct device_node *np = dev->of_node;
int rc;
u32 tmp;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
init_data = of_get_regulator_init_data(dev, dev->of_node);
#else
init_data = of_get_regulator_init_data(dev);
#endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) */
rc = of_property_read_u32(np, "rt,ramp_sel", &tmp);
if (rc) {
dev_info(dev, "no ramp_sel property, use default value\n");
} else {
if (tmp > RT5025_DCDCRAMP_MAX)
tmp = RT5025_DCDCRAMP_MAX;
rt5025_assign_bits(ri->i2c, ri->ramp_reg, ri->ramp_bit, tmp);
}
if (of_property_read_bool(np, "rt,allow_mode_mask")) {
init_data->constraints.valid_modes_mask |=
(REGULATOR_MODE_FAST|\
REGULATOR_MODE_NORMAL);
init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE;
}
#endif /* #ifdef CONFIG_OF */
return init_data;
}
static int rt5025_regulator_probe(struct platform_device *pdev)
{
struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct rt5025_platform_data *pdata = chip->dev->platform_data;
struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data;
struct rt5025_regulator_info *ri;
struct rt5025_regulator_ramp *ramp;
struct regulator_dev *rdev;
struct regulator_init_data* init_data;
struct regulator_init_data *init_data;
bool use_dt = pdev->dev.of_node;
ri = find_regulator_info(pdev->id);
if (ri == NULL) {
dev_err(&pdev->dev, "invalid regulator ID specified\n");
return -EINVAL;
}
init_data = pdata->regulator[pdev->id];
if (init_data == NULL) {
ri->i2c = chip->i2c;
if (use_dt) {
init_data = of_parse_dt(ri, &pdev->dev);
} else {
init_data = pdata->regulator[pdev->id];
ramp = init_data->driver_data;
if (ramp)
rt5025_assign_bits(ri->i2c, ri->ramp_reg,
ri->ramp_bit, ramp->ramp_sel);
}
if (!init_data) {
dev_err(&pdev->dev, "no initializing data\n");
return -EINVAL;
}
ri->i2c = chip->i2c;
ri->chip = chip;
rdev = rt5025_regulator_register(&ri->desc, &pdev->dev,
init_data, ri);
@ -420,46 +464,59 @@ static int __devinit rt5025_regulator_probe(struct platform_device *pdev)
ri->desc.name);
return PTR_ERR(rdev);
}
platform_set_drvdata(pdev, rdev);
/* dev_info(&pdev->dev, "driver successfully loaded\n");*/
return 0;
}
static int __devexit rt5025_regulator_remove(struct platform_device *pdev)
static int rt5025_regulator_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
regulator_unregister(rdev);
dev_info(&pdev->dev, "%s\n", __func__);
return 0;
}
static struct platform_driver rt5025_regulator_driver =
{
.driver = {
.name = RT5025_DEVICE_NAME "-regulator",
.owner = THIS_MODULE,
},
.probe = rt5025_regulator_probe,
.remove = __devexit_p(rt5025_regulator_remove),
static struct of_device_id rt_match_table[] = {
{ .compatible = "rt,rt5025-dcdc1",},
{ .compatible = "rt,rt5025-dcdc2",},
{ .compatible = "rt,rt5025-dcdc3",},
{ .compatible = "rt,rt5025-dcdc4",},
{ .compatible = "rt,rt5025-ldo1",},
{ .compatible = "rt,rt5025-ldo2",},
{ .compatible = "rt,rt5025-ldo3",},
{ .compatible = "rt,rt5025-ldo4",},
{ .compatible = "rt,rt5025-ldo5",},
{ .compatible = "rt,rt5025-ldo6",},
{},
};
static int __init rt5025_regulator_init(void)
static struct platform_driver rt5025_regulator_driver = {
.driver = {
.name = RT5025_DEV_NAME "-regulator",
.owner = THIS_MODULE,
.of_match_table = rt_match_table,
},
.probe = rt5025_regulator_probe,
.remove = rt5025_regulator_remove,
};
static int rt5025_regulator_init(void)
{
return platform_driver_register(&rt5025_regulator_driver);
}
subsys_initcall_sync(rt5025_regulator_init);
subsys_initcall(rt5025_regulator_init);
static void __exit rt5025_regulator_exit(void)
static void rt5025_regulator_exit(void)
{
platform_driver_unregister(&rt5025_regulator_driver);
}
module_exit(rt5025_regulator_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("Regulator driver for RT5025");
MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-regulator");
MODULE_ALIAS("platform:" RT5025_DEV_NAME "-regulator");
MODULE_VERSION(RT5025_DRV_VER);

View File

@ -1,26 +1,21 @@
/*
* include/linux/mfd/rt5025-gpio.h
* include/linux/mfd/rt5025/rt5025-gpio.h
* Include header file for Richtek RT5025 PMIC GPIO file
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2013 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT5025_GPIO_H
#define __LINUX_RT5025_GPIO_H
#define RT5025_REG_GPIO0 0x1C
#define RT5025_REG_GPIO1 0x1D
#define RT5025_REG_GPIO2 0x1E
#define RT5025_GPIO_NR 3
#define RT5025_GPIO_INPUT 0x00
#define RT5025_GPIO_OUTPUT 0x02
#define RT5025_GPIO_INPUT 0x00
#define RT5025_GPIO_OUTPUT 0x02
#define RT5025_GPIO_DIRSHIFT 6
#define RT5025_GPIO_DIRMASK 0xC0

30
include/linux/mfd/rt5025-irq.h Normal file → Executable file
View File

@ -1,39 +1,19 @@
/*
* include/linux/mfd/rt5025-irq.h
* include/linux/mfd/rt5025/rt5025-irq.h
* Include header file for Richtek RT5025 PMIC IRQ file
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT5025_IRQ_H
#define __LINUX_RT5025_IRQ_H
#define RT5025_REG_CHGSTAT 0x01
#define RT5025_REG_IRQEN1 0x30
#define RT5025_REG_IRQSTATUS1 0x31
#define RT5025_REG_IRQEN2 0x32
#define RT5025_REG_IRQSTATUS2 0x33
#define RT5025_REG_IRQEN3 0x34
#define RT5025_REG_IRQSTATUS3 0x35
#define RT5025_REG_IRQEN4 0x36
#define RT5025_REG_IRQSTATUS4 0x37
#define RT5025_REG_IRQEN5 0x38
#define RT5025_REG_IRQSTATUS5 0x39
#define RT5025_INACIRQ_MASK 0x40
#define RT5025_INUSBIRQ_MASK 0x08
#define RT5025_ADAPIRQ_MASK (RT5025_INACIRQ_MASK|RT5025_INUSBIRQ_MASK)
#define RT5025_CHTERMI_MASK 0x01
#define RT5025_REG_GAUGEIRQEN 0x50
#define RT5025_REG_GAUGEIRQFLG 0x51
#define RT5025_FLG_TEMP 0x30
#define RT5025_FLG_VOLT 0x07
#define RT5025_TALRT_MASK 0x30
#endif /* #ifndef __LINUX_RT5025_IRQ_H */

37
include/linux/mfd/rt5025-misc.h Normal file → Executable file
View File

@ -1,5 +1,5 @@
/*
* include/linux/mfd/rt5025-misc.h
* include/linux/mfd/rt5025/rt5025-misc.h
* Include header file for Richtek RT5025 PMIC Misc
*
* Copyright (C) 2013 Richtek Technology Corp.
@ -14,15 +14,36 @@
#ifndef __LINUX_RT5025_MISC_H
#define __LINUX_RT5025_MISC_H
#define RT5025_RESETCTRL_REG 0x15
#define RT5025_VSYSULVO_REG 0x17
#define RT5025_PWRONCTRL_REG 0x19
#define RT5025_SHDNCTRL_REG 0x1A
#define RT5025_PWROFFEN_REG 0x1B
#define RT5025_CHENH_REG 0x62
#define RT5025_CHENL_REG 0x63
enum {
MISCEVENT_GPIO0_IE = 1,
MISCEVENT_GPIO1_IE,
MISCEVENT_GPIO2_IE,
MISCEVENT_RESETB,
MISCEVENT_PWRONF,
MISCEVENT_PWRONR,
MISCEVENT_KPSHDN,
MISCEVENT_SYSLV,
MISCEVENT_DCDC4LVHV,
MISCEVENT_PWRONLP_IRQ,
MISCEVENT_PWRONSP_IRQ,
MISCEVENT_DCDC3LV,
MISCEVENT_DCDC2LV,
MISCEVENT_DCDC1LV,
MISCEVENT_OT,
MISCEVENT_MAX,
};
#define RT5025_SHDNCTRL_MASK 0x80
#define RT5025_VSYSOFF_MASK 0xE0
#define RT5025_VSYSOFF_SHFT 5
#define RT5025_SHDNLPRESS_MASK 0x0C
#define RT5025_SHDNLPRESS_SHFT 2
#define RT5025_STARTLPRESS_MASK 0xC0
#define RT5025_STARTLPRESS_SHFT 6
#define RT5025_VSYSLVSHDN_MASK 0x80
#define RT5025_VSYSLVSHDN_SHFT 7
#define RT5025_CABLEIN_MASK 0x03
extern int rt5025_cable_exist(void);
#endif /* #ifndef __LINUX_RT5025_MISC_H */

844
include/linux/mfd/rt5025.h Normal file → Executable file
View File

@ -1,36 +1,147 @@
/*
* include/linux/mfd/rt5025.h
* include/linux/mfd/rt5025/rt5025.h
* Include header file for Richtek RT5025 Core file
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2013 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_MFD_RT5025_H
#define __LINUX_MFD_RT5025_H
#include <linux/power_supply.h>
#include <linux/android_alarm.h>
#include <linux/alarmtimer.h>
#include <linux/wakelock.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif /* CONFIG_HAS_EARLYSUSPEND */
#define RT5025_DEVICE_NAME "RT5025"
#define RT5025_DRV_VER "1.0.8_R"
#define RT5025_DEV_NAME "rt5025"
#define RT5025_DRV_VER "1.1.0_R"
#define RT_BATT_NAME "rt-battery"
enum {
RT5025_RSTDELAY1_100MS,
RT5025_RSTDELAY1_500MS,
RT5025_RSTDELAY1_1S,
RT5025_RSTDELAY1_2S,
};
enum {
RT5025_RSTDELAY2_100MS,
RT5025_RSTDELAY2_500MS,
RT5025_RSTDELAY2_1S,
RT5025_RSTDELAY2_2S,
RT5025_REG_DEVID,
RT5025_REG_RANGE1START = RT5025_REG_DEVID,
RT5025_REG_CHGCTL1,
RT5025_REG_CHGCTL2,
RT5025_REG_CHGCTL3,
RT5025_REG_CHGCTL4,
RT5025_REG_CHGCTL5,
RT5025_REG_CHGCTL6,
RT5025_REG_CHGCTL7,
RT5025_REG_DCDCCTL1,
RT5025_REG_DCDCCTL2,
RT5025_REG_DCDCCTL3,
RT5025_REG_VRCCTL,
RT5025_REG_DCDCCTL4,
RT5025_REG_LDOCTL1,
RT5025_REG_LDOCTL2,
RT5025_REG_LDOCTL3,
RT5025_REG_LDOCTL4,
RT5025_REG_LDOCTL5,
RT5025_REG_LDOCTL6,
RT5025_REG_RESV0,
RT5025_REG_LDOOMS,
RT5025_REG_MISC1,
RT5025_REG_ONEVENT,
RT5025_REG_DCDCONOFF,
RT5025_REG_LDOONOFF,
RT5025_REG_MISC2,
RT5025_REG_MISC3,
RT5025_REG_MISC4,
RT5025_REG_GPIO0,
RT5025_REG_GPIO1,
RT5025_REG_GPIO2,
RT5025_REG_RANGE1END = RT5025_REG_GPIO2,
RT5025_REG_OFFEVENT = 0x20,
RT5025_REG_RANGE2START = RT5025_REG_OFFEVENT,
RT5025_REG_RESV1,
RT5025_REG_RESV2,
RT5025_REG_RESV3,
RT5025_REG_RESV4,
RT5025_REG_RESV5,
RT5025_REG_RESV6,
RT5025_REG_RESV7,
RT5025_REG_RESV8,
RT5025_REG_RESV9,
RT5025_REG_RESV10,
RT5025_REG_RESV11,
RT5025_REG_RESV12,
RT5025_REG_RESV13,
RT5025_REG_RESV14,
RT5025_REG_RESV15,
RT5025_REG_IRQEN1,
RT5025_REG_IRQSTAT1,
RT5025_REG_IRQEN2,
RT5025_REG_IRQSTAT2,
RT5025_REG_IRQEN3,
RT5025_REG_IRQSTAT3,
RT5025_REG_IRQEN4,
RT5025_REG_IRQSTAT4,
RT5025_REG_IRQEN5,
RT5025_REG_IRQSTAT5,
RT5025_REG_RANGE2END = RT5025_REG_IRQSTAT5,
RT5025_REG_IRQCTL = 0x50,
RT5025_REG_RANGE3START = RT5025_REG_IRQCTL,
RT5025_REG_IRQFLG,
RT5025_REG_FGRESV1,
RT5025_REG_VALRTMAX,
RT5025_REG_VALRTMIN1,
RT5025_REG_VALRTMIN2,
RT5025_REG_TALRTMAX,
RT5025_REG_TALRTMIN,
RT5025_REG_VBATSH,
RT5025_REG_VBATSL,
RT5025_REG_INTEMPH,
RT5025_REG_INTEMPL,
RT5025_REG_FGRESV2,
RT5025_REG_CONFIG,
RT5025_REG_AINH,
RT5025_REG_AINL,
RT5025_REG_TIMERH,
RT5025_REG_TIMERL,
RT5025_REG_CHANNELH,
RT5025_REG_CHANNELL,
RT5025_REG_INACVLTH,
RT5025_REG_INACVLTL,
RT5025_REG_INUSBVLTH,
RT5025_REG_INUSBVLTL,
RT5025_REG_VSYSVLTH,
RT5025_REG_VSYSVLTL,
RT5025_REG_GPIO0VLTH,
RT5025_REG_GPIO0VLTL,
RT5025_REG_GPIO1VLTH,
RT5025_REG_GPIO1VLTL,
RT5025_REG_GPIO2VLTH,
RT5025_REG_GPIO2VLTL,
RT5025_REG_DCDC1VLTH,
RT5025_REG_DCDC1VLTL,
RT5025_REG_DCDC2VLTH,
RT5025_REG_DCDC2VLTL,
RT5025_REG_DCDC3VLTH,
RT5025_REG_DCDC3VLTL,
RT5025_REG_CURRH,
RT5025_REG_CURRL,
RT5025_REG_QCHGHH,
RT5025_REG_QCHGHL,
RT5025_REG_QCHGLH,
RT5025_REG_QCHGLL,
RT5025_REG_QDCHGHH,
RT5025_REG_QDCHGHL,
RT5025_REG_QDCHGLH,
RT5025_REG_QDCHGLL,
RT5025_REG_RANGE3END = RT5025_REG_QDCHGLL,
RT5025_REG_DCDC4OVP = 0xA9,
RT5025_REG_RANGE4START = RT5025_REG_DCDC4OVP,
RT5025_REG_RANGE4END = RT5025_REG_DCDC4OVP,
RT5025_REG_MAX,
};
enum {
@ -42,6 +153,7 @@ enum {
RT5025_VOFF_3P3V,
RT5025_VOFF_3P4V,
RT5025_VOFF_3P5V,
RT5025_VOFF_MAX = RT5025_VOFF_3P5V,
};
enum {
@ -49,13 +161,7 @@ enum {
RT5025_STARTIME_1S,
RT5025_STARTIME_2S,
RT5025_STARTIME_3S,
};
enum {
RT5025_LPRESS_1S,
RT5025_LPRESS_1P5S,
RT5025_LPRESS_2S,
RT5025_LPRESS_2P5S,
RT5025_STARTIME_MAX = RT5025_STARTIME_3S,
};
enum {
@ -63,68 +169,21 @@ enum {
RT5025_SHDNPRESS_6S,
RT5025_SHDNPRESS_8S,
RT5025_SHDNPRESS_10S,
RT5025_SHDNPRESS_MAX = RT5025_SHDNPRESS_10S,
};
enum {
RT5025_PGDLY_10MS,
RT5025_PGDLY_50MS,
RT5025_PGDLY_100MS,
RT5025_PGDLY_200MS,
RT5025_VDPM_4V,
RT5025_VDPM_4P25V,
RT5025_VDPM_4P5V,
RT5025_VDPM_DIS,
RT5025_VDPM_MAX = RT5025_VDPM_DIS,
};
enum {
RT5025_SHDNDLY_100MS,
RT5025_SHDNDLY_500MS,
RT5025_SHDNDLY_1S,
RT5025_SHDNDLY_2S,
};
enum {
RT5025_CCCHG_TO_4H,
RT5025_CCCHG_TO_6H,
RT5025_CCCHG_TO_8H,
RT5025_CCCHG_TO_10H,
};
enum {
RT5025_PRECHG_TO_30M,
RT5025_PRECHG_TO_40M,
RT5025_PRECHG_TO_50M,
RT5025_PRECHG_TO_60M,
};
enum {
RT5025_ICC_0P5A,
RT5025_ICC_0P6A,
RT5025_ICC_0P7A,
RT5025_ICC_0P8A,
RT5025_ICC_0P9A,
RT5025_ICC_1A,
RT5025_ICC_1P1A,
RT5025_ICC_1P2A,
RT5025_ICC_1P3A,
RT5025_ICC_1P4A,
RT5025_ICC_1P5A,
RT5025_ICC_1P6A,
RT5025_ICC_1P7A,
RT5025_ICC_1P8A,
RT5025_ICC_1P9A,
RT5025_ICC_2A,
RT5025_ICC_MAX,
};
enum {
RT5025_AICR_100MA,
RT5025_AICR_500MA,
RT5025_AICR_1A,
RT5025_AICR_NOLIMIT,
};
enum {
RT5025_DPM_4V,
RT5025_DPM_4P25V,
RT5025_DPM_4P5V,
RT5025_DPM_DIS,
RT5025_IEOC_10P,
RT5025_IEOC_20P,
RT5025_IEOC_MAX = RT5025_IEOC_20P,
};
enum {
@ -134,18 +193,13 @@ enum {
RT5025_VPREC_2P6V,
RT5025_VPREC_2P8V,
RT5025_VPREC_3V,
RT5025_VPREC_3V_1,
RT5025_VPREC_3V_2,
};
enum {
RT5025_IEOC_10P,
RT5025_IEOC_20P,
RT5025_VPREC_MAX = RT5025_VPREC_3V,
};
enum {
RT5025_IPREC_10P,
RT5025_IPREC_20P,
RT5025_IPREC_MAX = RT5025_IPREC_20P,
};
enum {
@ -162,306 +216,58 @@ enum {
RT5025_MAX_REGULATOR,
};
struct rt5025_power_data {
union {
struct {
unsigned char Resv1:1;
unsigned char CHGBC_EN:1;
unsigned char TE:1;
unsigned char Resv2:1;
unsigned char CCCHG_TIMEOUT:2;
unsigned char PRECHG_TIMEOUT:2;
}bitfield;
unsigned char val;
}CHGControl2;
union {
struct {
unsigned char Resv:2;
unsigned char VOREG:6;
}bitfield;
unsigned char val;
}CHGControl3;
union {
struct {
unsigned char AICR_CON:1;
unsigned char AICR:2;
unsigned char ICC:4;
unsigned char CHG_RST:1;
}bitfield;
unsigned char val;
}CHGControl4;
union {
struct {
unsigned char Resv1:4;
unsigned char DPM:2;
unsigned char Resv2:2;
}bitfield;
unsigned char val;
}CHGControl5;
union {
struct {
unsigned char IPREC:1;
unsigned char IEOC:1;
unsigned char VPREC:3;
unsigned char Resv:3;
}bitfield;
unsigned char val;
}CHGControl6;
union {
struct {
unsigned char Resv1:4;
unsigned char CHGC_EN:1;
unsigned char CHG_DCDC_MODE:1;
unsigned char BATD_EN:1;
unsigned char Resv2:1;
}bitfield;
unsigned char val;
}CHGControl7;
typedef void (*rt_irq_handler)(void *info, int eventno);
#define RT5025_DCDCRAMP_MAX 0x03
struct rt5025_regulator_ramp {
unsigned char ramp_sel:2;
};
struct rt5025_gpio_data {
unsigned gpio_base;
unsigned irq_base;
};
struct rt5025_misc_data {
union {
struct {
unsigned char Action:2;
unsigned char Delayed1:2;
unsigned char Delayed2:2;
unsigned char Resv:2;
}bitfield;
unsigned char val;
}RSTCtrl;
union {
struct {
unsigned char Resv:5;
unsigned char VOFF:3;
}bitfield;
unsigned char val;
}VSYSCtrl;
union {
struct {
unsigned char PG_DLY:2;
unsigned char SHDN_PRESS:2;
unsigned char LPRESS_TIME:2;
unsigned char START_TIME:2;
}bitfield;
unsigned char val;
}PwrOnCfg;
union {
struct {
unsigned char Resv:4;
unsigned char SHDN_DLYTIME:2;
unsigned char SHDN_TIMING:1;
unsigned char SHDN_CTRL:1;
}bitfield;
unsigned char val;
}SHDNCtrl;
union {
struct {
unsigned char Resv:2;
unsigned char OT_ENSHDN:1;
unsigned char PWRON_ENSHDN:1;
unsigned char DCDC3LV_ENSHDN:1;
unsigned char DCDC2LV_ENSHDN:1;
unsigned char DCDC1LV_ENSHDN:1;
unsigned char SYSLV_ENSHDN:1;
}bitfield;
unsigned char val;
}PwrOffCond;
};
struct rt5025_irq_data {
union {
struct {
unsigned char BATABS:1;
unsigned char Resv1:2;
unsigned char INUSB_PLUGIN:1;
unsigned char INUSBOVP:1;
unsigned char Resv2:1;
unsigned char INAC_PLUGIN:1;
unsigned char INACOVP:1;
}bitfield;
unsigned char val;
}irq_enable1;
union {
struct {
unsigned char CHTERMI:1;
unsigned char CHBATOVI:1;
unsigned char CHGOODI_INUSB:1;
unsigned char CHBADI_INUSB:1;
unsigned char CHSLPI_INUSB:1;
unsigned char CHGOODI_INAC:1;
unsigned char CHBADI_INAC:1;
unsigned char CHSLPI_INAC:1;
}bitfield;
unsigned char val;
}irq_enable2;
union {
struct {
unsigned char TIMEOUT_CC:1;
unsigned char TIMEOUT_PC:1;
unsigned char Resv:3;
unsigned char CHVSREGI:1;
unsigned char CHTREGI:1;
unsigned char CHRCHGI:1;
}bitfield;
unsigned char val;
}irq_enable3;
union {
struct {
unsigned char SYSLV:1;
unsigned char DCDC4LVHV:1;
unsigned char PWRONLP:1;
unsigned char PWRONSP:1;
unsigned char DCDC3LV:1;
unsigned char DCDC2LV:1;
unsigned char DCDC1LV:1;
unsigned char OT:1;
}bitfield;
unsigned char val;
}irq_enable4;
union {
struct {
unsigned char Resv:1;
unsigned char GPIO0_IE:1;
unsigned char GPIO1_IE:1;
unsigned char GPIO2_IE:1;
unsigned char RESETB:1;
unsigned char PWRONF:1;
unsigned char PWRONR:1;
unsigned char KPSHDN:1;
}bitfield;
unsigned char val;
}irq_enable5;
};
enum {
JEITA_NO_CHARGE,
JEITA_NORMAL_USB,
JEITA_USB_TA,
JEITA_AC_ADAPTER,
JEITA_CHARGER_MAX,
};
struct rt5025_jeita_data {
int* temp;
u8* temp_scalar;
int (*temp_cc)[5];
int (*temp_cv)[5];
};
#define CHG_EVENT_INACOVP (0x80<<16)
#define CHG_EVENT_INAC_PLUGIN (0x40<<16)
#define CHG_EVENT_INUSBOVP (0x10<<16)
#define CHG_EVENT_INUSB_PLUGIN (0x08<<16)
#define CHG_EVENT_BAT_ABS (0x01<<16)
#define CHG_EVENT_CHSLPI_INAC (0x80<<8)
#define CHG_EVENT_CHBADI_INAC (0x40<<8)
#define CHG_EVENT_CHGOODI_INAC (0x20<<8)
#define CHG_EVENT_CHSLPI_INUSB (0x10<<8)
#define CHG_EVENT_CHBADI_INUSB (0x08<<8)
#define CHG_EVENT_CHGOODI_INUSB (0x04<<8)
#define CHG_EVENT_CHBATOVI (0x02<<8)
#define CHG_EVENT_CHTERMI (0x01<<8)
#define CHG_EVENT_CHRCHGI (0x80<<0)
#define CHG_EVENT_CHTREGI (0x40<<0)
#define CHG_EVENT_CHVSREGI (0x20<<0)
#define CHG_EVENT_TIMEOUTPC (0x02<<0)
#define CHG_EVENT_TIMEOUTCC (0x01<<0)
#define CHARGER_DETECT_MASK (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN | \
CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB | \
CHG_EVENT_CHBADI_INAC | CHG_EVENT_CHBADI_INUSB | \
CHG_EVENT_CHTERMI | CHG_EVENT_CHRCHGI)
#define PWR_EVENT_OTIQ (0x80<<8)
#define PWR_EVENT_DCDC1LV (0x40<<8)
#define PWR_EVENT_DCDC2LV (0x20<<8)
#define PWR_EVENT_DCDC3LV (0x10<<8)
#define PWR_EVENT_PWRONSP (0x08<<8)
#define PWR_EVENT_PWRONLP (0x04<<8)
#define PWR_EVENT_DCDC4LVHV (0x02<<8)
#define PWR_EVENT_SYSLV (0x01<<8)
#define PWR_EVENT_KPSHDN (0x80<<0)
#define PWR_EVNET_PWRONR (0x40<<0)
#define PWR_EVENT_PWRONF (0x20<<0)
#define PWR_EVENT_RESETB (0x10<<0)
#define PWR_EVENT_GPIO2IE (0x08<<0)
#define PWR_EVENT_GPIO1IE (0x04<<0)
#define PWR_EVENT_GPIO0IE (0x02<<0)
struct rt5025_event_callback {
#if 1
void (*charger_event_callback)(uint32_t detected);
void (*power_event_callkback)(uint32_t detected);
#else
void (*over_temperature_callback)(uint8_t detected);
void (*charging_complete_callback)(void);
void (*over_voltage_callback)(uint8_t detected);
void (*under_voltage_callback)(uint8_t detected);
void (*charge_fault_callback)(uint8_t detected);
void (*charge_warning_callback)(uint8_t detected);
#endif
};
struct rt5025_power_info {
struct rt5025_charger_info {
struct i2c_client *i2c;
struct device *dev;
struct rt5025_chip *chip;
//struct rt5025_gauge_callbacks *event_callback;
struct power_supply ac;
struct power_supply usb;
struct mutex var_lock;
struct delayed_work usb_detect_work;
int usb_cnt;
int chg_term;
int otg_en;
unsigned ac_online:1;
unsigned usb_online:1;
unsigned chg_stat:3;
};
struct rt5025_swjeita_info {
struct i2c_client *i2c;
struct rt5025_chip *chip;
struct delayed_work thermal_reg_work;
int *temp;
u8 *temp_scalar;
int (*temp_cc)[5];
int (*temp_cv)[5];
int dec_current;
int cur_section;
int cur_therm_region;
int cur_cable;
int cur_temp;
int cur_inttemp;
int init_once;
int suspend;
struct power_supply psy;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif /* CONFIG_HAS_EARLYSUSPEND */
struct delayed_work tempmon_work;
int temp[4];
u32 temp_scalar[8];
unsigned int te_en:1;
unsigned int online:1;
unsigned int batabs:1;
unsigned int battemp_region:3;
unsigned int inttemp_region:2;
unsigned int otg_en:1;
unsigned int init_once:1;
unsigned int suspend:1;
unsigned int screenon_adjust:1;
unsigned int screen_on:1;
int chg_status;
int charger_cable;
int chg_volt;
int acchg_icc;
int usbtachg_icc;
int usbchg_icc;
int screenon_icc;
};
struct rt5025_battery_info {
struct i2c_client *client;
struct rt5025_chip *chip;
//struct rt5025_gauge_callbacks cb;
struct power_supply battery;
struct delayed_work monitor_work;
struct wake_lock monitor_wake_lock;
struct wake_lock low_battery_wake_lock;
struct wake_lock status_wake_lock;
//#if RT5025_TEST_WAKE_LOCK
struct wake_lock test_wake_lock;
//#endif
struct wake_lock smooth0_wake_lock;
struct wake_lock smooth100_wake_lock;
struct wake_lock full_battery_wake_lock;
/*#if RT5025_TEST_WAKE_LOCK
// struct wake_lock test_wake_lock;
//#endif*/
struct mutex status_change_lock;
struct alarm wakeup_alarm;
bool temp_range_0_5;
bool temp_range_5_10;
bool temp_range_10_15;
@ -471,7 +277,7 @@ struct rt5025_battery_info {
bool temp_range_35_40;
bool temp_range_40_45;
bool temp_range_45_50;
bool range_0_5_done;
bool range_5_10_done;
bool range_10_15_done;
@ -481,159 +287,183 @@ struct rt5025_battery_info {
bool range_35_40_done;
bool range_40_45_done;
bool range_45_50_done;
bool suspend_poll;
ktime_t last_poll;
// ktime_t last_event;
struct timespec last_event;
/* ktime_t last_event;*/
struct timespec last_event;
u16 update_time;
/* previous battery voltage */
u16 pre_vcell;
/* previous battery current */
s16 pre_curr;
/* battery voltage */
u16 vcell;
/* battery current */
s16 curr;
/* battery current offset */
u16 curr_offset;
/* AIN voltage */
u16 ain_volt;
/* battery internal temperature */
s16 int_temp;
/* battery external temperature */
s16 ext_temp;
/* charge coulomb counter */
u32 chg_cc;
u32 chg_cc_unuse;
/* discharge coulomb counter */
u32 dchg_cc;
u32 dchg_cc_unuse;
/* battery capacity */
u16 soc;
u16 temp_soc;
u16 pre_soc;
u16 time_interval;
u16 pre_gauge_timer;
u8 online;
u8 status;
u8 internal_status;
u8 health;
u8 present;
u16 update_time;
/* IRQ flag */
u8 irq_flag;
/* max voltage IRQ flag */
bool max_volt_irq;
/* min voltage1 IRQ flag */
bool min_volt1_irq;
/* min voltage2 IRQ flag */
bool min_volt2_irq;
/* max temperature IRQ flag */
bool max_temp_irq;
/* min temperature IRQ flag */
bool min_temp_irq;
/* previous battery voltage */
u16 pre_vcell;
/* previous battery current */
s16 pre_curr;
/* battery voltage */
u16 vcell;
/* battery current */
s16 curr;
/* battery current offset */
u16 curr_offset;
/* AIN voltage */
u16 ain_volt;
/* battery internal temperature */
s16 int_temp;
/* battery external temperature */
s16 ext_temp;
/* charge coulomb counter */
u32 chg_cc;
u32 chg_cc_unuse;
/* discharge coulomb counter */
u32 dchg_cc;
u32 dchg_cc_unuse;
/* battery capacity */
u16 soc;
u16 temp_soc;
u16 pre_soc;
bool min_volt2_alert;
u16 time_interval;
u16 pre_gauge_timer;
u8 online;
u8 status;
u8 internal_status;
u8 health;
u8 present;
u8 batt_present;
/* IRQ flag */
u8 irq_flag;
/* max voltage IRQ flag */
bool max_volt_irq;
/* min voltage1 IRQ flag */
bool min_volt1_irq;
/* min voltage2 IRQ flag */
bool min_volt2_irq;
/* max temperature IRQ flag */
bool max_temp_irq;
/* min temperature IRQ flag */
bool min_temp_irq;
bool min_volt2_alert;
u8 temp_high_cnt;
u8 temp_low_cnt;
u8 temp_recover_cnt;
bool init_cap;
bool avg_flag;
/* remain capacity */
u32 rm;
/* SOC permille */
u16 permille;
/* full capccity */
u16 fcc_aging;
u16 fcc;
u16 dc;
s16 tempcmp;
#if 0
u32 time_to_empty;
u32 time_to_full;
#endif
bool edv_flag;
bool edv_detection;
u8 edv_cnt;
bool tp_flag;
u8 tp_cnt;
u8 cycle_cnt;
u32 acc_dchg_cap;
bool smooth_flag;
u16 gauge_timer;
s16 curr_raw;
u32 empty_edv;
u8 edv_region;
/* remain capacity */
u32 rm;
/* SOC permille */
u16 permille;
/* full capccity */
u16 fcc_aging;
u16 fcc;
u16 dc;
s16 tempcmp;
bool init_once;
bool device_suspend;
bool last_suspend;
bool last_tp_flag;
u32 cal_fcc;
u8 test_temp;
bool edv_flag;
bool edv_detection;
u8 edv_cnt;
bool tp_flag;
u8 tp_cnt;
u8 cycle_cnt;
u32 acc_dchg_cap;
bool smooth_flag;
u16 gauge_timer;
s16 curr_raw;
u32 empty_edv;
u8 edv_region;
u32 soc1_lock_cnt;
u32 soc99_lock_cnt;
bool init_once;
bool device_suspend;
bool last_suspend;
bool last_tp_flag;
bool fcc_update_flag;
u32 cal_fcc;
u8 test_temp;
u8 last_tp;
u32 cal_eoc_fcc;
u32 cal_soc_offset;
};
struct rt5025_charger_data {
int *temp;
u32 *temp_scalar;
int chg_volt;
int acchg_icc;
int usbtachg_icc;
int usbchg_icc;
int screenon_icc;
unsigned int ieoc:1;
unsigned int vdpm:2;
unsigned int te_en:1;
unsigned int vprec:3;
unsigned int iprec:1;
unsigned int screenon_adjust:1;
};
struct rt5025_gpio_data {
int ngpio;
};
struct rt5025_misc_data {
unsigned char vsyslv:3;
unsigned char shdnlpress_time:2;
unsigned char startlpress_time:2;
unsigned char vsyslv_enshdn:1;
};
struct rt5025_irq_data {
int irq_gpio;
};
struct rt5025_chip;
struct rt5025_platform_data {
struct regulator_init_data *regulator[RT5025_MAX_REGULATOR];
struct rt5025_charger_data *chg_pdata;
struct rt5025_gpio_data *gpio_pdata;
struct rt5025_misc_data *misc_pdata;
struct rt5025_irq_data *irq_pdata;
int (*pre_init)(struct rt5025_chip *rt5025_chip);
/** Called after subdevices are set up */
int (*post_init)(void);
};
struct rt5025_misc_info {
struct i2c_client *i2c;
struct device *dev;
};
struct rt5025_chip {
struct i2c_client *i2c;
struct workqueue_struct *wq;
struct device *dev;
struct rt5025_power_info *power_info;
struct rt5025_swjeita_info *jeita_info;
struct rt5025_charger_info *charger_info;
struct rt5025_battery_info *battery_info;
int suspend;
int irq;
struct delayed_work delayed_work;
struct rt5025_misc_info *misc_info;
struct mutex io_lock;
int suspend;
};
struct rt5025_platform_data {
struct regulator_init_data* regulator[RT5025_MAX_REGULATOR];
struct rt5025_power_data* power_data;
struct rt5025_gpio_data* gpio_data;
struct rt5025_misc_data* misc_data;
struct rt5025_irq_data* irq_data;
struct rt5025_jeita_data* jeita_data;
struct rt5025_event_callback *cb;
int (*pre_init)(struct rt5025_chip *rt5025_chip);
/** Called after subdevices are set up */
int (*post_init)(void);
int (*set_otg_enable)(int);
int intr_pin;
};
#ifdef CONFIG_MFD_RT5025_MISC
extern void rt5025_power_off(void);
extern int rt5025_cable_exist(void);
#endif /* CONFIG_MFD_RT5025_MISC */
#ifdef CONFIG_POWER_RT5025
extern int rt5025_charger_reset_and_reinit(struct rt5025_power_info *);
extern int rt5025_ext_set_charging_buck(int);
extern int rt5025_set_charging_buck(struct i2c_client *, int);
extern int rt5025_set_charging_current_switch(struct i2c_client *, int);
extern void rt5025_gauge_set_status(struct rt5025_battery_info *, int);
extern void rt5025_gauge_set_online(struct rt5025_battery_info *, bool);
extern void rt5025_gauge_irq_handler(struct rt5025_battery_info *, u8);
extern int rt5025_power_charge_detect(struct rt5025_power_info *);
extern int rt5025_notify_charging_cable(struct rt5025_swjeita_info *, int);
extern int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *, unsigned char);
#endif /* CONFIG_POEWR_RT5025 */
#ifdef CONFIG_CHARGER_RT5025
void rt5025_charger_irq_handler(struct rt5025_charger_info *ci, unsigned int event);
#endif /* #ifdef CONFIG_CHARGER_RT5025 */
#ifdef CONFIG_MISC_RT5025
void rt5025_misc_irq_handler(struct rt5025_misc_info *mi, unsigned int event);
#endif /* #ifdef CONFIG_MISC_RT5025 */
#ifdef CONFIG_BATTERY_RT5025
void rt5025_gauge_irq_handler(struct rt5025_battery_info *bi, unsigned int event);
#endif /* #ifdef CONFIG_BATTERY_RT5025 */
extern int rt5025_reg_block_read(struct i2c_client *, int, int, void *);
extern int rt5025_reg_block_write(struct i2c_client *, int, int, void *);
@ -648,9 +478,9 @@ extern int rt5025_core_deinit(struct rt5025_chip *);
#ifdef CONFIG_MFD_RT_SHOW_INFO
#define RTINFO(format, args...) \
printk(KERN_INFO "%s:%s() line-%d: " format, RT5025_DEVICE_NAME,__FUNCTION__,__LINE__, ##args)
printk(KERN_INFO "%s:%s() line-%d: " format, RT5025_DEV_NAME, __FUNCTION__, __LINE__, ##args)
#else
#define RTINFO(format,args...)
#define RTINFO(format, args...)
#endif /* CONFIG_MFD_RT_SHOW_INFO */
#endif /* __LINUX_MFD_RT5025_H */

View File

@ -1,26 +1,24 @@
battery_graph_prop rt5025_battery_param1[] =
{
battery_graph_prop rt5025_battery_param1[] = {
{4190, 1000},
{4120, 980},
{4037, 890},
{3970, 800},
{3914, 710},
{3835, 580},
{3796, 490},
{3773, 400},
{3736, 240},
{3697, 140},
{3665, 70},
{3651, 50},
{3545, 20},
{3400, 0},
{4153, 980},
{4067, 890},
{3991, 800},
{3931, 710},
{3845, 580},
{3799, 490},
{3776, 400},
{3743, 240},
{3695, 140},
{3660, 70},
{3642, 50},
{3509, 20},
{3300, 0},
};
battery_graph_prop rt5025_battery_param2[] =
{
{450,14},
battery_graph_prop rt5025_battery_param2[] = {
{450, 30},
{250, 0},
{50,-78},
{50, 10},
{3400, 3671},
{50, -90},
{50, 10},
{3400, 6900},
};

27
include/linux/power/rt-power.h Executable file
View File

@ -0,0 +1,27 @@
/*
* include/linux/power/rt5025/rt-power.h
* Include header file for Richtek RT5025 Core charger Driver
*
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT_POWER_H
#define __LINUX_RT_POWER_H
#define RT_AC_NAME "rt-ac"
#define RT_USB_NAME "rt-usb"
struct rt_power_data {
int chg_volt;
int acchg_icc;
int usbtachg_icc;
int usbchg_icc;
};
#endif /* #ifndef __LINUX_RT_POWER_H */

123
include/linux/power/rt5025-battery.h Normal file → Executable file
View File

@ -1,13 +1,14 @@
/*
* include/linux/power/rt5025-battery.h
* include/linux/power/rt5025/rt5025-battery.h
* Include header file for Richtek RT5025 battery Driver
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2013 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT5025_BATTERY_H
@ -16,38 +17,38 @@
#undef ROCKCHIP_BATTERY_6900MAH
#undef ROCKCHIP_BATTERY_4000MAH
#define RT5025_REG_IRQ_CTL 0x50
#define RT5025_REG_IRQ_FLAG 0x51
#define RT5025_REG_VALRT_MAXTH 0x53
#define RT5025_REG_VALRT_MIN1TH 0x54
#define RT5025_REG_VALRT_MIN2TH 0x55
#define RT5025_REG_TALRT_MAXTH 0x56
#define RT5025_REG_TALRT_MINTH 0x57
#define RT5025_REG_VCELL_MSB 0x58
#define RT5025_REG_VCELL_LSB 0x59
#define RT5025_REG_INT_TEMPERATUE_MSB 0x5A
#define RT5025_REG_INT_TEMPERATUE_LSB 0x5B
#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E
#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F
#define RT5025_REG_TIMER 0x60
#define RT5025_REG_CHANNEL_MSB 0x62
#define RT5025_REG_CHANNEL_LSB 0x63
#define RT5025_REG_CURRENT_MSB 0x76
#define RT5025_REG_CURRENT_LSB 0x77
#define RT5025_REG_QCHGH_MSB 0x78
#define RT5025_REG_QCHGH_LSB 0x79
#define RT5025_REG_QCHGL_MSB 0x7A
#define RT5025_REG_QCHGL_LSB 0x7B
#define RT5025_REG_QDCHGH_MSB 0x7C
#define RT5025_REG_QDCHGH_LSB 0x7D
#define RT5025_REG_QDCHGL_MSB 0x7E
#define RT5025_REG_QDCHGL_LSB 0x7F
#define RT5025_REG_IRQ_CTL 0x50
#define RT5025_REG_IRQ_FLAG 0x51
#define RT5025_REG_VALRT_MAXTH 0x53
#define RT5025_REG_VALRT_MIN1TH 0x54
#define RT5025_REG_VALRT_MIN2TH 0x55
#define RT5025_REG_TALRT_MAXTH 0x56
#define RT5025_REG_TALRT_MINTH 0x57
#define RT5025_REG_VCELL_MSB 0x58
#define RT5025_REG_VCELL_LSB 0x59
#define RT5025_REG_INT_TEMPERATUE_MSB 0x5A
#define RT5025_REG_INT_TEMPERATUE_LSB 0x5B
#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E
#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F
#define RT5025_REG_TIMER 0x60
#define RT5025_REG_CHANNEL_MSB 0x62
#define RT5025_REG_CHANNEL_LSB 0x63
#define RT5025_REG_CURRENT_MSB 0x76
#define RT5025_REG_CURRENT_LSB 0x77
#define RT5025_REG_QCHGH_MSB 0x78
#define RT5025_REG_QCHGH_LSB 0x79
#define RT5025_REG_QCHGL_MSB 0x7A
#define RT5025_REG_QCHGL_LSB 0x7B
#define RT5025_REG_QDCHGH_MSB 0x7C
#define RT5025_REG_QDCHGH_LSB 0x7D
#define RT5025_REG_QDCHGL_MSB 0x7E
#define RT5025_REG_QDCHGL_LSB 0x7F
#define IRQ_CTL_BIT_TMX (1 << 5)
#define IRQ_CTL_BIT_TMN (1 << 4)
#define IRQ_CTL_BIT_VMX (1 << 2)
#define IRQ_CTL_BIT_VMN1 (1 << 1)
#define IRQ_CTL_BIT_VMN2 (1 << 0)
#define IRQ_CTL_BIT_TMX (1 << 5)
#define IRQ_CTL_BIT_TMN (1 << 4)
#define IRQ_CTL_BIT_VMX (1 << 2)
#define IRQ_CTL_BIT_VMN1 (1 << 1)
#define IRQ_CTL_BIT_VMN2 (1 << 0)
#define IRQ_FLG_BIT_TMX (1 << 5)
#define IRQ_FLG_BIT_TMN (1 << 4)
@ -81,61 +82,25 @@
#define EDV_HYS 100
#define IRQ_THRES_UNIT 1953
#define TALRTMAX_VALUE 0x38 //65.39'C
#define TALRTMIN_VALUE 0x9 //-18.75'C
#define TRLS_VALUE 55 //5'C ; unit:mV
#define VRLS_VALUE 100 //100mV
#define TALRTMAX_VALUE 0x38 /*65.39'C*/
#define TALRTMIN_VALUE 0x9 /*-18.75'C*/
#define TRLS_VALUE 55 /*5'C ; unit:mV*/
#define VRLS_VALUE 100 /*100mV*/
#define DEADBAND 10
//#define SLEEP_CURRENT 3 //mA
u16 crctab16[256] =
{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78,
};
/*#define SLEEP_CURRENT 3 //mA*/
typedef enum{
CHG,
DCHG
}operation_mode;
} operation_mode;
typedef struct{
int x;
int y;
}battery_graph_prop;
} battery_graph_prop;
typedef enum {
MAXTEMP,
@ -146,7 +111,7 @@ typedef enum {
TEMP_RLS,
VOLT_RLS,
LAST_TYPE,
}alert_type;
} alert_type;
#if defined(ROCKCHIP_BATTERY_6900MAH)
#include <linux/power/rockchip-6900ma-bat.h>
@ -156,6 +121,6 @@ typedef enum {
#include <linux/power/rockchip-general-bat.h>
#endif
#define VALRTMIN2_VALUE (rt5025_battery_param2[4].x * 100 / IRQ_THRES_UNIT + 1) //EDV0 voltage
#define VALRTMIN2_VALUE (rt5025_battery_param2[4].x * 100 / IRQ_THRES_UNIT + 1) /*EDV0 voltage*/
#endif /* #ifndef __LINUX_RT5025_BATTERY_H */

View File

@ -0,0 +1,86 @@
/*
* include/linux/power/rt5025/rt5025-charger.h
* Include header file for Richtek RT5025 Core charger Driver
*
* Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT5025_CHARGER_H
#define __LINUX_RT5025_CHARGER_H
enum {
CHGEVENT_TIMEOUT_CC,
CHGEVENT_TIMEOUT_PC,
CHGEVENT_CHVSREGI = 5,
CHGEVENT_CHTREGI,
CHGEVENT_CHRCHGI,
CHGEVENT_CHTERMI,
CHGEVENT_CHBATOVI,
CHGEVENT_CHGOODI_INUSB,
CHGEVENT_CHBADI_INUSB,
CHGEVENT_CHSLPI_INUSB,
CHGEVENT_CHGOODI_INAC,
CHGEVENT_CHBADI_INAC,
CHGEVENT_CHSLPI_INAC,
CHGEVENT_BATABS,
CHGEVENT_INUSB_PLUGIN = 19,
CHGEVENT_INUSBOVP,
CHGEVENT_INAC_PLUGIN = 22,
CHGEVENT_INACOVP,
/*append TALRT IRQ*/
CHGEVENT_TALRTMIN = 28,
CHGEVENT_TALRTMAX = 29,
CHGEVENT_MAX,
};
enum {
RT5025_BATTEMP_COLD,
RT5025_BATTEMP_COOL,
RT5025_BATTEMP_NORMAL,
RT5025_BATTEMP_WARM,
RT5025_BATTEMP_HOT,
RT5025_BATTEMP_MAX,
};
enum {
RT5025_INTTEMP_NORMAL,
RT5025_INTTEMP_WARM,
RT5025_INTTEMP_HOT,
RT5025_INTTEMP_MAX,
};
#define RT5025_CHGIPREC_MASK 0x01
#define RT5025_CHGIPREC_SHFT 0
#define RT5025_CHGIEOC_MASK 0x02
#define RT5025_CHGIEOC_SHFT 1
#define RT5025_CHGVPREC_MASK 0x1C
#define RT5025_CHGVPREC_SHFT 2
#define RT5025_CHGVDPM_MASK 0x30
#define RT5025_CHGVDPM_SHFT 4
#define RT5025_CHGCEN_MASK 0x10
#define RT5025_CHGAICR_MASK 0x06
#define RT5025_CHGAICR_SHFT 1
#define RT5025_CHGICC_MASK 0x78
#define RT5025_CHGICC_SHFT 3
#define RT5025_CHGCV_MASK 0xFC
#define RT5025_CHGCV_SHFT 2
#define RT5025_CHGTEEN_MASK 0x04
#define RT5025_BATDEN_MASK 0x40
#define RT5025_VBUSHZ_MASK 0x01
#define RT5025_CHGBCEN_MASK 0x02
#define RT5025_CHRCHGI_MASK 0x80
#define RT5025_CHTERMI_MASK 0x01
#define RT5025_ACUSABLE_MASK 0x02
#define RT5025_USBUSABLE_MASK 0x01
#define RT5025_TALRTMX_MASK 0x20
#define RT5025_TALRTMN_MASK 0x10
#endif /* #ifndef __LINUX_RT5025_POWER_H */

123
include/linux/regulator/rt5025-regulator.h Normal file → Executable file
View File

@ -2,88 +2,75 @@
* include/linux/regulator/rt5025-regulator.h
* Include header file to Richtek RT5025 Regulator driver
*
* Copyright (C) 2013 Richtek Electronics
* Copyright (C) 2013 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT5025_REGULATOR_H
#define __LINUX_RT5025_REGULATOR_H
#define RT5025_REG_DCDCCTRL1 0x08
#define RT5025_REG_DCDCCTRL2 0x09
#define RT5025_REG_DCDCCTRL3 0x0A
#define RT5025_REG_DCDCCTRL4 0x0B
#define RT5025_REG_LDOCTRL1 0x0D
#define RT5025_REG_LDOCTRL2 0x0E
#define RT5025_REG_LDOCTRL3 0x0F
#define RT5025_REG_LDOCTRL4 0x10
#define RT5025_REG_LDOCTRL5 0x11
#define RT5025_REG_LDOCTRL6 0x12
#define RT5025_REG_DCDCEN 0x17
#define RT5025_REG_LDOEN 0x18
#define RT5025_REG_DCDCVRC 0x0B
#define RT5025_REG_LDOVRC 0x00
#define RT5025_DCDCVOUT1 RT5025_REG_DCDCCTL1
#define RT5025_DCDCVOUT2 RT5025_REG_DCDCCTL2
#define RT5025_DCDCVOUT3 RT5025_REG_DCDCCTL3
#define RT5025_DCDCVOUT4 RT5025_REG_VRCCTL
#define RT5025_LDOVOUT1 RT5025_REG_LDOCTL1
#define RT5025_LDOVOUT2 RT5025_REG_LDOCTL2
#define RT5025_LDOVOUT3 RT5025_REG_LDOCTL3
#define RT5025_LDOVOUT4 RT5025_REG_LDOCTL4
#define RT5025_LDOVOUT5 RT5025_REG_LDOCTL5
#define RT5025_LDOVOUT6 RT5025_REG_LDOCTL6
#define RT5025_DCDCVOUT1 RT5025_REG_DCDCCTRL1
#define RT5025_DCDCVOUT2 RT5025_REG_DCDCCTRL2
#define RT5025_DCDCVOUT3 RT5025_REG_DCDCCTRL3
#define RT5025_DCDCVOUT4 RT5025_REG_DCDCCTRL4
#define RT5025_LDOVOUT1 RT5025_REG_LDOCTRL1
#define RT5025_LDOVOUT2 RT5025_REG_LDOCTRL2
#define RT5025_LDOVOUT3 RT5025_REG_LDOCTRL3
#define RT5025_LDOVOUT4 RT5025_REG_LDOCTRL4
#define RT5025_LDOVOUT5 RT5025_REG_LDOCTRL5
#define RT5025_LDOVOUT6 RT5025_REG_LDOCTRL6
#define RT5025_DCDCVOUT_SHIFT1 2
#define RT5025_DCDCVOUT_SHIFT2 1
#define RT5025_DCDCVOUT_SHIFT3 2
#define RT5025_DCDCVOUT_SHIFT4 0
#define RT5025_LDOVOUT_SHIFT1 0
#define RT5025_LDOVOUT_SHIFT2 0
#define RT5025_LDOVOUT_SHIFT3 3
#define RT5025_LDOVOUT_SHIFT4 3
#define RT5025_LDOVOUT_SHIFT5 3
#define RT5025_LDOVOUT_SHIFT6 3
#define RT5025_DCDCVOUT_SHIFT1 2
#define RT5025_DCDCVOUT_SHIFT2 1
#define RT5025_DCDCVOUT_SHIFT3 2
#define RT5025_DCDCVOUT_SHIFT4 0
#define RT5025_LDOVOUT_SHIFT1 0
#define RT5025_LDOVOUT_SHIFT2 0
#define RT5025_LDOVOUT_SHIFT3 3
#define RT5025_LDOVOUT_SHIFT4 3
#define RT5025_LDOVOUT_SHIFT5 3
#define RT5025_LDOVOUT_SHIFT6 3
#define RT5025_DCDCVOUT_MASK1 0xFC
#define RT5025_DCDCVOUT_MASK2 0xFE
#define RT5025_DCDCVOUT_MASK3 0xFC
#define RT5025_DCDCVOUT_MASK4 0x0F
#define RT5025_LDOVOUT_MASK1 0x7F
#define RT5025_LDOVOUT_MASK2 0x7F
#define RT5025_LDOVOUT_MASK3 0xF8
#define RT5025_LDOVOUT_MASK4 0xF8
#define RT5025_LDOVOUT_MASK5 0xF8
#define RT5025_LDOVOUT_MASK6 0xF8
#define RT5025_DCDCVOUT_MASK1 0xFC
#define RT5025_DCDCVOUT_MASK2 0xFE
#define RT5025_DCDCVOUT_MASK3 0xFC
#define RT5025_DCDCVOUT_MASK4 0x0F
#define RT5025_LDOVOUT_MASK1 0x7F
#define RT5025_LDOVOUT_MASK2 0x7F
#define RT5025_LDOVOUT_MASK3 0xF8
#define RT5025_LDOVOUT_MASK4 0xF8
#define RT5025_LDOVOUT_MASK5 0xF8
#define RT5025_LDOVOUT_MASK6 0xF8
#define RT5025_DCDCEN_MASK1 0x01
#define RT5025_DCDCEN_MASK2 0x02
#define RT5025_DCDCEN_MASK3 0x04
#define RT5025_DCDCEN_MASK4 0x08
#define RT5025_LDOEN_MASK1 0x01
#define RT5025_LDOEN_MASK2 0x02
#define RT5025_LDOEN_MASK3 0x04
#define RT5025_LDOEN_MASK4 0x08
#define RT5025_LDOEN_MASK5 0x10
#define RT5025_LDOEN_MASK6 0x20
#define RT5025_DCDC_OUTPUT_EN RT5025_REG_DCDCEN
#define RT5025_LDO_OUTPUT_EN RT5025_REG_LDOEN
#define RT5025_DCDCMODE_REG1 RT5025_REG_VRCCTL
#define RT5025_DCDCMODE_REG2 RT5025_REG_VRCCTL
#define RT5025_DCDCMODE_REG3 RT5025_REG_VRCCTL
#define RT5025_DCDCMODE_REG4 0
#define RT5025_DCDCEN_MASK1 0x01
#define RT5025_DCDCEN_MASK2 0x02
#define RT5025_DCDCEN_MASK3 0x04
#define RT5025_DCDCEN_MASK4 0x08
#define RT5025_LDOEN_MASK1 0x01
#define RT5025_LDOEN_MASK2 0x02
#define RT5025_LDOEN_MASK3 0x04
#define RT5025_LDOEN_MASK4 0x08
#define RT5025_LDOEN_MASK5 0x10
#define RT5025_LDOEN_MASK6 0x20
#define RT5025_DCDCMODE_MASK1 0x40
#define RT5025_DCDCMODE_MASK2 0x20
#define RT5025_DCDCMODE_MASK3 0x10
#define RT5025_DCDCMODE_MASK4 0x00
#define RT5025_DCDCMODE_MASK1 0x40
#define RT5025_DCDCMODE_MASK2 0x20
#define RT5025_DCDCMODE_MASK3 0x10
#define RT5025_DCDCMODE_MASK4 0x00
#define RT5025_LDOMODE_MASK1 0x00
#define RT5025_LDOMODE_MASK2 0x00
#define RT5025_LDOMODE_MASK3 0x00
#define RT5025_LDOMODE_MASK4 0x00
#define RT5025_LDOMODE_MASK5 0x00
#define RT5025_LDOMODE_MASK6 0x00
#define RT5025_DCDCRAMP_MASK1 0x03
#define RT5025_DCDCRAMP_MASK2 0x01
#define RT5025_DCDCRAMP_MASK3 0x03
#define RT5025_DCDCRAMP_MASK4 0x00
#endif /* __LINUX_RT5025_REGULATOR_H */