#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mutex.h>
+#include <linux/mfd/core.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
+#include <asm/system_misc.h>
#if 0
#define DBG(x...) printk(KERN_INFO x)
struct i2c_client *i2c;
int num_regulators;
struct regulator_dev **rdev;
-// struct early_suspend act8846_suspend;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend act8846_suspend;
+#endif
int irq_base;
int chip_irq;
int pmic_sleep_gpio; /* */
+ int pmic_hold_gpio; /* */
unsigned int dcdc_slp_voltage[3]; /* buckx_voltage in uV */
bool pmic_sleep;
struct regmap *regmap;
#else
ret = act8846_set_bits(act8846, act8846_BUCK_SET_VOL_REG(buck) ,BUCK_VOL_MASK, val);
#endif
+
+ if(ret < 0)
+ printk("##################:set voltage error!voltage set is %d mv\n",vol_map[val]);
return ret;
}
static int act8846_dcdc_set_voltage_time_sel(struct regulator_dev *dev, unsigned int old_selector,
unsigned int new_selector)
{
- struct act8846 *act8846 = rdev_get_drvdata(dev);
- int ret =0,old_volt, new_volt;
+ int old_volt, new_volt;
old_volt = act8846_dcdc_list_voltage(dev, old_selector);
if (old_volt < 0)
DBG("***run in %s %d msgs[1].buf = %d\n",__FUNCTION__,__LINE__,*(msgs[1].buf));
- return 0;
+ return ret;
}
static int act8846_i2c_write(struct i2c_client *i2c, char reg, int count, const u16 src)
static u8 act8846_reg_read(struct act8846 *act8846, u8 reg)
{
u16 val = 0;
+ int ret;
mutex_lock(&act8846->io_lock);
- act8846_i2c_read(act8846->i2c, reg, 1, &val);
+ ret = act8846_i2c_read(act8846->i2c, reg, 1, &val);
+ if(ret < 0){
+ mutex_unlock(&act8846->io_lock);
+ return ret;
+ }
DBG("reg read 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff);
mutex_lock(&act8846->io_lock);
ret = act8846_i2c_read(act8846->i2c, reg, 1, &tmp);
+ if(ret < 0){
+ mutex_unlock(&act8846->io_lock);
+ return ret;
+ }
DBG("1 reg read 0x%02x -> 0x%02x\n", (int)reg, (unsigned)tmp&0xff);
tmp = (tmp & ~mask) | val;
- if (ret == 0) {
- ret = act8846_i2c_write(act8846->i2c, reg, 1, tmp);
- DBG("reg write 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff);
+ ret = act8846_i2c_write(act8846->i2c, reg, 1, tmp);
+ if(ret < 0){
+ mutex_unlock(&act8846->io_lock);
+ return ret;
+ }
+ DBG("reg write 0x%02x -> 0x%02x\n", (int)reg, (unsigned)val&0xff);
+
+ ret = act8846_i2c_read(act8846->i2c, reg, 1, &tmp);
+ if(ret < 0){
+ mutex_unlock(&act8846->io_lock);
+ return ret;
}
- act8846_i2c_read(act8846->i2c, reg, 1, &tmp);
DBG("2 reg read 0x%02x -> 0x%02x\n", (int)reg, (unsigned)tmp&0xff);
mutex_unlock(&act8846->io_lock);
struct act8846_board *pdata;
struct device_node *regs;
struct device_node *act8846_pmic_np;
- int i, count,sleep_voltage_nr =1;
+ int i, count;
int gpio;
printk("%s,line=%d\n", __func__,__LINE__);
pdata->irq = act8846->chip_irq;
pdata->irq_base = -1;
- if (of_get_property(act8846_pmic_np, "act,pmic-dcdc-sleep-voltage", NULL))
- pdata->pmic_sleep = true;
-
- if (of_get_property(act8846_pmic_np, "act,pmic-ldo-sleep-voltage", NULL))
- pdata->pmic_sleep = true;
-
gpio = of_get_named_gpio(act8846_pmic_np,"gpios", 0);
if (!gpio_is_valid(gpio))
printk("invalid gpio: %d\n",gpio);
- pdata->pmic_sleep_gpio = gpio;
+ pdata->pmic_sleep_gpio = gpio;
+ pdata->pmic_sleep = true;
- if (of_property_read_u32_array(act8846_pmic_np,
- "act,pmic-dcdc-sleep-voltage",
- pdata->dcdc_slp_voltage, sleep_voltage_nr)) {
- printk("dcdc sleep voltages not specified\n");
- }\r
+ gpio = of_get_named_gpio(act8846_pmic_np,"gpios", 1);
+ if (!gpio_is_valid(gpio))
+ printk("invalid gpio: %d\n",gpio);
+ pdata->pmic_hold_gpio = gpio;
+ pdata->pm_off = of_property_read_bool(act8846_pmic_np,"act8846,system-power-controller");
return pdata;
}
-static int act8846_dcdc_sleep_voltage_get_val(int min_uV,int buck)
-{
- int min_vol = min_uV / 1000, max_vol = min_uV / 1000;
- const int *vol_map = buck_voltage_map;
- u16 val;
-
- if (min_vol < vol_map[VOL_MIN_IDX] ||
- min_vol > vol_map[VOL_MAX_IDX])
- return -EINVAL;
-
- for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; val++){
- if (vol_map[val] >= min_vol)
- break;
- }
- if (vol_map[val] > max_vol)
- printk("WARNING:this voltage is not support!voltage set is %d mv\n",vol_map[val]);
- return val;
-}
-static int act8846_dts_dcdc_set_mode(unsigned int mode,int buck)
-{
- struct act8846 *act8846 = g_act8846;
- u16 mask = 0x80;
- switch(mode)
- {
- case REGULATOR_MODE_STANDBY:
- return act8846_set_bits(act8846, act8846_BUCK_CONTR_REG(buck), mask, 0);
- case REGULATOR_MODE_NORMAL:
- return act8846_set_bits(act8846, act8846_BUCK_CONTR_REG(buck), mask, mask);
- default:
- printk("error:pmu_act8846 only powersave and pwm mode\n");
- return -EINVAL;
- }
-}
#else
static struct act8846_board *act8846_parse_dt(struct i2c_client *i2c)
{
#endif
-int act8846_device_shutdown(void)
+void act8846_device_shutdown(void)
{
- int ret;
- int err = -1;
struct act8846 *act8846 = g_act8846;
printk("%s\n",__func__);
-
+#if 1
+ if (act8846->pmic_hold_gpio) {
+ gpio_direction_output(act8846->pmic_hold_gpio,0);
+ mdelay(100);
+ arm_pm_restart('h', "charge");
+ }
+
+#else
ret = act8846_reg_read(act8846,0xc3);
ret = act8846_set_bits(act8846, 0xc3,(0x1<<3),(0x1<<3));
ret = act8846_set_bits(act8846, 0xc3,(0x1<<4),(0x1<<4));
printk("act8846 set 0xc3 error!\n");
return err;
}
- return 0;
+#endif
}
EXPORT_SYMBOL_GPL(act8846_device_shutdown);
__weak void act8846_device_suspend(void) {}
__weak void act8846_device_resume(void) {}
#ifdef CONFIG_PM
-static int act8846_suspend(struct i2c_client *i2c, pm_message_t mesg)
-{
+static int act8846_suspend(struct device *dev)
+{
act8846_device_suspend();
return 0;
}
-static int act8846_resume(struct i2c_client *i2c)
+static int act8846_resume(struct device *dev)
{
act8846_device_resume();
return 0;
}
#else
-static int act8846_suspend(struct i2c_client *i2c, pm_message_t mesg)
+static int act8846_suspend(struct device *dev)
{
return 0;
}
-static int act8846_resume(struct i2c_client *i2c)
+static int act8846_resume(struct device *dev)
{
return 0;
}
}
}
- act8846 = kzalloc(sizeof(struct act8846), GFP_KERNEL);
+ act8846 = devm_kzalloc(&i2c->dev,sizeof(struct act8846), GFP_KERNEL);
if (act8846 == NULL) {
ret = -ENOMEM;
goto err;
ret = act8846_reg_read(act8846,0x22);
if ((ret < 0) || (ret == 0xff)){
printk("The device is not act8846 %x \n",ret);
- return 0;
+ goto err;
}
ret = act8846_set_bits(act8846, 0xf4,(0x1<<7),(0x0<<7));
if (act8846->dev->of_node)
pdev = act8846_parse_dt(act8846);
+
+ #ifdef CONFIG_OF
+ act8846->pmic_hold_gpio = pdev->pmic_hold_gpio;
+ if (act8846->pmic_hold_gpio) {
+ ret = gpio_request(act8846->pmic_hold_gpio, "act8846_pmic_hold");
+ if (ret < 0) {
+ dev_err(act8846->dev,"Failed to request gpio %d with ret:""%d\n", act8846->pmic_hold_gpio, ret);
+ return IRQ_NONE;
+ }
+ gpio_direction_output(act8846->pmic_hold_gpio,1);
+ ret = gpio_get_value(act8846->pmic_hold_gpio);
+ // gpio_free(act8846->pmic_hold_gpio);
+ printk("%s: act8846_pmic_hold=%x\n", __func__, ret);
+ }
+ #endif
/******************************set sleep vol & dcdc mode******************/
#ifdef CONFIG_OF
dev_err(act8846->dev,"Failed to request gpio %d with ret:""%d\n", act8846->pmic_sleep_gpio, ret);
return IRQ_NONE;
}
- gpio_direction_input(act8846->pmic_sleep_gpio);
+ gpio_direction_output(act8846->pmic_sleep_gpio,1);
ret = gpio_get_value(act8846->pmic_sleep_gpio);
gpio_free(act8846->pmic_sleep_gpio);
printk("%s: act8846_pmic_sleep=%x\n", __func__, ret);
}
- for (i = 0;i <4 ; i ++){
- act8846->dcdc_slp_voltage[i] = pdev->dcdc_slp_voltage[i];
- if (act8846->dcdc_slp_voltage[i]){
- if (i ==0)
- continue;
-
- #ifdef CONFIG_ACT8846_SUPPORT_RESET
- ret = act8846_set_bits(act8846, act8846_BUCK_SET_VOL_REG(i) ,BUCK_VOL_MASK, act8846_dcdc_sleep_voltage_get_val(act8846->dcdc_slp_voltage[i],i));
- #else
- ret = act8846_set_bits(act8846, (act8846_BUCK_SET_VOL_REG(i) +0x01),BUCK_VOL_MASK, act8846_dcdc_sleep_voltage_get_val(act8846->dcdc_slp_voltage[i],i));
- #endif
- }
- }
#endif
if (pdev) {
act8846->num_regulators = act8846_NUM_REGULATORS;
- act8846->rdev = kcalloc(act8846_NUM_REGULATORS,sizeof(struct regulator_dev *), GFP_KERNEL);
+ act8846->rdev = devm_kcalloc(act8846->dev,
+ act8846_NUM_REGULATORS,
+ sizeof(struct regulator_dev *),
+ GFP_KERNEL);
if (!act8846->rdev) {
return -ENOMEM;
}
act8846->rdev[i] = act_rdev;
}
}
+
+ if (pdev->pm_off && !pm_power_off) {
+ pm_power_off = act8846_device_shutdown;
+ }
#ifdef CONFIG_HAS_EARLYSUSPEND
act8846->act8846_suspend.suspend = act8846_early_suspend,
for (i = 0; i < act8846->num_regulators; i++)
if (act8846->rdev[i])
regulator_unregister(act8846->rdev[i]);
- kfree(act8846->rdev);
i2c_set_clientdata(i2c, NULL);
- kfree(act8846);
return 0;
}
+static const struct dev_pm_ops act8846_pm_ops = {
+ .suspend = act8846_suspend,
+ .resume = act8846_resume,
+};
+
static const struct i2c_device_id act8846_i2c_id[] = {
{ "act8846", 0 },
{ }
.driver = {
.name = "act8846",
.owner = THIS_MODULE,
+ #ifdef CONFIG_PM
+ .pm = &act8846_pm_ops,
+ #endif
.of_match_table =of_match_ptr(act8846_of_match),
},
.probe = act8846_i2c_probe,
.remove = act8846_i2c_remove,
.id_table = act8846_i2c_id,
- #ifdef CONFIG_PM
- .suspend = act8846_suspend,
- .resume = act8846_resume,
- #endif
};
static int __init act8846_module_init(void)