ARM64: dts: rk3399-box-rev2: enable hdmi uboot logo display
[firefly-linux-kernel-4.4.55.git] / drivers / power / rt5025-power.c
old mode 100644 (file)
new mode 100755 (executable)
index b99a79d..6d654d7
 #include <linux/workqueue.h>
 #include <linux/mfd/rt5025.h>
 #include <linux/power/rt5025-power.h>
-#include <linux/power/rt5025-gauge.h>
 #include <linux/delay.h>
 
+static struct platform_device *dev_ptr;
+
 
 static enum power_supply_property rt5025_adap_props[] = {
        POWER_SUPPLY_PROP_ONLINE,
@@ -34,8 +35,8 @@ static char *rt5025_supply_list[] = {
        "rt5025-battery",
 };
 
-#if 0
-static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
+
+int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
 {
        int ret;
        if (onoff)
@@ -44,8 +45,9 @@ static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff
                ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK);
        return ret;
 }
+EXPORT_SYMBOL(rt5025_set_charging_current_switch);
 
-static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
+int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
 {
        int ret;
        if (onoff)
@@ -54,7 +56,53 @@ static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff)
                ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
        return ret;
 }
-#endif
+EXPORT_SYMBOL(rt5025_set_charging_buck);
+
+int rt5025_ext_set_charging_buck(int onoff)
+{
+       struct rt5025_power_info *pi = platform_get_drvdata(dev_ptr);
+       int ret;
+       if (onoff)
+       {
+               pi->otg_en = 0;
+               ret = rt5025_set_bits(pi->i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+               msleep(100);
+       }
+       else
+       {
+               pi->otg_en = 1;
+               ret = rt5025_clr_bits(pi->i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+               msleep(100);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(rt5025_ext_set_charging_buck);
+
+int rt5025_charger_reset_and_reinit(struct rt5025_power_info *pi)
+{
+       struct rt5025_platform_data *pdata = pi->dev->parent->platform_data;
+       int ret;
+
+       RTINFO("\n");
+
+       //do charger reset
+       ret = rt5025_reg_read(pi->i2c, RT5025_REG_CHGCTL4);
+       if (ret < 0)
+               return ret;
+       rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL4, ret|RT5025_CHGRST_MASK);
+       mdelay(200);
+
+       rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL2, pdata->power_data->CHGControl2.val);
+       rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL3, pdata->power_data->CHGControl3.val);
+       rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL4, pdata->power_data->CHGControl4.val);
+       rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL5, pdata->power_data->CHGControl5.val);
+       rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL6, pdata->power_data->CHGControl6.val);
+       //rt5025_reg_write(pi->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
+       rt5025_assign_bits(pi->i2c, RT5025_REG_CHGCTL7, 0xEF, pdata->power_data->CHGControl7.val);
+       rt5025_reg_write(pi->i2c, 0xA9, 0x60 );
+       return 0;
+}
+EXPORT_SYMBOL(rt5025_charger_reset_and_reinit);
 
 static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value)
 {
@@ -62,6 +110,7 @@ static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value)
        u8 data = 0;
 
        //ICC Setting
+       #if 0
        if (cur_value > 2000)
                data |= 0x0f<<3;
        else if (cur_value >= 500 && cur_value <= 2000)
@@ -69,7 +118,7 @@ static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value)
                data = (cur_value-500)/100;
                data<<=3;
        }
-       
+       #endif
 
        //AICR Setting
        if (cur_value > 1000)
@@ -79,7 +128,7 @@ static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value)
        else if (cur_value > 100 && cur_value >= 500)
                data |= 0x01<<1;
 
-       rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGCC_MASK, data);
+       rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGAICR_MASK, data);
        return ret;
 }
 
@@ -94,22 +143,53 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v
                        rt5025_set_charging_buck(info->i2c, 1);
                        #endif
                        info->chg_stat = 0x00;
