1*7e541f6dSKaustabh Chakraborty // SPDX-License-Identifier: GPL-2.0 2*7e541f6dSKaustabh Chakraborty /* 3*7e541f6dSKaustabh Chakraborty * Battery Charger Driver for Samsung S2M series PMICs. 4*7e541f6dSKaustabh Chakraborty * 5*7e541f6dSKaustabh Chakraborty * Copyright (c) 2015 Samsung Electronics Co., Ltd 6*7e541f6dSKaustabh Chakraborty * Copyright (c) 2026 Kaustabh Chakraborty <kauschluss@disroot.org> 7*7e541f6dSKaustabh Chakraborty * Copyright (c) 2026 Łukasz Lebiedziński <kernel@lvkasz.us> 8*7e541f6dSKaustabh Chakraborty */ 9*7e541f6dSKaustabh Chakraborty 10*7e541f6dSKaustabh Chakraborty #include <linux/devm-helpers.h> 11*7e541f6dSKaustabh Chakraborty #include <linux/extcon.h> 12*7e541f6dSKaustabh Chakraborty #include <linux/mfd/samsung/core.h> 13*7e541f6dSKaustabh Chakraborty #include <linux/mfd/samsung/s2mu005.h> 14*7e541f6dSKaustabh Chakraborty #include <linux/module.h> 15*7e541f6dSKaustabh Chakraborty #include <linux/of.h> 16*7e541f6dSKaustabh Chakraborty #include <linux/of_graph.h> 17*7e541f6dSKaustabh Chakraborty #include <linux/platform_device.h> 18*7e541f6dSKaustabh Chakraborty #include <linux/power_supply.h> 19*7e541f6dSKaustabh Chakraborty #include <linux/regmap.h> 20*7e541f6dSKaustabh Chakraborty 21*7e541f6dSKaustabh Chakraborty struct s2m_chgr { 22*7e541f6dSKaustabh Chakraborty struct device *dev; 23*7e541f6dSKaustabh Chakraborty struct regmap *regmap; 24*7e541f6dSKaustabh Chakraborty struct power_supply *psy; 25*7e541f6dSKaustabh Chakraborty struct extcon_dev *extcon; 26*7e541f6dSKaustabh Chakraborty struct work_struct extcon_work; 27*7e541f6dSKaustabh Chakraborty struct notifier_block extcon_nb; 28*7e541f6dSKaustabh Chakraborty }; 29*7e541f6dSKaustabh Chakraborty 30*7e541f6dSKaustabh Chakraborty static int s2mu005_chgr_get_online(struct s2m_chgr *priv, int *value) 31*7e541f6dSKaustabh Chakraborty { 32*7e541f6dSKaustabh Chakraborty u32 val; 33*7e541f6dSKaustabh Chakraborty int ret; 34*7e541f6dSKaustabh Chakraborty 35*7e541f6dSKaustabh Chakraborty ret = regmap_read(priv->regmap, S2MU005_REG_CHGR_STATUS0, &val); 36*7e541f6dSKaustabh Chakraborty if (ret) { 37*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to read register (%d)\n", ret); 38*7e541f6dSKaustabh Chakraborty return ret; 39*7e541f6dSKaustabh Chakraborty } 40*7e541f6dSKaustabh Chakraborty 41*7e541f6dSKaustabh Chakraborty *value = !!(val & S2MU005_CHGR_CHG); 42*7e541f6dSKaustabh Chakraborty 43*7e541f6dSKaustabh Chakraborty return 0; 44*7e541f6dSKaustabh Chakraborty } 45*7e541f6dSKaustabh Chakraborty 46*7e541f6dSKaustabh Chakraborty static void s2mu005_chgr_get_usb_type(struct s2m_chgr *priv, int *value) 47*7e541f6dSKaustabh Chakraborty { 48*7e541f6dSKaustabh Chakraborty if (extcon_get_state(priv->extcon, EXTCON_CHG_USB_CDP) > 0) 49*7e541f6dSKaustabh Chakraborty *value = POWER_SUPPLY_USB_TYPE_CDP; 50*7e541f6dSKaustabh Chakraborty else if (extcon_get_state(priv->extcon, EXTCON_CHG_USB_SDP) > 0) 51*7e541f6dSKaustabh Chakraborty *value = POWER_SUPPLY_USB_TYPE_SDP; 52*7e541f6dSKaustabh Chakraborty else if (extcon_get_state(priv->extcon, EXTCON_CHG_USB_DCP) > 0) 53*7e541f6dSKaustabh Chakraborty *value = POWER_SUPPLY_USB_TYPE_DCP; 54*7e541f6dSKaustabh Chakraborty else 55*7e541f6dSKaustabh Chakraborty *value = POWER_SUPPLY_USB_TYPE_UNKNOWN; 56*7e541f6dSKaustabh Chakraborty } 57*7e541f6dSKaustabh Chakraborty 58*7e541f6dSKaustabh Chakraborty static int s2mu005_chgr_get_property(struct power_supply *psy, 59*7e541f6dSKaustabh Chakraborty enum power_supply_property psp, 60*7e541f6dSKaustabh Chakraborty union power_supply_propval *val) 61*7e541f6dSKaustabh Chakraborty { 62*7e541f6dSKaustabh Chakraborty struct s2m_chgr *priv = power_supply_get_drvdata(psy); 63*7e541f6dSKaustabh Chakraborty int ret; 64*7e541f6dSKaustabh Chakraborty 65*7e541f6dSKaustabh Chakraborty switch (psp) { 66*7e541f6dSKaustabh Chakraborty case POWER_SUPPLY_PROP_ONLINE: 67*7e541f6dSKaustabh Chakraborty ret = s2mu005_chgr_get_online(priv, &val->intval); 68*7e541f6dSKaustabh Chakraborty if (ret) 69*7e541f6dSKaustabh Chakraborty return ret; 70*7e541f6dSKaustabh Chakraborty break; 71*7e541f6dSKaustabh Chakraborty case POWER_SUPPLY_PROP_USB_TYPE: 72*7e541f6dSKaustabh Chakraborty s2mu005_chgr_get_usb_type(priv, &val->intval); 73*7e541f6dSKaustabh Chakraborty break; 74*7e541f6dSKaustabh Chakraborty default: 75*7e541f6dSKaustabh Chakraborty return -EINVAL; 76*7e541f6dSKaustabh Chakraborty } 77*7e541f6dSKaustabh Chakraborty 78*7e541f6dSKaustabh Chakraborty return 0; 79*7e541f6dSKaustabh Chakraborty } 80*7e541f6dSKaustabh Chakraborty 81*7e541f6dSKaustabh Chakraborty static int s2mu005_chgr_mode_set_host(struct s2m_chgr *priv) 82*7e541f6dSKaustabh Chakraborty { 83*7e541f6dSKaustabh Chakraborty int ret; 84*7e541f6dSKaustabh Chakraborty 85*7e541f6dSKaustabh Chakraborty /* set mode to OTG */ 86*7e541f6dSKaustabh Chakraborty ret = regmap_update_bits(priv->regmap, S2MU005_REG_CHGR_CTRL0, 87*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OP_MODE, 88*7e541f6dSKaustabh Chakraborty FIELD_PREP(S2MU005_CHGR_OP_MODE, 89*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OP_MODE_OTG)); 90*7e541f6dSKaustabh Chakraborty if (ret) { 91*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to set OTG mode (%d)\n", ret); 92*7e541f6dSKaustabh Chakraborty return ret; 93*7e541f6dSKaustabh Chakraborty } 94*7e541f6dSKaustabh Chakraborty 95*7e541f6dSKaustabh Chakraborty /* set boost frequency to 2MHz */ 96*7e541f6dSKaustabh Chakraborty ret = regmap_update_bits(priv->regmap, S2MU005_REG_CHGR_CTRL11, 97*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OSC_BOOST, 98*7e541f6dSKaustabh Chakraborty FIELD_PREP(S2MU005_CHGR_OSC_BOOST, 99*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OSC_BOOST_2MHZ)); 100*7e541f6dSKaustabh Chakraborty if (ret) { 101*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to set boost frequency (%d)\n", ret); 102*7e541f6dSKaustabh Chakraborty return ret; 103*7e541f6dSKaustabh Chakraborty } 104*7e541f6dSKaustabh Chakraborty 105*7e541f6dSKaustabh Chakraborty /* set OTG current limit to 1.5 A */ 106*7e541f6dSKaustabh Chakraborty ret = regmap_update_bits(priv->regmap, S2MU005_REG_CHGR_CTRL4, 107*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OTG_OCP, 108*7e541f6dSKaustabh Chakraborty FIELD_PREP(S2MU005_CHGR_OTG_OCP, 109*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OTG_OCP_1P5A)); 110*7e541f6dSKaustabh Chakraborty if (ret) { 111*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to set OTG current limit (%d)\n", ret); 112*7e541f6dSKaustabh Chakraborty return ret; 113*7e541f6dSKaustabh Chakraborty } 114*7e541f6dSKaustabh Chakraborty 115*7e541f6dSKaustabh Chakraborty /* VBUS switches are OFF when OTG over-current happens */ 116*7e541f6dSKaustabh Chakraborty ret = regmap_set_bits(priv->regmap, S2MU005_REG_CHGR_CTRL4, 117*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OTG_OCP_OFF); 118*7e541f6dSKaustabh Chakraborty if (ret) { 119*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to set OTG OCP switch (%d)\n", ret); 120*7e541f6dSKaustabh Chakraborty return ret; 121*7e541f6dSKaustabh Chakraborty } 122*7e541f6dSKaustabh Chakraborty 123*7e541f6dSKaustabh Chakraborty /* set OTG voltage to 5.1 V */ 124*7e541f6dSKaustabh Chakraborty ret = regmap_update_bits(priv->regmap, S2MU005_REG_CHGR_CTRL5, 125*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_VMID_BOOST, 126*7e541f6dSKaustabh Chakraborty FIELD_PREP(S2MU005_CHGR_VMID_BOOST, 127*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_VMID_BOOST_5P1V)); 128*7e541f6dSKaustabh Chakraborty if (ret) { 129*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to set OTG voltage (%d)\n", ret); 130*7e541f6dSKaustabh Chakraborty return ret; 131*7e541f6dSKaustabh Chakraborty } 132*7e541f6dSKaustabh Chakraborty 133*7e541f6dSKaustabh Chakraborty /* turn on OTG */ 134*7e541f6dSKaustabh Chakraborty ret = regmap_update_bits(priv->regmap, S2MU005_REG_CHGR_CTRL15, 135*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OTG_EN, 136*7e541f6dSKaustabh Chakraborty FIELD_PREP(S2MU005_CHGR_OTG_EN, 137*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OTG_EN_ON)); 138*7e541f6dSKaustabh Chakraborty if (ret) { 139*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to turn on OTG (%d)\n", ret); 140*7e541f6dSKaustabh Chakraborty return ret; 141*7e541f6dSKaustabh Chakraborty } 142*7e541f6dSKaustabh Chakraborty 143*7e541f6dSKaustabh Chakraborty return 0; 144*7e541f6dSKaustabh Chakraborty } 145*7e541f6dSKaustabh Chakraborty 146*7e541f6dSKaustabh Chakraborty static int s2mu005_chgr_mode_set_charger(struct s2m_chgr *priv) 147*7e541f6dSKaustabh Chakraborty { 148*7e541f6dSKaustabh Chakraborty int ret; 149*7e541f6dSKaustabh Chakraborty 150*7e541f6dSKaustabh Chakraborty /* first reset to mode 0 */ 151*7e541f6dSKaustabh Chakraborty ret = regmap_clear_bits(priv->regmap, S2MU005_REG_CHGR_CTRL0, 152*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OP_MODE); 153*7e541f6dSKaustabh Chakraborty if (ret) { 154*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to reset opmode (%d)\n", ret); 155*7e541f6dSKaustabh Chakraborty return ret; 156*7e541f6dSKaustabh Chakraborty } 157*7e541f6dSKaustabh Chakraborty 158*7e541f6dSKaustabh Chakraborty /* wait for the charger to settle before switching to charging mode */ 159*7e541f6dSKaustabh Chakraborty msleep(50); 160*7e541f6dSKaustabh Chakraborty /* then set to charging mode */ 161*7e541f6dSKaustabh Chakraborty ret = regmap_update_bits(priv->regmap, S2MU005_REG_CHGR_CTRL0, 162*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OP_MODE, 163*7e541f6dSKaustabh Chakraborty FIELD_PREP(S2MU005_CHGR_OP_MODE, 164*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OP_MODE_CHG)); 165*7e541f6dSKaustabh Chakraborty if (ret) { 166*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to set opmode to charging (%d)\n", ret); 167*7e541f6dSKaustabh Chakraborty return ret; 168*7e541f6dSKaustabh Chakraborty } 169*7e541f6dSKaustabh Chakraborty 170*7e541f6dSKaustabh Chakraborty return 0; 171*7e541f6dSKaustabh Chakraborty } 172*7e541f6dSKaustabh Chakraborty 173*7e541f6dSKaustabh Chakraborty static int s2mu005_chgr_mode_unset(struct s2m_chgr *priv) 174*7e541f6dSKaustabh Chakraborty { 175*7e541f6dSKaustabh Chakraborty int ret; 176*7e541f6dSKaustabh Chakraborty 177*7e541f6dSKaustabh Chakraborty /* turn off OTG */ 178*7e541f6dSKaustabh Chakraborty ret = regmap_clear_bits(priv->regmap, S2MU005_REG_CHGR_CTRL15, 179*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OTG_EN); 180*7e541f6dSKaustabh Chakraborty if (ret) { 181*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to turn off OTG (%d)\n", ret); 182*7e541f6dSKaustabh Chakraborty return ret; 183*7e541f6dSKaustabh Chakraborty } 184*7e541f6dSKaustabh Chakraborty 185*7e541f6dSKaustabh Chakraborty /* reset operation mode */ 186*7e541f6dSKaustabh Chakraborty ret = regmap_clear_bits(priv->regmap, S2MU005_REG_CHGR_CTRL0, 187*7e541f6dSKaustabh Chakraborty S2MU005_CHGR_OP_MODE); 188*7e541f6dSKaustabh Chakraborty if (ret) { 189*7e541f6dSKaustabh Chakraborty dev_err(priv->dev, "failed to reset opmode (%d)\n", ret); 190*7e541f6dSKaustabh Chakraborty return ret; 191*7e541f6dSKaustabh Chakraborty } 192*7e541f6dSKaustabh Chakraborty 193*7e541f6dSKaustabh Chakraborty return 0; 194*7e541f6dSKaustabh Chakraborty } 195*7e541f6dSKaustabh Chakraborty 196*7e541f6dSKaustabh Chakraborty static void s2mu005_chgr_extcon_work(struct work_struct *work) 197*7e541f6dSKaustabh Chakraborty { 198*7e541f6dSKaustabh Chakraborty struct s2m_chgr *priv = container_of(work, struct s2m_chgr, extcon_work); 199*7e541f6dSKaustabh Chakraborty 200*7e541f6dSKaustabh Chakraborty if (extcon_get_state(priv->extcon, EXTCON_USB_HOST) > 0) 201*7e541f6dSKaustabh Chakraborty s2mu005_chgr_mode_set_host(priv); 202*7e541f6dSKaustabh Chakraborty else if (extcon_get_state(priv->extcon, EXTCON_USB) > 0) 203*7e541f6dSKaustabh Chakraborty s2mu005_chgr_mode_set_charger(priv); 204*7e541f6dSKaustabh Chakraborty else 205*7e541f6dSKaustabh Chakraborty s2mu005_chgr_mode_unset(priv); 206*7e541f6dSKaustabh Chakraborty 207*7e541f6dSKaustabh Chakraborty power_supply_changed(priv->psy); 208*7e541f6dSKaustabh Chakraborty } 209*7e541f6dSKaustabh Chakraborty 210*7e541f6dSKaustabh Chakraborty static const enum power_supply_property s2mu005_chgr_properties[] = { 211*7e541f6dSKaustabh Chakraborty POWER_SUPPLY_PROP_ONLINE, 212*7e541f6dSKaustabh Chakraborty POWER_SUPPLY_PROP_USB_TYPE, 213*7e541f6dSKaustabh Chakraborty }; 214*7e541f6dSKaustabh Chakraborty 215*7e541f6dSKaustabh Chakraborty static const struct power_supply_desc s2mu005_chgr_psy_desc = { 216*7e541f6dSKaustabh Chakraborty .name = "s2mu005-charger", 217*7e541f6dSKaustabh Chakraborty .type = POWER_SUPPLY_TYPE_USB, 218*7e541f6dSKaustabh Chakraborty .properties = s2mu005_chgr_properties, 219*7e541f6dSKaustabh Chakraborty .num_properties = ARRAY_SIZE(s2mu005_chgr_properties), 220*7e541f6dSKaustabh Chakraborty .get_property = s2mu005_chgr_get_property, 221*7e541f6dSKaustabh Chakraborty .usb_types = BIT(POWER_SUPPLY_USB_TYPE_CDP) | 222*7e541f6dSKaustabh Chakraborty BIT(POWER_SUPPLY_USB_TYPE_SDP) | 223*7e541f6dSKaustabh Chakraborty BIT(POWER_SUPPLY_USB_TYPE_DCP) | 224*7e541f6dSKaustabh Chakraborty BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), 225*7e541f6dSKaustabh Chakraborty }; 226*7e541f6dSKaustabh Chakraborty 227*7e541f6dSKaustabh Chakraborty static int s2m_chgr_extcon_notifier(struct notifier_block *nb, 228*7e541f6dSKaustabh Chakraborty unsigned long event, void *param) 229*7e541f6dSKaustabh Chakraborty { 230*7e541f6dSKaustabh Chakraborty struct s2m_chgr *priv = container_of(nb, struct s2m_chgr, extcon_nb); 231*7e541f6dSKaustabh Chakraborty 232*7e541f6dSKaustabh Chakraborty schedule_work(&priv->extcon_work); 233*7e541f6dSKaustabh Chakraborty 234*7e541f6dSKaustabh Chakraborty return NOTIFY_OK; 235*7e541f6dSKaustabh Chakraborty } 236*7e541f6dSKaustabh Chakraborty 237*7e541f6dSKaustabh Chakraborty static int s2m_chgr_probe(struct platform_device *pdev) 238*7e541f6dSKaustabh Chakraborty { 239*7e541f6dSKaustabh Chakraborty struct device *dev = &pdev->dev; 240*7e541f6dSKaustabh Chakraborty struct sec_pmic_dev *pmic_drvdata = dev_get_drvdata(dev->parent); 241*7e541f6dSKaustabh Chakraborty struct s2m_chgr *priv; 242*7e541f6dSKaustabh Chakraborty struct device_node *extcon_node __free(device_node) = NULL; 243*7e541f6dSKaustabh Chakraborty struct power_supply_config psy_cfg = {}; 244*7e541f6dSKaustabh Chakraborty const struct power_supply_desc *psy_desc; 245*7e541f6dSKaustabh Chakraborty work_func_t extcon_work_func; 246*7e541f6dSKaustabh Chakraborty int ret; 247*7e541f6dSKaustabh Chakraborty 248*7e541f6dSKaustabh Chakraborty priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 249*7e541f6dSKaustabh Chakraborty if (!priv) 250*7e541f6dSKaustabh Chakraborty return -ENOMEM; 251*7e541f6dSKaustabh Chakraborty 252*7e541f6dSKaustabh Chakraborty platform_set_drvdata(pdev, priv); 253*7e541f6dSKaustabh Chakraborty priv->dev = dev; 254*7e541f6dSKaustabh Chakraborty priv->regmap = pmic_drvdata->regmap_pmic; 255*7e541f6dSKaustabh Chakraborty 256*7e541f6dSKaustabh Chakraborty switch (platform_get_device_id(pdev)->driver_data) { 257*7e541f6dSKaustabh Chakraborty case S2MU005: 258*7e541f6dSKaustabh Chakraborty psy_desc = &s2mu005_chgr_psy_desc; 259*7e541f6dSKaustabh Chakraborty extcon_work_func = s2mu005_chgr_extcon_work; 260*7e541f6dSKaustabh Chakraborty break; 261*7e541f6dSKaustabh Chakraborty default: 262*7e541f6dSKaustabh Chakraborty return dev_err_probe(dev, -ENODEV, 263*7e541f6dSKaustabh Chakraborty "device type %d is not supported by driver\n", 264*7e541f6dSKaustabh Chakraborty pmic_drvdata->device_type); 265*7e541f6dSKaustabh Chakraborty } 266*7e541f6dSKaustabh Chakraborty 267*7e541f6dSKaustabh Chakraborty /* MUIC is mandatory. If unavailable, request probe deferral */ 268*7e541f6dSKaustabh Chakraborty extcon_node = of_get_child_by_name(dev->parent->of_node, "muic"); 269*7e541f6dSKaustabh Chakraborty if (!extcon_node) 270*7e541f6dSKaustabh Chakraborty return dev_err_probe(dev, -ENODEV, "MUIC node required but not found\n"); 271*7e541f6dSKaustabh Chakraborty 272*7e541f6dSKaustabh Chakraborty priv->extcon = extcon_find_edev_by_node(extcon_node); 273*7e541f6dSKaustabh Chakraborty if (IS_ERR(priv->extcon)) 274*7e541f6dSKaustabh Chakraborty return -EPROBE_DEFER; 275*7e541f6dSKaustabh Chakraborty 276*7e541f6dSKaustabh Chakraborty psy_cfg.drv_data = priv; 277*7e541f6dSKaustabh Chakraborty psy_cfg.fwnode = dev_fwnode(dev->parent); 278*7e541f6dSKaustabh Chakraborty priv->psy = devm_power_supply_register(dev, psy_desc, &psy_cfg); 279*7e541f6dSKaustabh Chakraborty if (IS_ERR(priv->psy)) 280*7e541f6dSKaustabh Chakraborty return dev_err_probe(dev, PTR_ERR(priv->psy), 281*7e541f6dSKaustabh Chakraborty "failed to register power supply subsystem\n"); 282*7e541f6dSKaustabh Chakraborty 283*7e541f6dSKaustabh Chakraborty ret = devm_work_autocancel(dev, &priv->extcon_work, extcon_work_func); 284*7e541f6dSKaustabh Chakraborty if (ret) 285*7e541f6dSKaustabh Chakraborty return dev_err_probe(dev, ret, "failed to initialize extcon work\n"); 286*7e541f6dSKaustabh Chakraborty 287*7e541f6dSKaustabh Chakraborty priv->extcon_nb.notifier_call = s2m_chgr_extcon_notifier; 288*7e541f6dSKaustabh Chakraborty ret = devm_extcon_register_notifier_all(dev, priv->extcon, &priv->extcon_nb); 289*7e541f6dSKaustabh Chakraborty if (ret) 290*7e541f6dSKaustabh Chakraborty return dev_err_probe(dev, ret, "failed to register extcon notifier\n"); 291*7e541f6dSKaustabh Chakraborty 292*7e541f6dSKaustabh Chakraborty return 0; 293*7e541f6dSKaustabh Chakraborty } 294*7e541f6dSKaustabh Chakraborty 295*7e541f6dSKaustabh Chakraborty static const struct platform_device_id s2m_chgr_id_table[] = { 296*7e541f6dSKaustabh Chakraborty { "s2mu005-charger", S2MU005 }, 297*7e541f6dSKaustabh Chakraborty { /* sentinel */ }, 298*7e541f6dSKaustabh Chakraborty }; 299*7e541f6dSKaustabh Chakraborty MODULE_DEVICE_TABLE(platform, s2m_chgr_id_table); 300*7e541f6dSKaustabh Chakraborty 301*7e541f6dSKaustabh Chakraborty static struct platform_driver s2m_chgr_driver = { 302*7e541f6dSKaustabh Chakraborty .driver = { 303*7e541f6dSKaustabh Chakraborty .name = "s2m-charger", 304*7e541f6dSKaustabh Chakraborty }, 305*7e541f6dSKaustabh Chakraborty .probe = s2m_chgr_probe, 306*7e541f6dSKaustabh Chakraborty .id_table = s2m_chgr_id_table, 307*7e541f6dSKaustabh Chakraborty }; 308*7e541f6dSKaustabh Chakraborty module_platform_driver(s2m_chgr_driver); 309*7e541f6dSKaustabh Chakraborty 310*7e541f6dSKaustabh Chakraborty MODULE_DESCRIPTION("Battery Charger Driver For Samsung S2M Series PMICs"); 311*7e541f6dSKaustabh Chakraborty MODULE_AUTHOR("Kaustabh Chakraborty <kauschluss@disroot.org>"); 312*7e541f6dSKaustabh Chakraborty MODULE_AUTHOR("Łukasz Lebiedziński <kernel@lvkasz.us>"); 313*7e541f6dSKaustabh Chakraborty MODULE_LICENSE("GPL"); 314