Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * DA9150 Core MFD Driver
0004  *
0005  * Copyright (c) 2014 Dialog Semiconductor
0006  *
0007  * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/i2c.h>
0014 #include <linux/regmap.h>
0015 #include <linux/slab.h>
0016 #include <linux/irq.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/mfd/core.h>
0019 #include <linux/mfd/da9150/core.h>
0020 #include <linux/mfd/da9150/registers.h>
0021 
0022 /* Raw device access, used for QIF */
0023 static int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count,
0024                   u8 *buf)
0025 {
0026     struct i2c_msg xfer;
0027     int ret;
0028 
0029     /*
0030      * Read is split into two transfers as device expects STOP/START rather
0031      * than repeated start to carry out this kind of access.
0032      */
0033 
0034     /* Write address */
0035     xfer.addr = client->addr;
0036     xfer.flags = 0;
0037     xfer.len = 1;
0038     xfer.buf = &addr;
0039 
0040     ret = i2c_transfer(client->adapter, &xfer, 1);
0041     if (ret != 1) {
0042         if (ret < 0)
0043             return ret;
0044         else
0045             return -EIO;
0046     }
0047 
0048     /* Read data */
0049     xfer.addr = client->addr;
0050     xfer.flags = I2C_M_RD;
0051     xfer.len = count;
0052     xfer.buf = buf;
0053 
0054     ret = i2c_transfer(client->adapter, &xfer, 1);
0055     if (ret == 1)
0056         return 0;
0057     else if (ret < 0)
0058         return ret;
0059     else
0060         return -EIO;
0061 }
0062 
0063 static int da9150_i2c_write_device(struct i2c_client *client, u8 addr,
0064                    int count, const u8 *buf)
0065 {
0066     struct i2c_msg xfer;
0067     u8 *reg_data;
0068     int ret;
0069 
0070     reg_data = kzalloc(1 + count, GFP_KERNEL);
0071     if (!reg_data)
0072         return -ENOMEM;
0073 
0074     reg_data[0] = addr;
0075     memcpy(&reg_data[1], buf, count);
0076 
0077     /* Write address & data */
0078     xfer.addr = client->addr;
0079     xfer.flags = 0;
0080     xfer.len = 1 + count;
0081     xfer.buf = reg_data;
0082 
0083     ret = i2c_transfer(client->adapter, &xfer, 1);
0084     kfree(reg_data);
0085     if (ret == 1)
0086         return 0;
0087     else if (ret < 0)
0088         return ret;
0089     else
0090         return -EIO;
0091 }
0092 
0093 static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
0094 {
0095     switch (reg) {
0096     case DA9150_PAGE_CON:
0097     case DA9150_STATUS_A:
0098     case DA9150_STATUS_B:
0099     case DA9150_STATUS_C:
0100     case DA9150_STATUS_D:
0101     case DA9150_STATUS_E:
0102     case DA9150_STATUS_F:
0103     case DA9150_STATUS_G:
0104     case DA9150_STATUS_H:
0105     case DA9150_STATUS_I:
0106     case DA9150_STATUS_J:
0107     case DA9150_STATUS_K:
0108     case DA9150_STATUS_L:
0109     case DA9150_STATUS_N:
0110     case DA9150_FAULT_LOG_A:
0111     case DA9150_FAULT_LOG_B:
0112     case DA9150_EVENT_E:
0113     case DA9150_EVENT_F:
0114     case DA9150_EVENT_G:
0115     case DA9150_EVENT_H:
0116     case DA9150_CONTROL_B:
0117     case DA9150_CONTROL_C:
0118     case DA9150_GPADC_MAN:
0119     case DA9150_GPADC_RES_A:
0120     case DA9150_GPADC_RES_B:
0121     case DA9150_ADETVB_CFG_C:
0122     case DA9150_ADETD_STAT:
0123     case DA9150_ADET_CMPSTAT:
0124     case DA9150_ADET_CTRL_A:
0125     case DA9150_PPR_TCTR_B:
0126     case DA9150_COREBTLD_STAT_A:
0127     case DA9150_CORE_DATA_A:
0128     case DA9150_CORE_DATA_B:
0129     case DA9150_CORE_DATA_C:
0130     case DA9150_CORE_DATA_D:
0131     case DA9150_CORE2WIRE_STAT_A:
0132     case DA9150_FW_CTRL_C:
0133     case DA9150_FG_CTRL_B:
0134     case DA9150_FW_CTRL_B:
0135     case DA9150_GPADC_CMAN:
0136     case DA9150_GPADC_CRES_A:
0137     case DA9150_GPADC_CRES_B:
0138     case DA9150_CC_ICHG_RES_A:
0139     case DA9150_CC_ICHG_RES_B:
0140     case DA9150_CC_IAVG_RES_A:
0141     case DA9150_CC_IAVG_RES_B:
0142     case DA9150_TAUX_CTRL_A:
0143     case DA9150_TAUX_VALUE_H:
0144     case DA9150_TAUX_VALUE_L:
0145     case DA9150_TBAT_RES_A:
0146     case DA9150_TBAT_RES_B:
0147         return true;
0148     default:
0149         return false;
0150     }
0151 }
0152 
0153 static const struct regmap_range_cfg da9150_range_cfg[] = {
0154     {
0155         .range_min = DA9150_PAGE_CON,
0156         .range_max = DA9150_TBAT_RES_B,
0157         .selector_reg = DA9150_PAGE_CON,
0158         .selector_mask = DA9150_I2C_PAGE_MASK,
0159         .selector_shift = DA9150_I2C_PAGE_SHIFT,
0160         .window_start = 0,
0161         .window_len = 256,
0162     },
0163 };
0164 
0165 static const struct regmap_config da9150_regmap_config = {
0166     .reg_bits = 8,
0167     .val_bits = 8,
0168     .ranges = da9150_range_cfg,
0169     .num_ranges = ARRAY_SIZE(da9150_range_cfg),
0170     .max_register = DA9150_TBAT_RES_B,
0171 
0172     .cache_type = REGCACHE_RBTREE,
0173 
0174     .volatile_reg = da9150_volatile_reg,
0175 };
0176 
0177 void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf)
0178 {
0179     int ret;
0180 
0181     ret = da9150_i2c_read_device(da9150->core_qif, addr, count, buf);
0182     if (ret < 0)
0183         dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n",
0184             addr, ret);
0185 }
0186 EXPORT_SYMBOL_GPL(da9150_read_qif);
0187 
0188 void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf)
0189 {
0190     int ret;
0191 
0192     ret = da9150_i2c_write_device(da9150->core_qif, addr, count, buf);
0193     if (ret < 0)
0194         dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n",
0195             addr, ret);
0196 }
0197 EXPORT_SYMBOL_GPL(da9150_write_qif);
0198 
0199 u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
0200 {
0201     int val, ret;
0202 
0203     ret = regmap_read(da9150->regmap, reg, &val);
0204     if (ret)
0205         dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
0206             reg, ret);
0207 
0208     return (u8) val;
0209 }
0210 EXPORT_SYMBOL_GPL(da9150_reg_read);
0211 
0212 void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
0213 {
0214     int ret;
0215 
0216     ret = regmap_write(da9150->regmap, reg, val);
0217     if (ret)
0218         dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
0219             reg, ret);
0220 }
0221 EXPORT_SYMBOL_GPL(da9150_reg_write);
0222 
0223 void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
0224 {
0225     int ret;
0226 
0227     ret = regmap_update_bits(da9150->regmap, reg, mask, val);
0228     if (ret)
0229         dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
0230             reg, ret);
0231 }
0232 EXPORT_SYMBOL_GPL(da9150_set_bits);
0233 
0234 void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
0235 {
0236     int ret;
0237 
0238     ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
0239     if (ret)
0240         dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
0241             reg, ret);
0242 }
0243 EXPORT_SYMBOL_GPL(da9150_bulk_read);
0244 
0245 void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
0246 {
0247     int ret;
0248 
0249     ret = regmap_raw_write(da9150->regmap, reg, buf, count);
0250     if (ret)
0251         dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
0252             reg, ret);
0253 }
0254 EXPORT_SYMBOL_GPL(da9150_bulk_write);
0255 
0256 static const struct regmap_irq da9150_irqs[] = {
0257     [DA9150_IRQ_VBUS] = {
0258         .reg_offset = 0,
0259         .mask = DA9150_E_VBUS_MASK,
0260     },
0261     [DA9150_IRQ_CHG] = {
0262         .reg_offset = 0,
0263         .mask = DA9150_E_CHG_MASK,
0264     },
0265     [DA9150_IRQ_TCLASS] = {
0266         .reg_offset = 0,
0267         .mask = DA9150_E_TCLASS_MASK,
0268     },
0269     [DA9150_IRQ_TJUNC] = {
0270         .reg_offset = 0,
0271         .mask = DA9150_E_TJUNC_MASK,
0272     },
0273     [DA9150_IRQ_VFAULT] = {
0274         .reg_offset = 0,
0275         .mask = DA9150_E_VFAULT_MASK,
0276     },
0277     [DA9150_IRQ_CONF] = {
0278         .reg_offset = 1,
0279         .mask = DA9150_E_CONF_MASK,
0280     },
0281     [DA9150_IRQ_DAT] = {
0282         .reg_offset = 1,
0283         .mask = DA9150_E_DAT_MASK,
0284     },
0285     [DA9150_IRQ_DTYPE] = {
0286         .reg_offset = 1,
0287         .mask = DA9150_E_DTYPE_MASK,
0288     },
0289     [DA9150_IRQ_ID] = {
0290         .reg_offset = 1,
0291         .mask = DA9150_E_ID_MASK,
0292     },
0293     [DA9150_IRQ_ADP] = {
0294         .reg_offset = 1,
0295         .mask = DA9150_E_ADP_MASK,
0296     },
0297     [DA9150_IRQ_SESS_END] = {
0298         .reg_offset = 1,
0299         .mask = DA9150_E_SESS_END_MASK,
0300     },
0301     [DA9150_IRQ_SESS_VLD] = {
0302         .reg_offset = 1,
0303         .mask = DA9150_E_SESS_VLD_MASK,
0304     },
0305     [DA9150_IRQ_FG] = {
0306         .reg_offset = 2,
0307         .mask = DA9150_E_FG_MASK,
0308     },
0309     [DA9150_IRQ_GP] = {
0310         .reg_offset = 2,
0311         .mask = DA9150_E_GP_MASK,
0312     },
0313     [DA9150_IRQ_TBAT] = {
0314         .reg_offset = 2,
0315         .mask = DA9150_E_TBAT_MASK,
0316     },
0317     [DA9150_IRQ_GPIOA] = {
0318         .reg_offset = 2,
0319         .mask = DA9150_E_GPIOA_MASK,
0320     },
0321     [DA9150_IRQ_GPIOB] = {
0322         .reg_offset = 2,
0323         .mask = DA9150_E_GPIOB_MASK,
0324     },
0325     [DA9150_IRQ_GPIOC] = {
0326         .reg_offset = 2,
0327         .mask = DA9150_E_GPIOC_MASK,
0328     },
0329     [DA9150_IRQ_GPIOD] = {
0330         .reg_offset = 2,
0331         .mask = DA9150_E_GPIOD_MASK,
0332     },
0333     [DA9150_IRQ_GPADC] = {
0334         .reg_offset = 2,
0335         .mask = DA9150_E_GPADC_MASK,
0336     },
0337     [DA9150_IRQ_WKUP] = {
0338         .reg_offset = 3,
0339         .mask = DA9150_E_WKUP_MASK,
0340     },
0341 };
0342 
0343 static const struct regmap_irq_chip da9150_regmap_irq_chip = {
0344     .name = "da9150_irq",
0345     .status_base = DA9150_EVENT_E,
0346     .mask_base = DA9150_IRQ_MASK_E,
0347     .ack_base = DA9150_EVENT_E,
0348     .num_regs = DA9150_NUM_IRQ_REGS,
0349     .irqs = da9150_irqs,
0350     .num_irqs = ARRAY_SIZE(da9150_irqs),
0351 };
0352 
0353 static const struct resource da9150_gpadc_resources[] = {
0354     DEFINE_RES_IRQ_NAMED(DA9150_IRQ_GPADC, "GPADC"),
0355 };
0356 
0357 static const struct resource da9150_charger_resources[] = {
0358     DEFINE_RES_IRQ_NAMED(DA9150_IRQ_CHG, "CHG_STATUS"),
0359     DEFINE_RES_IRQ_NAMED(DA9150_IRQ_TJUNC, "CHG_TJUNC"),
0360     DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VFAULT, "CHG_VFAULT"),
0361     DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VBUS, "CHG_VBUS"),
0362 };
0363 
0364 static const struct resource da9150_fg_resources[] = {
0365     DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG"),
0366 };
0367 
0368 enum da9150_dev_idx {
0369     DA9150_GPADC_IDX = 0,
0370     DA9150_CHARGER_IDX,
0371     DA9150_FG_IDX,
0372 };
0373 
0374 static struct mfd_cell da9150_devs[] = {
0375     [DA9150_GPADC_IDX] = {
0376         .name = "da9150-gpadc",
0377         .of_compatible = "dlg,da9150-gpadc",
0378         .resources = da9150_gpadc_resources,
0379         .num_resources = ARRAY_SIZE(da9150_gpadc_resources),
0380     },
0381     [DA9150_CHARGER_IDX] = {
0382         .name = "da9150-charger",
0383         .of_compatible = "dlg,da9150-charger",
0384         .resources = da9150_charger_resources,
0385         .num_resources = ARRAY_SIZE(da9150_charger_resources),
0386     },
0387     [DA9150_FG_IDX] = {
0388         .name = "da9150-fuel-gauge",
0389         .of_compatible = "dlg,da9150-fuel-gauge",
0390         .resources = da9150_fg_resources,
0391         .num_resources = ARRAY_SIZE(da9150_fg_resources),
0392     },
0393 };
0394 
0395 static int da9150_probe(struct i2c_client *client,
0396             const struct i2c_device_id *id)
0397 {
0398     struct da9150 *da9150;
0399     struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
0400     int qif_addr;
0401     int ret;
0402 
0403     da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
0404     if (!da9150)
0405         return -ENOMEM;
0406 
0407     da9150->dev = &client->dev;
0408     da9150->irq = client->irq;
0409     i2c_set_clientdata(client, da9150);
0410 
0411     da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
0412     if (IS_ERR(da9150->regmap)) {
0413         ret = PTR_ERR(da9150->regmap);
0414         dev_err(da9150->dev, "Failed to allocate register map: %d\n",
0415             ret);
0416         return ret;
0417     }
0418 
0419     /* Setup secondary I2C interface for QIF access */
0420     qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A);
0421     qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1;
0422     qif_addr |= DA9150_QIF_I2C_ADDR_LSB;
0423     da9150->core_qif = i2c_new_dummy_device(client->adapter, qif_addr);
0424     if (IS_ERR(da9150->core_qif)) {
0425         dev_err(da9150->dev, "Failed to attach QIF client\n");
0426         return PTR_ERR(da9150->core_qif);
0427     }
0428 
0429     i2c_set_clientdata(da9150->core_qif, da9150);
0430 
0431     if (pdata) {
0432         da9150->irq_base = pdata->irq_base;
0433 
0434         da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata;
0435         da9150_devs[DA9150_FG_IDX].pdata_size =
0436             sizeof(struct da9150_fg_pdata);
0437     } else {
0438         da9150->irq_base = -1;
0439     }
0440 
0441     ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
0442                   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
0443                   da9150->irq_base, &da9150_regmap_irq_chip,
0444                   &da9150->regmap_irq_data);
0445     if (ret) {
0446         dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n",
0447             ret);
0448         goto regmap_irq_fail;
0449     }
0450 
0451 
0452     da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
0453 
0454     enable_irq_wake(da9150->irq);
0455 
0456     ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
0457                   ARRAY_SIZE(da9150_devs), NULL,
0458                   da9150->irq_base, NULL);
0459     if (ret) {
0460         dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
0461         goto mfd_fail;
0462     }
0463 
0464     return 0;
0465 
0466 mfd_fail:
0467     regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
0468 regmap_irq_fail:
0469     i2c_unregister_device(da9150->core_qif);
0470 
0471     return ret;
0472 }
0473 
0474 static int da9150_remove(struct i2c_client *client)
0475 {
0476     struct da9150 *da9150 = i2c_get_clientdata(client);
0477 
0478     regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
0479     mfd_remove_devices(da9150->dev);
0480     i2c_unregister_device(da9150->core_qif);
0481 
0482     return 0;
0483 }
0484 
0485 static void da9150_shutdown(struct i2c_client *client)
0486 {
0487     struct da9150 *da9150 = i2c_get_clientdata(client);
0488 
0489     /* Make sure we have a wakup source for the device */
0490     da9150_set_bits(da9150, DA9150_CONFIG_D,
0491             DA9150_WKUP_PM_EN_MASK,
0492             DA9150_WKUP_PM_EN_MASK);
0493 
0494     /* Set device to DISABLED mode */
0495     da9150_set_bits(da9150, DA9150_CONTROL_C,
0496             DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
0497 }
0498 
0499 static const struct i2c_device_id da9150_i2c_id[] = {
0500     { "da9150", },
0501     { }
0502 };
0503 MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
0504 
0505 static const struct of_device_id da9150_of_match[] = {
0506     { .compatible = "dlg,da9150", },
0507     { }
0508 };
0509 MODULE_DEVICE_TABLE(of, da9150_of_match);
0510 
0511 static struct i2c_driver da9150_driver = {
0512     .driver = {
0513         .name   = "da9150",
0514         .of_match_table = da9150_of_match,
0515     },
0516     .probe      = da9150_probe,
0517     .remove     = da9150_remove,
0518     .shutdown   = da9150_shutdown,
0519     .id_table   = da9150_i2c_id,
0520 };
0521 
0522 module_i2c_driver(da9150_driver);
0523 
0524 MODULE_DESCRIPTION("MFD Core Driver for DA9150");
0525 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
0526 MODULE_LICENSE("GPL");