+                       #if 1
+                       if (info->chip->battery_info)
+                       {
+                               if (info->chg_term <= 1)
+                                       rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_CHARGING);
+                               else if (info->chg_term == 2)
+                               {
+                                       rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_FULL);
+                                       //info->chg_term = 0;
+                               }
+                               else if (info->chg_term > 2)
+                                       ;
+                       }
+                       #else
                        if (info->event_callback)
                                info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
+                       #endif
                        break;
                case 0x01:
                        //rt5025_set_charging_current_switch(info->i2c, 1);
                        info->chg_stat = 0x01;
+                       #if 1
+                       if (info->chip->battery_info)
+                       {
+                               rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_CHARGING);
+                               info->chg_term = 0;
+                       }
+                       #else
                        if (info->event_callback)
                                info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING);
+                       #endif
                        break;
                case 0x02:
                        #if 0
                        rt5025_set_charging_current_switch(info->i2c, 0);
                        #endif
                        info->chg_stat = 0x02;
+                       #if 1
+                       if (info->chip->battery_info)
+                       {
+                               rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_FULL);
+                               info->chg_term = 0;
+                       }
+                       #else
                        if (info->event_callback)
                                info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL);
+                       #endif
                        break;
                case 0x03:
                        #if 0
@@ -117,8 +197,23 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v
                        rt5025_set_charging_current_switch(info->i2c, 0);
                        #endif
                        info->chg_stat = 0x03;
+                       #if 1
+                       if (info->chip->battery_info)
+                       {
+                               if (info->chg_term <= 1)
+                                       rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_CHARGING);
+                               else if (info->chg_term == 2)
+                               {
+                                       rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_FULL);
+                                       //info->chg_term = 0;
+                               }
+                               else if (info->chg_term > 2)
+                                       ;
+                       }
+                       #else
                        if (info->event_callback)
                                info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
+                       #endif
                        break;
                default:
                        break;
@@ -126,6 +221,7 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v
        return ret;
 }
 
+#if 0
 int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
 {
        if (info->event_callback)
@@ -133,6 +229,7 @@ int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info)
        return 0;
 }
 EXPORT_SYMBOL(rt5025_power_passirq_to_gauge);
+#endif
 
 int rt5025_power_charge_detect(struct rt5025_power_info *info)
 {
@@ -143,6 +240,8 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info)
        old_acval = info->ac_online;
        old_usbval = info->usb_online;
        old_chgval = info->chg_stat;
+
+       mdelay(50);
        
        ret = rt5025_reg_read(info->i2c, RT5025_REG_CHGSTAT);
        if (ret<0)
@@ -151,6 +250,13 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info)
                return ret;
        }
        chgstatval = ret;
+       RTINFO("chgstat = 0x%02x\n", chgstatval);
+
+       if (info->otg_en)
+       {
+               ret = rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+               msleep(100);
+       }
 
        new_acval = (chgstatval&RT5025_CHG_ACONLINE)>>RT5025_CHG_ACSHIFT;
        if (old_acval != new_acval)
@@ -158,23 +264,36 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info)
                info->ac_online = new_acval;
                power_supply_changed(&info->ac);
        }
-       new_usbval = (chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT;
+
+       new_usbval = (info->otg_en? \
+               0:(chgstatval&RT5025_CHG_USBONLINE)>>RT5025_CHG_USBSHIFT);
        if (old_usbval != new_usbval)
        {
                info->usb_online = new_usbval;
                power_supply_changed(&info->usb);
        }
 
-       if (old_acval != new_acval || old_usbval != new_usbval)
+       if (info->otg_en && new_acval == 0)
+       {
+               ret = rt5025_clr_bits(info->i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK);
+               msleep(100);
+       }
+
+       //if (old_acval != new_acval || old_usbval != new_usbval)
+       if (new_acval || new_usbval)
+       {
+               info->usb_cnt = 0;
                schedule_delayed_work(&info->usb_detect_work, 0); //no delay
+       }
 
        new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT;
+       
        if (new_acval || new_usbval)
        {
-               if (old_chgval != new_chgval)
-               {
+               //if (old_chgval != new_chgval)
+               //{
                        ret = rt5025_chgstat_changed(info, new_chgval);
-               }
+               //}
        }
        else
        {
@@ -183,8 +302,15 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info)
                rt5025_set_charging_current_switch(info->i2c, 0);
                #endif
                info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
+               if (info->chip->jeita_info)
+                       rt5025_notify_charging_cable(info->chip->jeita_info, JEITA_NO_CHARGE);
+               #if 1
+               if (info->chip->battery_info)
+                       rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_DISCHARGING);
+               #else
                if (info->event_callback)
                        info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING);
