kernel-brax3-ubuntu-touch/drivers/power/supply/rt9758-charger.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

733 lines
19 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 MediaTek Inc.
*/
#include <linux/bits.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/linear_range.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include "charger_class.h"
#include "mtk_charger.h"
static bool dbg_log_en;
module_param(dbg_log_en, bool, 0644);
#define mt_dbg(dev, fmt, ...) \
do { \
if (dbg_log_en) \
dev_info(dev, "%s " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#define RT9758_REG_DEVINFO 0x00
#define RT9758_REG_FLAG1 0x01
#define RT9758_REG_FLAG2 0x02
#define RT9758_REG_FLAG3 0x03
#define RT9758_REG_ICSTAT 0x04
#define RT9758_REG_STAT1 0x08
#define RT9758_REG_CTRL1 0x0A
#define RT9758_REG_CTRL2 0x0B
#define RT9758_REG_CTRL3 0x0C
#define RT9758_REG_CTRL4 0x0D
#define RT9758_REG_CTRL5 0x0E
#define RT9758_REG_CTRL6 0x0F
#define RT9758_REG_CTRL7 0x10
#define RT9758_REG_CTRL8 0x11
#define RT9758_REG_CTRL9 0x12
#define RT9758_REG_CTRL10 0x13
#define RT9758_DEVID_MASK GENMASK(3, 0)
#define RT9758_WRXIN_MASK BIT(2)
#define RT9758_DEVICE_ID 0x03
#define RT9758_RSTRG_VAL BIT(2)
#define RT9758_RESET_WAITUS 1000
#define RT9758_Q0CTRL_OFF 0
#define RT9758_Q0CTRL_ON 2
enum {
RT9758_SYNC_OFF = 0,
RT9758_SYNC_MASTER,
RT9758_SYNC_SLAVE = 3,
RT9758_MAX_SYNC
};
enum {
RT9758_PRESENT_MODE = 0,
RT9758_STANDBY_MODE,
RT9758_FORWARD_DIV2_MODE,
RT9758_FORWARD_BYPASS_MODE,
RT9758_REVERSE_DIV2_MODE,
RT9758_REVERSE_BYPASS_MODE,
RT9758_CHARGE_FAULT,
};
enum rt9758_fields {
F_IC_STAT = 0,
F_VLERR_STAT,
F_WRXIN_STAT,
F_SWITCH_STAT,
F_VOUT_OVP,
F_VBUS_OVP,
F_IBUS_OCP,
F_SYNC_MODE,
F_Q0_CTRL,
F_WDT,
F_WDT_EN,
F_CHG_EN,
F_OP_MODE,
F_ATEN,
F_BA_WDT,
F_TDIE_EN,
F_MAX_FIELDS
};
enum {
RT9758_RANGE_VOUTOVP = 0,
RT9758_RANGE_VBUSOVP,
RT9758_RANGE_IBUSOCP,
RT9758_MAX_RANGES
};
enum rt9758_chg_dtprop_type {
DTPROP_U32,
DTPROP_BOOL,
};
struct rt9758_priv {
struct device *dev;
struct regmap *regmap;
struct regmap_field *rm_field[F_MAX_FIELDS];
struct gpio_desc *enable_gpio;
struct power_supply *psy;
struct power_supply_desc desc;
struct charger_device *chg_dev;
const char *chg_name;
struct charger_properties chg_prop;
bool charge_enabled;
bool bypass_enabled;
};
static struct reg_field rt9758_reg_fields[F_MAX_FIELDS] = {
[F_IC_STAT] = REG_FIELD(RT9758_REG_ICSTAT, 0, 2),
[F_VLERR_STAT] = REG_FIELD(RT9758_REG_STAT1, 3, 3),
[F_WRXIN_STAT] = REG_FIELD(RT9758_REG_STAT1, 2, 2),
[F_SWITCH_STAT] = REG_FIELD(RT9758_REG_STAT1, 1, 1),
[F_VOUT_OVP] = REG_FIELD(RT9758_REG_CTRL1, 0, 2),
[F_VBUS_OVP] = REG_FIELD(RT9758_REG_CTRL2, 0, 5),
[F_IBUS_OCP] = REG_FIELD(RT9758_REG_CTRL3, 4, 7),
[F_SYNC_MODE] = REG_FIELD(RT9758_REG_CTRL4, 2, 3),
[F_Q0_CTRL] = REG_FIELD(RT9758_REG_CTRL4, 0, 1),
[F_WDT] = REG_FIELD(RT9758_REG_CTRL5, 4, 6),
[F_WDT_EN] = REG_FIELD(RT9758_REG_CTRL5, 3, 3),
[F_CHG_EN] = REG_FIELD(RT9758_REG_CTRL6, 2, 2),
[F_OP_MODE] = REG_FIELD(RT9758_REG_CTRL6, 0, 0),
[F_ATEN] = REG_FIELD(RT9758_REG_CTRL7, 3, 3),
[F_BA_WDT] = REG_FIELD(RT9758_REG_CTRL8, 0, 0),
[F_TDIE_EN] = REG_FIELD(RT9758_REG_CTRL9, 5, 5)
};
static const struct linear_range rt9758_ranges[RT9758_MAX_RANGES] = {
[RT9758_RANGE_VOUTOVP] = { 7000000, 0, 7, 1000000 },
[RT9758_RANGE_VBUSOVP] = { 7250000, 0, 59, 250000 },
[RT9758_RANGE_IBUSOCP] = { 2000000, 2, 10, 500000 }
};
static int rt9758_get_status(struct rt9758_priv *priv,
union power_supply_propval *val)
{
unsigned int switching;
int ret;
ret = regmap_field_read(priv->rm_field[F_SWITCH_STAT], &switching);
if (ret)
return ret;
if (switching)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
return 0;
}
static int rt9758_get_charge_type(struct rt9758_priv *priv,
union power_supply_propval *val)
{
if (!priv->charge_enabled)
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
else if (!priv->bypass_enabled)
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
else
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
return 0;
}
static int rt9758_get_online(struct rt9758_priv *priv,
union power_supply_propval *val)
{
unsigned int wrxin_stat;
int ret;
ret = regmap_field_read(priv->rm_field[F_WRXIN_STAT], &wrxin_stat);
if (ret)
return ret;
val->intval = wrxin_stat;
return 0;
}
static int rt9758_get_const_charge_volt(struct rt9758_priv *priv,
union power_supply_propval *val)
{
const struct linear_range *range = rt9758_ranges + RT9758_RANGE_VOUTOVP;
unsigned int vout_ovp_sel, vout_ovp_val;
int ret;
ret = regmap_field_read(priv->rm_field[F_VOUT_OVP], &vout_ovp_sel);
if (ret)
return ret;
ret = linear_range_get_value(range, vout_ovp_sel, &vout_ovp_val);
if (ret)
return ret;
val->intval = vout_ovp_val;
return 0;
}
static int rt9758_get_input_curr_lim(struct rt9758_priv *priv,
union power_supply_propval *val)
{
const struct linear_range *range = rt9758_ranges + RT9758_RANGE_IBUSOCP;
unsigned int ibus_ocp_sel, ibus_ocp_val;
int ret;
ret = regmap_field_read(priv->rm_field[F_IBUS_OCP], &ibus_ocp_sel);
if (ret)
return ret;
ret = linear_range_get_value(range, ibus_ocp_sel, &ibus_ocp_val);
if (ret)
return ret;
val->intval = ibus_ocp_val;
return 0;
}
static int rt9758_get_input_volt_lim(struct rt9758_priv *priv,
union power_supply_propval *val)
{
const struct linear_range *range = rt9758_ranges + RT9758_RANGE_VBUSOVP;
unsigned int vbus_ovp_sel, vbus_ovp_val;
int ret;
ret = regmap_field_read(priv->rm_field[F_VBUS_OVP], &vbus_ovp_sel);
if (ret)
return ret;
ret = linear_range_get_value(range, vbus_ovp_sel, &vbus_ovp_val);
if (ret)
return ret;
val->intval = vbus_ovp_val;
return 0;
}
static int rt9758_get_manufacturer(struct rt9758_priv *priv,
union power_supply_propval *val)
{
val->strval = "Richtek Technology Corp.";
return 0;
}
static int rt9758_set_charge_enable(struct rt9758_priv *priv,
const union power_supply_propval *val)
{
unsigned int q0ctrl_val, chgen;
int ret;
chgen = !!val->intval;
if (chgen)
q0ctrl_val = RT9758_Q0CTRL_ON;
else
q0ctrl_val = RT9758_Q0CTRL_OFF;
ret = regmap_field_write(priv->rm_field[F_Q0_CTRL], q0ctrl_val);
if (ret)
return ret;
ret = regmap_field_write(priv->rm_field[F_CHG_EN], chgen);
if (ret)
return ret;
ret = regmap_field_write(priv->rm_field[F_WDT_EN], chgen);
if (ret)
return ret;
if (priv->enable_gpio)
gpiod_set_value(priv->enable_gpio, !chgen);
mdelay(1);
priv->charge_enabled = chgen;
return 0;
}
static int rt9758_set_bypass_enable(struct rt9758_priv *priv,
const union power_supply_propval *val)
{
unsigned int bypass_enabled;
int ret;
bypass_enabled = !!val->intval;
ret = regmap_field_write(priv->rm_field[F_OP_MODE], bypass_enabled);
if (ret)
return ret;
priv->bypass_enabled = bypass_enabled;
return regmap_field_write(priv->rm_field[F_WDT], 0);
}
static int rt9758_set_const_charge_volt(struct rt9758_priv *priv,
const union power_supply_propval *val)
{
const struct linear_range *range = rt9758_ranges + RT9758_RANGE_VOUTOVP;
unsigned int sel = 0;
linear_range_get_selector_within(range, val->intval, &sel);
return regmap_field_write(priv->rm_field[F_VOUT_OVP], sel);
}
static int rt9758_set_input_curr_lim(struct rt9758_priv *priv,
const union power_supply_propval *val)
{
const struct linear_range *range = rt9758_ranges + RT9758_RANGE_IBUSOCP;
unsigned int sel = 0;
linear_range_get_selector_within(range, val->intval, &sel);
return regmap_field_write(priv->rm_field[F_IBUS_OCP], sel);
}
static int rt9758_set_input_volt_lim(struct rt9758_priv *priv,
const union power_supply_propval *val)
{
const struct linear_range *range = rt9758_ranges + RT9758_RANGE_VBUSOVP;
unsigned int sel = 0;
linear_range_get_selector_within(range, val->intval, &sel);
return regmap_field_write(priv->rm_field[F_VBUS_OVP], sel);
}
static int rt9758_charger_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct rt9758_priv *priv = power_supply_get_drvdata(psy);
if (!priv)
return -ENODATA;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
return rt9758_get_status(priv, val);
case POWER_SUPPLY_PROP_CHARGE_TYPE:
return rt9758_get_charge_type(priv, val);
case POWER_SUPPLY_PROP_ONLINE:
return rt9758_get_online(priv, val);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
return rt9758_get_const_charge_volt(priv, val);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return rt9758_get_input_curr_lim(priv, val);
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
return rt9758_get_input_volt_lim(priv, val);
case POWER_SUPPLY_PROP_MANUFACTURER:
return rt9758_get_manufacturer(priv, val);
default:
return -ENODATA;
}
}
static int rt9758_charger_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct rt9758_priv *priv = power_supply_get_drvdata(psy);
if (!priv)
return -ENODATA;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
return rt9758_set_charge_enable(priv, val);
case POWER_SUPPLY_PROP_CHARGE_TYPE:
return rt9758_set_bypass_enable(priv, val);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
return rt9758_set_const_charge_volt(priv, val);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return rt9758_set_input_curr_lim(priv, val);
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
return rt9758_set_input_volt_lim(priv, val);
default:
return -EINVAL;
}
}
static const enum power_supply_property rt9758_charger_properties[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
POWER_SUPPLY_PROP_MANUFACTURER
};
static int rt9758_init_chg_properties(struct rt9758_priv *priv)
{
unsigned int sync_mode = RT9758_SYNC_OFF;
int ret;
ret = regmap_write(priv->regmap, RT9758_REG_CTRL9, RT9758_RSTRG_VAL);
if (ret)
return ret;
usleep_range(RT9758_RESET_WAITUS, RT9758_RESET_WAITUS + 100);
/* mediatek chgdev name */
ret = device_property_read_string(priv->dev, "chg_name",
&priv->chg_name);
if (ret) {
dev_notice(priv->dev, "failed to get chg_name\n");
priv->chg_name = "hvdiv2_chg1";
}
device_property_read_u32(priv->dev, "richtek,dv2-sync-mode",
&sync_mode);
if (sync_mode >= RT9758_MAX_SYNC) {
dev_err(priv->dev, "Not valid mode [%d]\n", sync_mode);
return -EINVAL;
}
ret = regmap_field_write(priv->rm_field[F_BA_WDT], 0);
if (ret)
return ret;
ret = regmap_field_write(priv->rm_field[F_SYNC_MODE], sync_mode);
if (ret)
return ret;
ret = regmap_field_write(priv->rm_field[F_Q0_CTRL], RT9758_Q0CTRL_OFF);
if (ret)
return ret;
return regmap_field_write(priv->rm_field[F_CHG_EN], 0);
}
static int rt9758_check_device_info(struct rt9758_priv *priv)
{
unsigned int dev_info;
int ret;
ret = regmap_read(priv->regmap, RT9758_REG_DEVINFO, &dev_info);
if (ret)
return ret;
if ((dev_info & RT9758_DEVID_MASK) != RT9758_DEVICE_ID) {
dev_err(priv->dev, "Failed to match devid 0x%02x\n", dev_info);
return -ENODEV;
}
dev_info(priv->dev, "devid = 0x%02X\n", dev_info);
return 0;
}
static int rt9758_psy_set_prop(struct rt9758_priv *priv,
enum power_supply_property psp, uint32_t data)
{
union power_supply_propval val;
val.intval = data;
return power_supply_set_property(priv->psy, psp, &val);
}
static int rt9758_enable_chg(struct charger_device *chg_dev, bool en)
{
uint32_t set_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
dev_info(priv->dev, "%s %d\n", __func__, en);
set_val = en;
return rt9758_psy_set_prop(priv, POWER_SUPPLY_PROP_STATUS, set_val);
}
static int rt9758_is_chg_enabled(struct charger_device *chg_dev, bool *en)
{
int ret;
unsigned int get_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
ret = regmap_field_read(priv->rm_field[F_CHG_EN], &get_val);
if (ret)
return ret;
*en = get_val;
dev_info(priv->dev, "%s %d\n", __func__, *en);
return 0;
}
static int rt9758_init_chip(struct charger_device *chg_dev)
{
return 0;
}
static int rt9758_set_vbusovp(struct charger_device *chg_dev, uint32_t uV)
{
uint32_t set_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
dev_info(priv->dev, "%s %d\n", __func__, uV);
set_val = uV;
return rt9758_psy_set_prop(priv, POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
set_val);
}
static int rt9758_set_ibusocp(struct charger_device *chg_dev, uint32_t uA)
{
uint32_t set_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
dev_info(priv->dev, "%s %d\n", __func__, uA);
set_val = uA;
return rt9758_psy_set_prop(priv, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
set_val);
}
static int rt9758_set_voutovp(struct charger_device *chg_dev, uint32_t uV)
{
uint32_t set_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
dev_info(priv->dev, "%s %d\n", __func__, uV);
set_val = uV;
return rt9758_psy_set_prop(priv,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
set_val);
}
static int rt9758_is_vbuslowerr(struct charger_device *chg_dev, bool *err)
{
int ret;
unsigned int get_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
ret = regmap_field_read(priv->rm_field[F_VLERR_STAT], &get_val);
if (ret)
return ret;
*err = get_val;
dev_info(priv->dev, "%s %d\n", __func__, *err);
return 0;
}
static int rt9758_enable_auto_trans(struct charger_device *chg_dev, bool en)
{
uint32_t set_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
dev_info(priv->dev, "%s %d\n", __func__, en);
set_val = en;
return regmap_field_write(priv->rm_field[F_ATEN], set_val);
}
static int rt9758_set_auto_trans(struct charger_device *chg_dev, uint32_t uV,
bool en)
{
return 0;
}
static int rt9758_operation_mode_select(struct charger_device *chg_dev,
bool div2)
{
unsigned int set_val;
struct rt9758_priv *priv = charger_get_data(chg_dev);
dev_info(priv->dev, "div2 = %d\n", div2);
set_val = div2;
return rt9758_psy_set_prop(priv, POWER_SUPPLY_PROP_CHARGE_TYPE,
set_val);
}
#define DUMP_REG_BUF_SIZE 1024
static int rt9758_dump_registers(struct charger_device *chg_dev)
{
struct rt9758_priv *priv = charger_get_data(chg_dev);
int ret, i;
u32 val;
char buf[DUMP_REG_BUF_SIZE] = "\0";
static const struct {
const u8 reg;
const char *name;
} regs[] = {
{ .reg = RT9758_REG_FLAG1, .name = "FLAG1"},
{ .reg = RT9758_REG_FLAG2, .name = "FLAG2"},
{ .reg = RT9758_REG_FLAG3, .name = "FLAG3"},
{ .reg = RT9758_REG_ICSTAT, .name = "IC_STAT"},
{ .reg = RT9758_REG_CTRL1, .name = "CTRL1"},
{ .reg = RT9758_REG_CTRL2, .name = "CTRL2"},
{ .reg = RT9758_REG_CTRL3, .name = "CTRL3"},
{ .reg = RT9758_REG_CTRL4, .name = "CTRL4"},
{ .reg = RT9758_REG_CTRL5, .name = "CTRL5"},
{ .reg = RT9758_REG_CTRL6, .name = "CTRL6"},
};
for (i = 0; i < ARRAY_SIZE(regs); i++) {
ret = regmap_read(priv->regmap, regs[i].reg, &val);
if (ret) {
dev_err(priv->dev, "failed to get %s\n", regs[i].name);
return ret;
}
if (i == ARRAY_SIZE(regs) - 1)
scnprintf(buf + strlen(buf), DUMP_REG_BUF_SIZE,
"%s = 0x%02X\n", regs[i].name, val);
else
scnprintf(buf + strlen(buf), DUMP_REG_BUF_SIZE,
"%s = 0x%02X, ", regs[i].name, val);
}
dev_info(priv->dev, "%s %s\n", __func__, buf);
dev_info(priv->dev, "%s enable_gpio = %d\n", __func__,
gpiod_get_value(priv->enable_gpio));
return 0;
}
static const struct charger_ops rt9758_chg_ops = {
.enable = rt9758_enable_chg,
.is_enabled = rt9758_is_chg_enabled,
.init_chip = rt9758_init_chip,
.set_vbusovp = rt9758_set_vbusovp,
.set_ibusocp = rt9758_set_ibusocp,
.set_vbatovp = rt9758_set_voutovp,
.is_vbuslowerr = rt9758_is_vbuslowerr,
.enable_auto_trans = rt9758_enable_auto_trans,
.set_auto_trans = rt9758_set_auto_trans,
.set_operation_mode = rt9758_operation_mode_select,
.dump_registers = rt9758_dump_registers,
};
static const struct regmap_config rt9758_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RT9758_REG_CTRL10,
};
static int rt9758_charger_probe(struct i2c_client *i2c)
{
struct rt9758_priv *priv;
struct power_supply_config cfg = {};
int ret;
priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = &i2c->dev;
i2c_set_clientdata(i2c, priv);
priv->regmap = devm_regmap_init_i2c(i2c, &rt9758_regmap_config);
if (IS_ERR(priv->regmap)) {
ret = PTR_ERR(priv->regmap);
dev_err(&i2c->dev, "Failed to init regmap [%d]\n", ret);
return ret;
}
ret = devm_regmap_field_bulk_alloc(&i2c->dev, priv->regmap,
priv->rm_field, rt9758_reg_fields,
ARRAY_SIZE(rt9758_reg_fields));
if (ret) {
dev_err(&i2c->dev, "Failed to alloc regmap fields\n");
return ret;
}
ret = rt9758_check_device_info(priv);
if (ret) {
dev_err(&i2c->dev, "Failed to check device info\n");
return ret;
}
/* If specified, initial control 'enable' high to enter lowest IQ */
priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(priv->enable_gpio)) {
dev_err(&i2c->dev, "Failed to init enable gpio\n");
return PTR_ERR(priv->enable_gpio);
}
ret = rt9758_init_chg_properties(priv);
if (ret) {
dev_err(&i2c->dev, "Failed to init charger properties\n");
return ret;
}
priv->desc.name = dev_name(&i2c->dev);
priv->desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
priv->desc.properties = rt9758_charger_properties;
priv->desc.num_properties = ARRAY_SIZE(rt9758_charger_properties);
priv->desc.get_property = rt9758_charger_get_property;
priv->desc.set_property = rt9758_charger_set_property;
cfg.of_node = i2c->dev.of_node;
cfg.drv_data = priv;
priv->psy = devm_power_supply_register(&i2c->dev, &priv->desc, &cfg);
if (IS_ERR(priv->psy)) {
dev_err(&i2c->dev, "Failed to register psy\n");
return PTR_ERR(priv->psy);
}
priv->chg_prop.alias_name = priv->chg_name;
priv->chg_dev = charger_device_register(priv->chg_name, priv->dev,
priv, &rt9758_chg_ops,
&priv->chg_prop);
if (IS_ERR(priv->chg_dev)) {
dev_err(&i2c->dev, "Failed to register chgdev\n");
return PTR_ERR(priv->chg_dev);
}
dev_info(&i2c->dev, "%s ok\n", __func__);
return 0;
}
static int rt9758_charger_remove(struct i2c_client *i2c)
{
struct rt9758_priv *priv = i2c_get_clientdata(i2c);
charger_device_unregister(priv->chg_dev);
return 0;
}
static const struct of_device_id rt9758_charger_of_match_table[] = {
{ .compatible = "richtek,rt9758", },
{ }
};
MODULE_DEVICE_TABLE(of, rt9758_charger_of_match_table);
static struct i2c_driver rt9758_charger_driver = {
.driver = {
.name = "rt9758-charger",
.of_match_table = rt9758_charger_of_match_table,
},
.probe_new = rt9758_charger_probe,
.remove = rt9758_charger_remove,
};
module_i2c_driver(rt9758_charger_driver);
MODULE_DESCRIPTION("Richtek RT9758 charger driver");
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
MODULE_LICENSE("GPL");