summaryrefslogtreecommitdiff
path: root/drivers/power/rt5033_charger.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/power/rt5033_charger.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/power/rt5033_charger.c')
-rw-r--r--drivers/power/rt5033_charger.c1359
1 files changed, 1359 insertions, 0 deletions
diff --git a/drivers/power/rt5033_charger.c b/drivers/power/rt5033_charger.c
new file mode 100644
index 00000000..fe41958f
--- /dev/null
+++ b/drivers/power/rt5033_charger.c
@@ -0,0 +1,1359 @@
+/* drivers/battery/rt5033_charger.c
+ * RT5033 Charger Driver
+ *
+ * Copyright (C) 2013 Richtek Technology Corp.
+ * Author: Patrick Chang <patrick_chang@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/battery/sec_charger.h>
+#ifdef CONFIG_USB_HOST_NOTIFY
+#include <linux/host_notify.h>
+#include <mach/usb3-drd.h>
+#endif
+
+#include <linux/mfd/rt5033.h>
+
+#ifdef CONFIG_FLED_RT5033
+#include <linux/leds/rt5033_fled.h>
+#include <linux/leds/rtfled.h>
+#endif /* CONFIG_FLED_RT5033 */
+#include <linux/version.h>
+
+#define ENABLE_MIVR 1
+
+#define EN_BAD_ADP_IRQ 1
+#define EN_OVP_IRQ 1
+#define EN_IEOC_IRQ 1
+#define EN_RECHG_REQ_IRQ 0
+#define EN_TR_IRQ 0
+#define EN_MIVR_SW_REGULATION 0
+#define EN_BST_IRQ 0
+#define MINVAL(a, b) ((a <= b) ? a : b)
+
+#define EOC_DEBOUNCE_CNT 3
+#define HEALTH_DEBOUNCE_CNT 3
+
+#define EOC_SLEEP 200
+/* Timeout setting should be larger than wakelock setting
+ * * to let CPU have enough time to go sleeping */
+#define EOC_TIMEOUT (10 * 1000)
+/* 9.9 second */
+#define BADADP_RESTART_TIMER (9900)
+
+#ifndef EN_TEST_READ
+#define EN_TEST_READ 0
+#endif
+
+static int rt5033_reg_map[] = {
+ RT5033_CHG_STAT_CTRL,
+ RT5033_CHG_CTRL1,
+ RT5033_CHG_CTRL2,
+ RT5033_CHG_CTRL3,
+ RT5033_CHG_CTRL4,
+ RT5033_CHG_CTRL5,
+ RT5033_CHG_RESET,
+ RT5033_UUG,
+};
+
+typedef struct rt5033_charger_data {
+ rt5033_mfd_chip_t *rt5033;
+ struct power_supply psy_chg;
+ rt5033_charger_platform_data_t *pdata;
+ int eoc_cnt;
+ int charging_current;
+ int siop_level;
+ int cable_type;
+ bool is_charging;
+ struct mutex io_lock;
+ /* register programming */
+ int reg_addr;
+ int reg_data;
+
+ bool full_charged;
+ bool ovp;
+ int unhealth_cnt;
+ struct workqueue_struct *wq;
+ struct delayed_work eoc_timeout_work;
+#if EN_BAD_ADP_IRQ
+ struct delayed_work activate_bad_adp_work;
+#endif /* EN_BAD_ADP_IRQ */
+ int status;
+#ifdef CONFIG_FLED_RT5033
+ struct rt_fled_info *fled_info;
+#endif /* CONFIG_FLED_RT5033 */
+} rt5033_charger_data_t;
+
+static enum power_supply_property sec_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL,
+};
+
+static int rt5033_get_charging_health(
+ struct rt5033_charger_data *charger);
+
+static void rt5033_read_regs(struct i2c_client *i2c, char *str)
+{
+ u8 data = 0;
+ int i = 0;
+ for (i = 0; i < ARRAY_SIZE(rt5033_reg_map); i++) {
+ data = rt5033_reg_read(i2c, rt5033_reg_map[i]);
+ sprintf(str + strlen(str), "0x%02x, ", data);
+ }
+}
+
+static void rt5033_test_read(struct i2c_client *i2c)
+{
+ int data = 0;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(rt5033_reg_map); i++) {
+ data = rt5033_reg_read(i2c, rt5033_reg_map[i]);
+ pr_info("rt50333: c: 0x%02x(0x%02x)\n", i, data);
+ }
+}
+
+static void rt5033_charger_otg_control(struct rt5033_charger_data *charger,
+ bool enable)
+{
+ struct i2c_client *i2c = charger->rt5033->i2c_client;
+
+ pr_info("%s: called charger otg control : %s\n", __func__,
+ enable ? "on" : "off");
+
+ if (!enable) {
+ /* turn off OTG */
+ rt5033_clr_bits(i2c, RT5033_CHG_CTRL1, RT5033_OPAMODE_MASK);
+#ifdef CONFIG_FLED_RT5033
+ if (charger->fled_info == NULL)
+ charger->fled_info = rt_fled_get_info_by_name(NULL);
+ if (charger->fled_info)
+ rt5033_boost_notification(charger->fled_info, 0);
+#endif /* CONFIG_FLED_RT5033 */
+ } else {
+ /* Set OTG boost vout = 5V, turn on OTG */
+ rt5033_assign_bits(charger->rt5033->i2c_client,
+ RT5033_CHG_CTRL2, RT5033_VOREG_MASK,
+ 0x37 << RT5033_VOREG_SHIFT);
+ rt5033_set_bits(charger->rt5033->i2c_client,
+ RT5033_CHG_CTRL1, RT5033_OPAMODE_MASK);
+ rt5033_clr_bits(charger->rt5033->i2c_client,
+ RT5033_CHG_CTRL1, RT5033_HZ_MASK);
+ charger->cable_type = POWER_SUPPLY_TYPE_OTG;
+#ifdef CONFIG_FLED_RT5033
+ if (charger->fled_info == NULL)
+ charger->fled_info = rt_fled_get_info_by_name(NULL);
+ if (charger->fled_info)
+ rt5033_boost_notification(charger->fled_info, 1);
+#endif /* CONFIG_FLED_RT5033 */
+ }
+}
+
+/* this function will work well on CHIP_REV = 3 or later */
+static void rt5033_enable_charger_switch(struct rt5033_charger_data *charger,
+ int onoff)
+{
+ int prev_charging_status = charger->is_charging;
+ struct i2c_client *iic = charger->rt5033->i2c_client;
+
+ charger->is_charging = onoff ? true : false;
+ if ((onoff > 0) && (prev_charging_status == false)) {
+ charger->full_charged = false;
+ pr_info("%s: turn on charger\n", __func__);
+#ifdef CONFIG_MFD_RT5033_EN_MRSTB
+ /* Disable Manual Reset */
+ rt5033_clr_bits(iic, 0x47, 1 << 3);
+#endif /* CONFIG_MFD_RT5033_EN_MRSTB */
+#ifdef CONFIG_FLED_RT5033
+ if (charger->fled_info == NULL)
+ charger->fled_info = rt_fled_get_info_by_name(NULL);
+ if (charger->fled_info)
+ rt5033_charger_notification(charger->fled_info, 1);
+#endif /* CONFIG_FLED_RT5033 */
+ rt5033_clr_bits(iic, RT5033_CHG_STAT_CTRL, RT5033_CHGENB_MASK);
+ rt5033_clr_bits(iic, RT5033_CHG_CTRL1, RT5033_HZ_MASK);
+ rt5033_set_bits(iic, RT5033_CHG_CTRL3, RT5033_COF_EN_MASK);
+ /* Reset EOC loop, and make it re-detect */
+ charger->eoc_cnt = 0;
+ rt5033_set_bits(iic, RT5033_EOC_CTRL, RT5033_EOC_RESET_MASK);
+ rt5033_clr_bits(iic, RT5033_EOC_CTRL, RT5033_EOC_RESET_MASK);
+ } else if (onoff == 0) {
+ charger->full_charged = false;
+ pr_info("%s: turn off charger\n", __func__);
+#ifdef CONFIG_MFD_RT5033_EN_MRSTB
+ /* Enable Manual Reset */
+ rt5033_set_bits(iic, 0x47, 1 << 3);
+#endif /* CONFIG_MFD_RT5033_EN_MRSTB */
+ charger->charging_current = 0;
+ charger->eoc_cnt = 0;
+#ifdef CONFIG_FLED_RT5033
+ if (charger->fled_info == NULL)
+ charger->fled_info = rt_fled_get_info_by_name(NULL);
+ if (charger->fled_info)
+ rt5033_charger_notification(charger->fled_info, 0);
+#endif /* CONFIG_FLED_RT5033 */
+ rt5033_set_bits(iic, RT5033_CHG_STAT_CTRL, RT5033_CHGENB_MASK);
+ } else {
+ pr_info("%s: repeated to set charger switch(%d), prev stat = %d\n",
+ __func__, onoff, prev_charging_status ? 1 : 0);
+ }
+}
+
+static void rt5033_enable_charging_termination(struct i2c_client *i2c,
+ int onoff)
+{
+ pr_info("%s:[BATT] Do termination set(%d)\n", __func__, onoff);
+ if (onoff)
+ rt5033_set_bits(i2c, RT5033_CHG_CTRL1, RT5033_TEEN_MASK);
+ else
+ rt5033_clr_bits(i2c, RT5033_CHG_CTRL1, RT5033_TEEN_MASK);
+}
+
+static int rt5033_input_current_limit[] = {
+ 100,
+ 500,
+ 700,
+ 900,
+ 1000,
+ 1500,
+ 2000,
+};
+
+static int __r5033_current_limit_to_setting(int current_limit)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(rt5033_input_current_limit); i++) {
+ if (current_limit <= rt5033_input_current_limit[i])
+ return i + 1;
+ }
+
+ return -EINVAL;
+}
+
+static void rt5033_set_input_current_limit(struct rt5033_charger_data *charger,
+ int current_limit)
+{
+ struct i2c_client *i2c = charger->rt5033->i2c_client;
+ int data = __r5033_current_limit_to_setting(current_limit);
+
+ if (data < 0)
+ data = 0;
+ mutex_lock(&charger->io_lock);
+ rt5033_assign_bits(i2c, RT5033_CHG_CTRL1, RT5033_AICR_LIMIT_MASK,
+ (data) << RT5033_AICR_LIMIT_SHIFT);
+ mutex_unlock(&charger->io_lock);
+}
+
+static int rt5033_get_input_current_limit(struct i2c_client *i2c)
+{
+ int ret;
+ ret = rt5033_reg_read(i2c, RT5033_CHG_CTRL1);
+ if (ret < 0)
+ return ret;
+ ret &= RT5033_AICR_LIMIT_MASK;
+ ret >>= RT5033_AICR_LIMIT_SHIFT;
+ if (ret == 0)
+ return 2000 + 1; // no limitation
+ return rt5033_input_current_limit[ret - 1];
+}
+
+static void rt5033_set_regulation_voltage(struct rt5033_charger_data *charger,
+ int float_voltage)
+{
+ struct i2c_client *i2c = charger->rt5033->i2c_client;
+ int data;
+
+ if (float_voltage < 3650)
+ data = 0;
+ else if (float_voltage >= 3650 && float_voltage <= 4400)
+ data = (float_voltage - 3650) / 25;
+ else
+ data = 0x3f;
+ mutex_lock(&charger->io_lock);
+ rt5033_assign_bits(i2c, RT5033_CHG_CTRL2, RT5033_VOREG_MASK,
+ data << RT5033_VOREG_SHIFT);
+ mutex_unlock(&charger->io_lock);
+}
+
+static void __rt5033_set_fast_charging_current(struct i2c_client *i2c,
+ int charging_current)
+{
+ int data;
+
+ if (charging_current < 700)
+ data = 0;
+ else if (charging_current >= 700 && charging_current <= 2000)
+ data = (charging_current - 700) / 100;
+ else
+ data = 0xd;
+
+ rt5033_assign_bits(i2c, RT5033_CHG_CTRL5, RT5033_ICHRG_MASK,
+ data << RT5033_ICHRG_SHIFT);
+}
+
+static int rt5033_eoc_level[] = {
+ 0,
+ 150,
+ 200,
+ 250,
+ 300,
+ 400,
+ 500,
+ 600,
+};
+
+static int rt5033_get_eoc_level(int eoc_current)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(rt5033_eoc_level); i++) {
+ if (eoc_current < rt5033_eoc_level[i]) {
+ if (i == 0)
+ return 0;
+ return i - 1;
+ }
+ }
+ return ARRAY_SIZE(rt5033_eoc_level) - 1;
+}
+
+static int rt5033_get_current_eoc_setting(struct rt5033_charger_data *charger)
+{
+ int ret;
+ mutex_lock(&charger->io_lock);
+ ret = rt5033_reg_read(charger->rt5033->i2c_client, RT5033_CHG_CTRL4);
+ mutex_unlock(&charger->io_lock);
+ if (ret < 0) {
+ pr_info("%s: warning --> fail to read i2c register(%d)\n", __func__, ret);
+ return ret;
+ }
+ return rt5033_eoc_level[(RT5033_IEOC_MASK & ret) >> RT5033_IEOC_SHIFT];
+}
+
+static int rt5033_get_fast_charging_current(struct i2c_client *i2c)
+{
+ int data = rt5033_reg_read(i2c, RT5033_CHG_CTRL5);
+ if (data < 0)
+ return data;
+
+ data = (data >> 4) & 0x0f;
+
+ if (data > 0xd)
+ data = 0xd;
+ return data * 100 + 700;
+}
+
+static void __rt5033_set_termination_current_limit(struct i2c_client *i2c,
+ int current_limit)
+{
+ int data = rt5033_get_eoc_level(current_limit);
+ int ret;
+
+ pr_info("%s : Set Termination\n", __func__);
+
+ ret = rt5033_assign_bits(i2c, RT5033_CHG_CTRL4, RT5033_IEOC_MASK,
+ data << RT5033_IEOC_SHIFT);
+}
+
+static void rt5033_set_charging_current(struct rt5033_charger_data *charger,
+ int eoc, int reset_eoc)
+{
+ int adj_current = 0;
+
+ adj_current = charger->charging_current * charger->siop_level / 100;
+ mutex_lock(&charger->io_lock);
+ __rt5033_set_fast_charging_current(charger->rt5033->i2c_client,
+ adj_current);
+ if (reset_eoc) {
+ __rt5033_set_termination_current_limit(
+ charger->rt5033->i2c_client, 0);
+ /* set EOC RESET */
+ rt5033_set_bits(charger->rt5033->i2c_client,
+ RT5033_EOC_CTRL, RT5033_EOC_RESET_MASK);
+ /* clear EOC RESET */
+ rt5033_clr_bits(charger->rt5033->i2c_client,
+ RT5033_EOC_CTRL, RT5033_EOC_RESET_MASK);
+ }
+
+ __rt5033_set_termination_current_limit(
+ charger->rt5033->i2c_client, eoc);
+ mutex_unlock(&charger->io_lock);
+
+}
+
+enum {
+ RT5033_MIVR_DISABLE = 0,
+ RT5033_MIVR_4200MV,
+ RT5033_MIVR_4300MV,
+ RT5033_MIVR_4400MV,
+ RT5033_MIVR_4500MV,
+ RT5033_MIVR_4600MV,
+ RT5033_MIVR_4700MV,
+ RT5033_MIVR_4800MV,
+};
+
+#if ENABLE_MIVR
+/* Dedicated charger (non-USB) device
+ * will use lower MIVR level to get better performance
+ */
+static void rt5033_set_mivr_level(struct rt5033_charger_data *charger)
+{
+ int mivr;
+
+ switch(charger->cable_type) {
+ case POWER_SUPPLY_TYPE_USB ... POWER_SUPPLY_TYPE_USB_ACA:
+ mivr = RT5033_MIVR_4600MV;
+ break;
+ default:
+ mivr = RT5033_MIVR_DISABLE;
+ }
+ mutex_lock(&charger->io_lock);
+ rt5033_assign_bits(charger->rt5033->i2c_client,
+ RT5033_CHG_CTRL4, RT5033_MIVR_MASK, mivr << RT5033_MIVR_SHIFT);
+ mutex_unlock(&charger->io_lock);
+}
+#endif /*ENABLE_MIVR*/
+
+static void rt5033_configure_charger(struct rt5033_charger_data *charger)
+{
+ int eoc;
+ union power_supply_propval val;
+
+ pr_info("%s : Set config charging\n", __func__);
+ if (charger->charging_current < 0) {
+ pr_info("%s : OTG is activated. Ignore command!\n",
+ __func__);
+ return;
+ }
+ /* Before configure charging setting,
+ * * enable bad adaptor detection.
+ * * Set Reg0x07[5] = 0 -> enable bad adaptor detection */
+ rt5033_clr_bits(charger->rt5033->i2c_client,
+ RT5033_EOC_CTRL, (1 << 5));
+#if ENABLE_MIVR
+ rt5033_set_mivr_level(charger);
+#endif /*DISABLE_MIVR*/
+ psy_do_property("battery", get,
+ POWER_SUPPLY_PROP_CHARGE_NOW, val);
+
+ /* Input current limit */
+ pr_info("%s : input current (%dmA)\n",
+ __func__, charger->pdata->charging_current_table
+ [charger->cable_type].input_current_limit);
+
+ rt5033_set_input_current_limit(charger,
+ charger->pdata->charging_current_table
+ [charger->cable_type].input_current_limit);
+
+ /* Float voltage */
+ pr_info("%s : float voltage (%dmV)\n",
+ __func__, charger->pdata->chg_float_voltage);
+
+ rt5033_set_regulation_voltage(charger,
+ charger->pdata->chg_float_voltage);
+
+ charger->charging_current = charger->pdata->charging_current_table
+ [charger->cable_type].fast_charging_current;
+ eoc = charger->pdata->charging_current_table
+ [charger->cable_type].full_check_current_1st;
+ /* Fast charge and Termination current */
+ pr_info("%s : fast charging current (%dmA)\n",
+ __func__, charger->charging_current);
+
+ pr_info("%s : termination current (%dmA)\n",
+ __func__, eoc);
+
+ rt5033_set_charging_current(charger, eoc, 1);
+ rt5033_enable_charger_switch(charger, 1);
+}
+
+int rt5033_chg_fled_init(struct i2c_client *client)
+{
+ int ret, rev_id;
+ rt5033_mfd_chip_t *chip = i2c_get_clientdata(client);
+ int is_750k_switching = 0;
+ int is_fixed_switching = 0;
+ struct rt5033_charger_data *charger = chip->charger;
+ /* if charger had loaded, we can get platform data */
+ if (charger) {
+ is_750k_switching = charger->pdata->is_fixed_switching;
+ is_fixed_switching = charger->pdata->is_750kHz_switching;
+ pr_info("rt5033 chg: is_750k_switching = %d, is_fixed_switching = %d\n",
+ is_750k_switching, is_fixed_switching);
+ }
+ rt5033_set_bits(client, 0x6b, 0x01);
+ usleep_range(100, 100); /* delay 100 us to wait for normal read (from e-fuse) */
+ ret = rt5033_reg_read(client, 0x03);
+ rt5033_clr_bits(client, 0x6b, 0x01);
+ if (ret < 0)
+ pr_err("%s : failed to read revision ID\n", __func__);
+ rev_id = ret & 0x0f;
+ if (rev_id >= 4) {
+ if (charger) {
+
+ if (is_fixed_switching)
+ ret = rt5033_set_bits(client, 0x22, 0x04);
+ else
+ ret = rt5033_clr_bits(client, 0x22, 0x04);
+ if (ret < 0)
+ goto rt5033_chg_fled_init_exit;
+ if (is_750k_switching)
+ ret = rt5033_set_bits(client, RT5033_CHG_CTRL1,
+ RT5033_SEL_SWFREQ_MASK);
+ else
+ ret = rt5033_clr_bits(client, RT5033_CHG_CTRL1,
+ RT5033_SEL_SWFREQ_MASK);
+ if (ret < 0)
+ goto rt5033_chg_fled_init_exit;
+ }
+ /* Enable charging CV High-GM, reg0x22 bit 5 */
+ ret = rt5033_set_bits(client, 0x22, 0x20);
+ } else {
+ /* Set switching frequency to 0.75MHz for old revision IC*/
+ ret = rt5033_set_bits(client, RT5033_CHG_CTRL1,
+ RT5033_SEL_SWFREQ_MASK);
+ }
+rt5033_chg_fled_init_exit:
+ return ret;
+}
+EXPORT_SYMBOL(rt5033_chg_fled_init);
+
+
+/* here is set init charger data */
+static bool rt5033_chg_init(struct rt5033_charger_data *charger)
+{
+ rt5033_mfd_chip_t *chip = i2c_get_clientdata(charger->rt5033->i2c_client);
+ chip->charger = charger;
+ rt5033_chg_fled_init(charger->rt5033->i2c_client);
+ /* Disable Timer function (Charging timeout fault) */
+ rt5033_clr_bits(charger->rt5033->i2c_client,
+ RT5033_CHG_CTRL3, RT5033_TIMEREN_MASK);
+ /* Disable TE */
+ rt5033_enable_charging_termination(charger->rt5033->i2c_client, 0);
+
+ /* Enable High-GM */
+ rt5033_set_bits(charger->rt5033->i2c_client,
+ 0x07, 0xC0);
+
+ /* EMI improvement , let reg0x18 bit2~5 be 1100*/
+ rt5033_assign_bits(charger->rt5033->i2c_client, 0x18, 0x3C, 0x30);
+
+ /* MUST set correct regulation voltage first
+ * Before MUIC pass cable type information to charger
+ * charger would be already enabled (default setting)
+ * it might cause EOC event by incorrect regulation voltage */
+ rt5033_set_regulation_voltage(charger,
+ charger->pdata->chg_float_voltage);
+
+#if !(ENABLE_MIVR)
+ rt5033_assign_bits(charger->rt5033->i2c_client,
+ RT5033_CHG_CTRL4, RT5033_MIVR_MASK,
+ RT5033_MIVR_DISABLE << RT5033_MIVR_SHIFT);
+#endif
+ /* Set Reg0x07[5] = 0 -> enable bad adaptor detection */
+ rt5033_clr_bits(charger->rt5033->i2c_client,
+ RT5033_EOC_CTRL, (1 << 5));
+ return true;
+}
+
+static int rt5033_get_charging_status(struct rt5033_charger_data *charger)
+{
+ int status = POWER_SUPPLY_STATUS_UNKNOWN;
+ int ret;
+
+#ifdef CONFIG_USB_HOST_NOTIFY
+ struct host_notifier_platform_data *host_noti_pdata =
+ host_notifier_device.dev.platform_data;
+#endif
+
+ ret = rt5033_reg_read(charger->rt5033->i2c_client, RT5033_CHG_STAT_CTRL);
+ if (ret < 0) {
+ pr_info("Error : can't get charging status (%d)\n", ret);
+
+ }
+
+ if (charger->full_charged)
+ return POWER_SUPPLY_STATUS_FULL;
+
+ switch (ret & 0x30) {
+ case 0x00:
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case 0x20:
+ case 0x10: // Only use flag "full_charged"
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case 0x30:
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ }
+
+ /* TEMP_TEST : when OTG is enabled(charging_current -1), handle OTG func. */
+ if (charger->charging_current < 0) {
+ /* For OTG mode, RT5033 would still report "charging" */
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ ret = rt5033_reg_read(charger->rt5033->i2c_client, RT5033_CHG_IRQ3);
+ if (ret & 0x80) {
+ pr_info("%s: otg overcurrent limit\n", __func__);
+#ifdef CONFIG_USB_HOST_NOTIFY
+ host_state_notify(&host_noti_pdata->ndev,
+ NOTIFY_HOST_OVERCURRENT);
+#endif
+ rt5033_charger_otg_control(charger, false);
+ }
+
+ }
+
+ return status;
+}
+
+static int rt5033_get_charge_type(struct i2c_client *iic)
+{
+ int status = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ int ret;
+
+ ret = rt5033_reg_read(iic, RT5033_CHG_STAT_CTRL);
+ if (ret < 0)
+ dev_err(&iic->dev, "%s fail\n", __func__);
+
+ switch (ret & 0x40) {
+ case 0x40:
+ status = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ default:
+ /* pre-charge mode */
+ status = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ }
+
+ return status;
+}
+
+static int rt5033_get_charging_health(struct rt5033_charger_data *charger)
+{
+ int ret = rt5033_reg_read(charger->rt5033->i2c_client, RT5033_CHG_STAT_CTRL);
+
+ if (ret < 0)
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+
+ /* Boost mode = 1 or PWR ready = 1*/
+ if (ret & (0x03 << 2)) {
+ charger->ovp = false;
+ charger->unhealth_cnt = 0;
+ return POWER_SUPPLY_HEALTH_GOOD;
+ }
+ charger->unhealth_cnt++;
+ if (charger->unhealth_cnt < HEALTH_DEBOUNCE_CNT)
+ return POWER_SUPPLY_HEALTH_GOOD;
+
+ charger->unhealth_cnt = HEALTH_DEBOUNCE_CNT;
+ if (charger->ovp)
+ return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+}
+
+static int sec_chg_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int chg_curr, aicr;
+ struct rt5033_charger_data *charger =
+ container_of(psy, struct rt5033_charger_data, psy_chg);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = charger->charging_current ? 1 : 0;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = rt5033_get_charging_status(charger);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = rt5033_get_charging_health(charger);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = 2000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ if (charger->charging_current) {
+ aicr = rt5033_get_input_current_limit(charger->rt5033->i2c_client);
+ chg_curr = rt5033_get_fast_charging_current(charger->rt5033->i2c_client);
+ val->intval = MINVAL(aicr, chg_curr);
+ } else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = rt5033_get_charge_type(charger->rt5033->i2c_client);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sec_chg_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rt5033_charger_data *charger =
+ container_of(psy, struct rt5033_charger_data, psy_chg);
+
+ int eoc;
+ int previous_cable_type = charger->cable_type;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ charger->status = val->intval;
+ break;
+ /* val->intval : type */
+ case POWER_SUPPLY_PROP_ONLINE:
+ charger->cable_type = val->intval;
+ if (charger->cable_type == POWER_SUPPLY_TYPE_BATTERY ||
+ charger->cable_type == POWER_SUPPLY_TYPE_UNKNOWN) {
+ pr_info("%s:[BATT] Type Battery\n", __func__);
+ rt5033_enable_charger_switch(charger, 0);
+
+ if (previous_cable_type == POWER_SUPPLY_TYPE_OTG)
+ rt5033_charger_otg_control(charger, false);
+ } else if (charger->cable_type == POWER_SUPPLY_TYPE_OTG) {
+ pr_info("%s: OTG mode\n", __func__);
+ rt5033_charger_otg_control(charger, true);
+ } else {
+ pr_info("%s:[BATT] Set charging"
+ ", Cable type = %d\n", __func__, charger->cable_type);
+ /* Enable charger */
+ rt5033_configure_charger(charger);
+ }
+#if EN_TEST_READ
+ msleep(100);
+ rt5033_test_read(charger->rt5033->i2c_client);
+#endif
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ /* set charging current */
+ if (charger->is_charging) {
+ /* decrease the charging current according to siop level */
+ charger->siop_level = val->intval;
+ pr_info("%s:SIOP level = %d, chg current = %d\n", __func__,
+ val->intval, charger->charging_current);
+ eoc = rt5033_get_current_eoc_setting(charger);
+ rt5033_set_charging_current(charger, eoc, 0);
+ }
+ break;
+ case POWER_SUPPLY_PROP_POWER_NOW:
+ eoc = rt5033_get_current_eoc_setting(charger);
+ pr_info("%s:Set Power Now -> chg current = %d mA, eoc = %d mA\n", __func__,
+ val->intval, eoc);
+ rt5033_set_charging_current(charger, eoc, 0);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL:
+ rt5033_charger_otg_control(charger, val->intval);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+ssize_t rt5033_chg_show_attrs(struct device *dev,
+ const ptrdiff_t offset, char *buf)
+{
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct rt5033_charger_data *charger =
+ container_of(psy, struct rt5033_charger_data, psy_chg);
+ int i = 0;
+ char *str = NULL;
+
+ switch (offset) {
+ case CHG_REG:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
+ charger->reg_addr);
+ break;
+ case CHG_DATA:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
+ charger->reg_data);
+ break;
+ case CHG_REGS:
+ str = kzalloc(sizeof(char) * 256, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+
+ rt5033_read_regs(charger->rt5033->i2c_client, str);
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
+ str);
+
+ kfree(str);
+ break;
+ default:
+ i = -EINVAL;
+ break;
+ }
+
+ return i;
+}
+
+ssize_t rt5033_chg_store_attrs(struct device *dev,
+ const ptrdiff_t offset,
+ const char *buf, size_t count)
+{
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct rt5033_charger_data *charger =
+ container_of(psy, struct rt5033_charger_data, psy_chg);
+
+ int ret = 0;
+ int x = 0;
+ uint8_t data = 0;
+
+ switch (offset) {
+ case CHG_REG:
+ if (sscanf(buf, "%x\n", &x) == 1) {
+ charger->reg_addr = x;
+ data = rt5033_reg_read(charger->rt5033->i2c_client,
+ charger->reg_addr);
+ charger->reg_data = data;
+ dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n",
+ __func__, charger->reg_addr, charger->reg_data);
+ ret = count;
+ }
+ break;
+ case CHG_DATA:
+ if (sscanf(buf, "%x\n", &x) == 1) {
+ data = (u8)x;
+
+ dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n",
+ __func__, charger->reg_addr, data);
+ ret = rt5033_reg_write(charger->rt5033->i2c_client,
+ charger->reg_addr, data);
+ if (ret < 0) {
+ dev_dbg(dev, "I2C write fail Reg0x%x = 0x%x\n",
+ (int)charger->reg_addr, (int)data);
+ }
+ ret = count;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+struct rt5033_chg_irq_handler {
+ char *name;
+ int irq_index;
+ irqreturn_t (*handler)(int irq, void *data);
+};
+
+#if EN_BAD_ADP_IRQ
+
+static void rt5033chg_activate_bad_adp(
+ struct work_struct *work)
+{
+ rt5033_charger_data_t *charger =
+ container_of(to_delayed_work(work),
+ rt5033_charger_data_t,
+ activate_bad_adp_work);
+#if ENABLE_MIVR
+ /* Restore MIVR setting */
+ rt5033_set_mivr_level(charger);
+#endif
+ /* Set Reg0x07[5] = 0 -> enable bad adaptor detection */
+ rt5033_clr_bits(charger->rt5033->i2c_client,
+ RT5033_EOC_CTRL, (1 << 5));
+}
+
+static irqreturn_t rt5033_chg_bad_adp_irq_handler(int irq,
+ void *data)
+{
+ struct rt5033_charger_data *info = data;
+ cancel_delayed_work(&info->activate_bad_adp_work);
+ pr_info("%s : Bad adaptor : enable MIVR temporarily\n",
+ __func__);
+ pr_info("%s : set MIVR = 4200mV\n", __func__);
+ rt5033_assign_bits(info->rt5033->i2c_client,
+ RT5033_CHG_CTRL4, RT5033_MIVR_MASK,
+ RT5033_MIVR_4200MV << RT5033_MIVR_SHIFT);
+ /* Disable bad adaptor detection */
+ rt5033_set_bits(info->rt5033->i2c_client,
+ RT5033_EOC_CTRL, (1 << 5));
+ queue_delayed_work(info->wq, &info->activate_bad_adp_work,
+ msecs_to_jiffies(BADADP_RESTART_TIMER));
+
+ return IRQ_HANDLED;
+}
+#endif /* EN_BAD_ADP_IRQ */
+
+#if EN_OVP_IRQ
+static irqreturn_t rt5033_chg_vin_ovp_irq_handler(int irq, void *data)
+{
+ struct rt5033_charger_data *info = data;
+ union power_supply_propval value;
+ int status;
+ /* Delay 100ms for debounce */
+ msleep(100);
+ status = rt5033_reg_read(info->rt5033->i2c_client,
+ RT5033_CHG_STAT_CTRL);
+
+ /* PWR ready = 0*/
+ if ((status & (0x04)) == 0) {
+ /* No need to disable charger,
+ * * H/W will do it automatically */
+ info->unhealth_cnt = HEALTH_DEBOUNCE_CNT;
+ info->ovp = true;
+ pr_info("%s: OVP triggered\n", __func__);
+ value.intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ psy_do_property("battery", set,
+ POWER_SUPPLY_PROP_HEALTH, value);
+ } else {
+ info->unhealth_cnt = 0;
+ info->ovp = false;
+ }
+
+ return IRQ_HANDLED;
+}
+#endif /* EN_OVP_IRQ */
+
+#if EN_IEOC_IRQ
+static irqreturn_t rt5033_chg_ieoc_irq_handler(int irq, void *data)
+{
+ struct rt5033_charger_data *info = data;
+ struct i2c_client *iic = info->rt5033->i2c_client;
+ int eoc_reg;
+ union power_supply_propval value;
+ cancel_delayed_work(&info->eoc_timeout_work);
+ mutex_lock(&info->io_lock);
+ info->eoc_cnt++;
+ mutex_unlock(&info->io_lock);
+ pr_info("%s : EOC CNT = %d / %d\n", __func__,
+ info->eoc_cnt, EOC_DEBOUNCE_CNT);
+ if (info->eoc_cnt >= EOC_DEBOUNCE_CNT) {
+ /* set full charged flag
+ * until TA/USB unplug event / stop charging by PSY
+ * / recharging event
+ */
+ pr_info("%s : Full charged\n", __func__);
+ info->full_charged = true;
+ info->eoc_cnt = 0;
+ value.intval = POWER_SUPPLY_STATUS_FULL;
+ psy_do_property("battery", set,
+ POWER_SUPPLY_PROP_STATUS, value);
+ } else {
+ pr_info("%s : Reset EOC detection\n", __func__);
+ msleep(10);
+ /* Reset EOC loop, and make it re-detect */
+ mutex_lock(&info->io_lock);
+ eoc_reg = rt5033_reg_read(iic, RT5033_CHG_CTRL4);
+ if (eoc_reg < 0)
+ pr_err("error : rt5033 i2c read failed...\n");
+ rt5033_set_bits(iic, RT5033_UUG, 0x80); // EN sinking
+ msleep(10); // 10ms
+ rt5033_clr_bits(iic, RT5033_UUG, 0x80); // DIS sinking
+ /* Disable EOC function */
+ rt5033_reg_write(iic, RT5033_CHG_CTRL4, (~RT5033_IEOC_MASK) & eoc_reg);
+ /* set EOC RESET */
+ rt5033_set_bits(iic, RT5033_EOC_CTRL, RT5033_EOC_RESET_MASK);
+ /* clear EOC RESET */
+ rt5033_clr_bits(iic, RT5033_EOC_CTRL, RT5033_EOC_RESET_MASK);
+ /* Restore EOC setting */
+ rt5033_reg_write(iic, RT5033_CHG_CTRL4, eoc_reg);
+ mutex_unlock(&info->io_lock);
+ msleep(EOC_SLEEP);
+ queue_delayed_work(info->wq, &info->eoc_timeout_work,
+ msecs_to_jiffies(EOC_TIMEOUT));
+ }
+ return IRQ_HANDLED;
+}
+#endif /* EN_IEOC_IRQ */
+
+#if EN_RECHG_REQ_IRQ
+static irqreturn_t rt5033_chg_rechg_request_irq_handler(int irq, void *data)
+{
+ struct rt5033_charger_data *info = data;
+ pr_info("%s: Recharging requesting\n", __func__);
+
+ info->full_charged = false;
+ info->eoc_cnt = 0;
+
+ return IRQ_HANDLED;
+}
+#endif /* EN_RECHG_REQ_IRQ */
+
+#if EN_TR_IRQ
+static irqreturn_t rt5033_chg_otp_tr_irq_handler(int irq, void *data)
+{
+ pr_info("%s : Over temperature : thermal regulation loop active\n",
+ __func__);
+ // if needs callback, do it here
+ return IRQ_HANDLED;
+}
+#endif
+
+const struct rt5033_chg_irq_handler rt5033_chg_irq_handlers[] = {
+#if EN_BAD_ADP_IRQ
+ {
+ .name = "BAD ADAPTOR",
+ .handler = rt5033_chg_bad_adp_irq_handler,
+ .irq_index = RT5033_ADPBAD_IRQ,
+ },
+#endif
+#if EN_OVP_IRQ
+ {
+ .name = "VIN_OVP",
+ .handler = rt5033_chg_vin_ovp_irq_handler,
+ .irq_index = RT5033_VINOVPI_IRQ,
+ },
+#endif /* EN_OVP_IRQ */
+#if EN_IEOC_IRQ
+ {
+ .name = "IEOC",
+ .handler = rt5033_chg_ieoc_irq_handler,
+ .irq_index = RT5033_IEOC_IRQ,
+ },
+#endif /* EN_IEOC_IRQ */
+#if EN_RECHG_REQ_IRQ
+ {
+ .name = "RECHG_RQUEST",
+ .handler = rt5033_chg_rechg_request_irq_handler,
+ .irq_index = RT5033_CHRCHGI_IRQ,
+ },
+#endif /* EN_RECHG_REQ_IRQ*/
+#if EN_TR_IRQ
+ {
+ .name = "OTP ThermalRegulation",
+ .handler = rt5033_chg_otp_tr_irq_handler,
+ .irq_index = RT5033_CHTREGI_IRQ,
+ },
+#endif /* EN_TR_IRQ */
+
+#if EN_BST_IRQ
+ {
+ .name = "OTG Low Batt",
+ .handler = rt5033_chg_otg_fail_irq_handler,
+ .irq_index = RT5033_BSTLOWVI_IRQ,
+ },
+ {
+ .name = "OTG Over Load",
+ .handler = rt5033_chg_otg_fail_irq_handler,
+ .irq_index = RT5033_BSTOLI_IRQ,
+ },
+ {
+ .name = "OTG OVP",
+ .handler = rt5033_chg_otg_fail_irq_handler,
+ .irq_index = RT5033_BSTVMIDOVP_IRQ,
+ },
+#endif /* EN_BST_IRQ */
+};
+
+static int register_irq(struct platform_device *pdev,
+ struct rt5033_charger_data *info)
+{
+ int irq;
+ int i, j;
+ int ret;
+ const struct rt5033_chg_irq_handler *irq_handler = rt5033_chg_irq_handlers;
+ const char *irq_name;
+ for (i = 0; i < ARRAY_SIZE(rt5033_chg_irq_handlers); i++) {
+ irq_name = rt5033_get_irq_name_by_index(irq_handler[i].irq_index);
+ irq = platform_get_irq_byname(pdev, irq_name);
+ ret = request_threaded_irq(irq, NULL, irq_handler[i].handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING |
+ IRQF_NO_SUSPEND, irq_name, info);
+ if (ret < 0) {
+ pr_err("%s : Failed to request IRQ (%s): #%d: %d\n",
+ __func__, irq_name, irq, ret);
+ goto err_irq;
+ }
+
+ pr_info("%s : Register IRQ%d(%s) successfully\n",
+ __func__, irq, irq_name);
+ }
+
+ return 0;
+err_irq:
+ for (j = 0; j < i; j++) {
+ irq_name = rt5033_get_irq_name_by_index(irq_handler[j].irq_index);
+ irq = platform_get_irq_byname(pdev, irq_name);
+ free_irq(irq, info);
+ }
+
+ return ret;
+}
+
+static void unregister_irq(struct platform_device *pdev,
+ struct rt5033_charger_data *info)
+{
+ int irq;
+ int i;
+ const char *irq_name;
+ const struct rt5033_chg_irq_handler *irq_handler = rt5033_chg_irq_handlers;
+
+ for (i = 0; i < ARRAY_SIZE(rt5033_chg_irq_handlers); i++) {
+ irq_name = rt5033_get_irq_name_by_index(irq_handler[i].irq_index);
+ irq = platform_get_irq_byname(pdev, irq_name);
+ free_irq(irq, info);
+ }
+}
+
+
+#ifdef CONFIG_OF
+static int sec_bat_read_u32_index_dt(const struct device_node *np,
+ const char *propname,
+ u32 index, u32 *out_value)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ u32 len = (index + 1) * sizeof(*out_value);
+
+ if (!prop)
+ return (-EINVAL);
+ if (!prop->value)
+ return (-ENODATA);
+ if (len > prop->length)
+ return (-EOVERFLOW);
+
+ *out_value = be32_to_cpup(((__be32 *)prop->value) + index);
+
+ return 0;
+}
+
+static int rt5033_charger_parse_dt(struct device *dev,
+ struct rt5033_charger_platform_data *pdata)
+{
+ struct device_node *np = dev->of_node;
+ const u32 *p;
+ int ret, i, len;
+ const char *charger_name = "sec-charger";
+
+ if (of_find_property(np, "is_750kHz_switching", NULL))
+ pdata->is_750kHz_switching = 1;
+ if (of_find_property(np, "is_fixed_switching", NULL))
+ pdata->is_fixed_switching = 1;
+ pr_info("%s : is_750kHz_switching = %d\n", __func__,
+ pdata->is_750kHz_switching);
+ pr_info("%s : is_fixed_switching = %d\n", __func__,
+ pdata->is_fixed_switching);
+
+ np = of_find_node_by_name(NULL, "charger");
+ if (!np) {
+ pr_info("%s : np NULL\n", __func__);
+ return -ENODATA;
+ }
+ ret = of_property_read_u32(np, "battery,chg_float_voltage",
+ &pdata->chg_float_voltage);
+ if (ret < 0) {
+ pr_info("%s : cannot get chg float voltage\n", __func__);
+ return -ENODATA;
+ }
+
+ of_property_read_string(np, "battery,charger_name", &charger_name);
+ len = strlen(charger_name);
+ pdata->charger_name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
+ strcpy(pdata->charger_name, charger_name);
+
+ p = of_get_property(np, "battery,input_current_limit", &len);
+
+ len = len / sizeof(u32);
+
+ pdata->charging_current_table =
+ kzalloc(sizeof(sec_charging_current_t) * len, GFP_KERNEL);
+
+ for (i = 0; i < len; i++) {
+ ret = sec_bat_read_u32_index_dt(np,
+ "battery,input_current_limit", i,
+ &pdata->charging_current_table[i].input_current_limit);
+ ret = sec_bat_read_u32_index_dt(np,
+ "battery,fast_charging_current", i,
+ &pdata->charging_current_table[i].fast_charging_current);
+ ret = sec_bat_read_u32_index_dt(np,
+ "battery,full_check_current_1st", i,
+ &pdata->charging_current_table[i].full_check_current_1st);
+ ret = sec_bat_read_u32_index_dt(np,
+ "battery,full_check_current_2nd", i,
+ &pdata->charging_current_table[i].full_check_current_2nd);
+ }
+ dev_info(dev, "rt5033 charger parse dt retval = %d\n", ret);
+ return ret;
+}
+
+static struct of_device_id rt5033_charger_match_table[] = {
+ { .compatible = "richtek,rt5033-charger",},
+ {},
+};
+#else
+static int rt5033_charger_parse_dt(struct device *dev,
+ struct rt5033_charger_platform_data *pdata)
+{
+ return -ENOSYS;
+}
+#define rt5033_charger_match_table NULL
+#endif /* CONFIG_OF */
+
+static void rt5033chg_eoc_timeout_reset(
+ struct work_struct *work)
+{
+ rt5033_charger_data_t *charger =
+ container_of(to_delayed_work(work),
+ rt5033_charger_data_t,
+ eoc_timeout_work);
+ mutex_lock(&charger->io_lock);
+ charger->eoc_cnt = 0;
+ mutex_unlock(&charger->io_lock);
+}
+
+
+static int rt5033_charger_probe(struct platform_device *pdev)
+{
+ rt5033_mfd_chip_t *chip = dev_get_drvdata(pdev->dev.parent);
+ struct rt5033_mfd_platform_data *mfd_pdata = dev_get_platdata(chip->dev);
+ struct rt5033_charger_data *charger;
+ int ret = 0;
+ pr_info("%s:[BATT] RT5033 Charger driver probe\n", __func__);
+ charger = kzalloc(sizeof(*charger), GFP_KERNEL);
+ if (!charger)
+ return -ENOMEM;
+
+#ifdef CONFIG_OF
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
+ if (pdev->dev.parent->of_node) {
+ pdev->dev.of_node = of_find_compatible_node(
+ of_node_get(pdev->dev.parent->of_node), NULL,
+ rt5033_charger_match_table[0].compatible);
+ }
+#endif
+#endif
+ mutex_init(&charger->io_lock);
+ charger->wq = create_workqueue("rt5033chg_workqueue");
+ INIT_DELAYED_WORK(&charger->eoc_timeout_work,
+ rt5033chg_eoc_timeout_reset);
+#if EN_BAD_ADP_IRQ
+ INIT_DELAYED_WORK(&charger->activate_bad_adp_work,
+ rt5033chg_activate_bad_adp);
+#endif /* EN_BAD_ADP_IRQ */
+ charger->rt5033 = chip;
+ if (pdev->dev.of_node) {
+ charger->pdata = devm_kzalloc(&pdev->dev, sizeof(*(charger->pdata)),
+ GFP_KERNEL);
+ if (!charger->pdata) {
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto err_parse_dt_nomem;
+ }
+ ret = rt5033_charger_parse_dt(&pdev->dev, charger->pdata);
+ if (ret < 0)
+ goto err_parse_dt;
+ } else
+ charger->pdata = mfd_pdata->charger_platform_data;
+
+ platform_set_drvdata(pdev, charger);
+ if (charger->pdata->charger_name == NULL)
+ charger->pdata->charger_name = "sec-charger";
+
+ charger->psy_chg.name = charger->pdata->charger_name;
+ charger->psy_chg.type = POWER_SUPPLY_TYPE_UNKNOWN;
+ charger->psy_chg.get_property = sec_chg_get_property;
+ charger->psy_chg.set_property = sec_chg_set_property;
+ charger->psy_chg.properties = sec_charger_props;
+ charger->psy_chg.num_properties = ARRAY_SIZE(sec_charger_props);
+
+ charger->siop_level = 100;
+ rt5033_chg_init(charger);
+
+ ret = power_supply_register(&pdev->dev, &charger->psy_chg);
+ if (ret) {
+ pr_err("%s: Failed to Register psy_chg\n", __func__);
+ goto err_power_supply_register;
+ }
+ ret = register_irq(pdev, charger);
+ if (ret < 0)
+ goto err_reg_irq;
+
+ rt5033_test_read(charger->rt5033->i2c_client);
+ pr_info("%s:[BATT] RT5033 charger driver loaded OK\n", __func__);
+
+ return 0;
+err_reg_irq:
+ power_supply_unregister(&charger->psy_chg);
+err_power_supply_register:
+err_parse_dt:
+err_parse_dt_nomem:
+ destroy_workqueue(charger->wq);
+ mutex_destroy(&charger->io_lock);
+ kfree(charger);
+ return ret;
+}
+
+static int rt5033_charger_remove(struct platform_device *pdev)
+{
+ struct rt5033_charger_data *charger =
+ platform_get_drvdata(pdev);
+ unregister_irq(pdev, charger);
+ power_supply_unregister(&charger->psy_chg);
+ destroy_workqueue(charger->wq);
+ mutex_destroy(&charger->io_lock);
+ kfree(charger);
+ return 0;
+}
+
+#if defined CONFIG_PM
+static int rt5033_charger_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int rt5033_charger_resume(struct device *dev)
+{
+ return 0;
+}
+#else
+#define rt5033_charger_suspend NULL
+#define rt5033_charger_resume NULL
+#endif
+
+static void rt5033_charger_shutdown(struct device *dev)
+{
+ pr_info("%s: RT5033 Charger driver shutdown\n", __func__);
+}
+
+static SIMPLE_DEV_PM_OPS(rt5033_charger_pm_ops, rt5033_charger_suspend,
+ rt5033_charger_resume);
+
+static struct platform_driver rt5033_charger_driver = {
+ .driver = {
+ .name = "rt5033-charger",
+ .owner = THIS_MODULE,
+ .of_match_table = rt5033_charger_match_table,
+ .pm = &rt5033_charger_pm_ops,
+ .shutdown = rt5033_charger_shutdown,
+ },
+ .probe = rt5033_charger_probe,
+ .remove = rt5033_charger_remove,
+};
+
+static int __init rt5033_charger_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&rt5033_charger_driver);
+
+ return ret;
+}
+subsys_initcall(rt5033_charger_init);
+
+static void __exit rt5033_charger_exit(void)
+{
+ platform_driver_unregister(&rt5033_charger_driver);
+}
+module_exit(rt5033_charger_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Chang <patrick_chang@richtek.com");
+MODULE_DESCRIPTION("Charger driver for RT5033");