+               #endif
        }
 
        return ret;
@@ -212,34 +338,39 @@ static int rt5025_adap_get_props(struct power_supply *psy,
        return 0;
 }
 
+
 extern int dwc_vbus_status(void);
 
+
 static void usb_detect_work_func(struct work_struct *work)
 {
        struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work);
        struct rt5025_power_info *pi = (struct rt5025_power_info *)container_of(delayed_work, struct rt5025_power_info, usb_detect_work);
        
-       pr_info("rt5025: %s ++", __func__);
+       RTINFO("rt5025: %s ++", __func__);
 
        mutex_lock(&pi->var_lock);
        if (pi->ac_online)
        {
-               rt5025_set_charging_current(pi->i2c, 1000);
+               rt5025_set_charging_current(pi->i2c, 2000);
+               rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_AC_ADAPTER);
                pi->usb_cnt = 0;
        }
        else if (pi->usb_online)
        {
-               pr_info("%s: usb_cnt %d\n", __func__, pi->usb_cnt);
+               RTINFO("%s: usb_cnt %d\n", __func__, pi->usb_cnt);
                switch(dwc_vbus_status())
                {
                        case 2: // USB Wall charger
-                               rt5025_set_charging_current(pi->i2c, 1000);
-                               pr_info("rt5025: detect usb wall charger\n");
+                               rt5025_set_charging_current(pi->i2c, 2000);
+                               rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_USB_TA);
+                               RTINFO("rt5025: detect usb wall charger\n");
                                break;
                        case 1: //normal USB
                        default:
-                               rt5025_set_charging_current(pi->i2c, 500);
-                               pr_info("rt5025: detect normal usb\n");
+                               rt5025_set_charging_current(pi->i2c, 2000);
+                               rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_NORMAL_USB);
+                               RTINFO("rt5025: detect normal usb\n");
                                break;
                }
                if (pi->usb_cnt++ < 60)
@@ -249,36 +380,55 @@ static void usb_detect_work_func(struct work_struct *work)
        {
                //default to prevent over current charging
                rt5025_set_charging_current(pi->i2c, 500);
+               rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_NO_CHARGE);
                //reset usb_cnt;
                pi->usb_cnt = 0;
        }
        mutex_unlock(&pi->var_lock);
 
-       pr_info("rt5025: %s --", __func__);
+       RTINFO("rt5025: %s --", __func__);
 }
 
 static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd)
 {
-       RTINFO("++\n");
+       //unsigned char data;
        info->ac_online = 0;
        info->usb_online =0;
        //init charger buckck & charger current en to disable stat
        info->chg_stat = RT5025_CHGSTAT_UNKNOWN;
+       #if 0
        if (info->event_callback)
                info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING);
-       rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK);
-       udelay(200);
+       #endif
+       //rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK);
+       //udelay(200);
        //init register setting
        rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL2, pd->CHGControl2.val);
        rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL3, pd->CHGControl3.val);
        rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL4, pd->CHGControl4.val);
        rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL5, pd->CHGControl5.val);
        rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL6, pd->CHGControl6.val);
-       rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
+       //rt5025_reg_write(info->i2c, RT5025_REG_CHGCTL7, pd->CHGControl7.val);
+       rt5025_assign_bits(info->i2c, RT5025_REG_CHGCTL7, 0xEF, pd->CHGControl7.val);
+       rt5025_reg_write(info->i2c, 0xA9, 0x60 );
+       //Special buck setting
+       #if 0
+       //Buck 1
+       data = rt5025_reg_read(info->i2c, 0x47);
+       data ^=0xc2;
+       rt5025_reg_write(info->i2c, 0x47, data);
+       //Buck 2
+       data = rt5025_reg_read(info->i2c, 0x48);
+       data ^=0xc2;
+       rt5025_reg_write(info->i2c, 0x48, data);
+       //Buck 3
+       data = rt5025_reg_read(info->i2c, 0x49);
+       data ^=0xc2;
+       rt5025_reg_write(info->i2c, 0x49, data);
+       #endif  //#if 0
        
        rt5025_power_charge_detect(info);
 
-       RTINFO("--\n");
        return 0;
 }
 
@@ -288,25 +438,27 @@ static int __devinit rt5025_power_probe(struct platform_device *pdev)
        struct rt5025_platform_data *pdata = chip->dev->platform_data;
        struct rt5025_power_info *pi;
        int ret = 0;
-       printk("%s,line=%d\n", __func__,__LINE__);      
-
+       
        pi = kzalloc(sizeof(*pi), GFP_KERNEL);
        if (!pi)
                return -ENOMEM;
 
        pi->i2c = chip->i2c;
        pi->dev = &pdev->dev;
-       pi->fcc = pdata->power_data->fcc;
+       pi->chip = chip;
        mutex_init(&pi->var_lock);
        INIT_DELAYED_WORK(&pi->usb_detect_work, usb_detect_work_func);
 
+       #if 0
        ret = rt5025_gauge_init(pi);
        if (ret)
                goto out;
+       #endif
 
        platform_set_drvdata(pdev, pi);
+       dev_ptr = pdev;
 
-       pi->ac.name = "rt5025-ac";
+       pi->ac.name = "rt5025-dc";
        pi->ac.type = POWER_SUPPLY_TYPE_MAINS;
        pi->ac.supplied_to = rt5025_supply_list;
        pi->ac.properties = rt5025_adap_props;
@@ -329,6 +481,8 @@ static int __devinit rt5025_power_probe(struct platform_device *pdev)
        rt5025_init_charger(pi, pdata->power_data);
        chip->power_info = pi;
 
+       pr_info("rt5025-power driver is successfully loaded\n");
+
        return ret;
 out_usb:
        power_supply_unregister(&pi->ac);
@@ -340,18 +494,25 @@ out:
 
 static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state)
 {
+       #if 0
        struct rt5025_power_info *pi = platform_get_drvdata(pdev);
 
        if (pi->event_callback)
                pi->event_callback->rt5025_gauge_suspend();
+       #endif
+       RTINFO("\n");
        return 0;
 }
 
 static int rt5025_power_resume(struct platform_device *pdev)
 {
+       #if 0
        struct rt5025_power_info *pi = platform_get_drvdata(pdev);
+
        if (pi->event_callback)
                pi->event_callback->rt5025_gauge_resume();
+       #endif
+       RTINFO("\n");
        return 0;
 }
 
@@ -360,12 +521,15 @@ static int __devexit rt5025_power_remove(struct platform_device *pdev)
        struct rt5025_power_info *pi = platform_get_drvdata(pdev);
        struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
 
+       #if 0
        if (pi->event_callback)
                pi->event_callback->rt5025_gauge_remove();
+       #endif
        power_supply_unregister(&pi->usb);
        power_supply_unregister(&pi->ac);
        chip->power_info = NULL;
        kfree(pi);
+       RTINFO("\n");
 
        return 0;
 }
@@ -386,7 +550,7 @@ static int __init rt5025_power_init(void)
 {
        return platform_driver_register(&rt5025_power_driver);
 }
-subsys_initcall_sync(rt5025_power_init);
+late_initcall_sync(rt5025_power_init);
 
 static void __exit rt5025_power_exit(void)
 {
@@ -399,3 +563,4 @@ MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
 MODULE_DESCRIPTION("Power/Gauge driver for RT5025");
 MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-power");
+MODULE_VERSION(RT5025_DRV_VER);