1/* 2 * DA9150 Core MFD Driver 3 * 4 * Copyright (c) 2014 Dialog Semiconductor 5 * 6 * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14#include <linux/kernel.h> 15#include <linux/module.h> 16#include <linux/platform_device.h> 17#include <linux/i2c.h> 18#include <linux/regmap.h> 19#include <linux/slab.h> 20#include <linux/irq.h> 21#include <linux/interrupt.h> 22#include <linux/mfd/core.h> 23#include <linux/mfd/da9150/core.h> 24#include <linux/mfd/da9150/registers.h> 25 26static bool da9150_volatile_reg(struct device *dev, unsigned int reg) 27{ 28 switch (reg) { 29 case DA9150_PAGE_CON: 30 case DA9150_STATUS_A: 31 case DA9150_STATUS_B: 32 case DA9150_STATUS_C: 33 case DA9150_STATUS_D: 34 case DA9150_STATUS_E: 35 case DA9150_STATUS_F: 36 case DA9150_STATUS_G: 37 case DA9150_STATUS_H: 38 case DA9150_STATUS_I: 39 case DA9150_STATUS_J: 40 case DA9150_STATUS_K: 41 case DA9150_STATUS_L: 42 case DA9150_STATUS_N: 43 case DA9150_FAULT_LOG_A: 44 case DA9150_FAULT_LOG_B: 45 case DA9150_EVENT_E: 46 case DA9150_EVENT_F: 47 case DA9150_EVENT_G: 48 case DA9150_EVENT_H: 49 case DA9150_CONTROL_B: 50 case DA9150_CONTROL_C: 51 case DA9150_GPADC_MAN: 52 case DA9150_GPADC_RES_A: 53 case DA9150_GPADC_RES_B: 54 case DA9150_ADETVB_CFG_C: 55 case DA9150_ADETD_STAT: 56 case DA9150_ADET_CMPSTAT: 57 case DA9150_ADET_CTRL_A: 58 case DA9150_PPR_TCTR_B: 59 case DA9150_COREBTLD_STAT_A: 60 case DA9150_CORE_DATA_A: 61 case DA9150_CORE_DATA_B: 62 case DA9150_CORE_DATA_C: 63 case DA9150_CORE_DATA_D: 64 case DA9150_CORE2WIRE_STAT_A: 65 case DA9150_FW_CTRL_C: 66 case DA9150_FG_CTRL_B: 67 case DA9150_FW_CTRL_B: 68 case DA9150_GPADC_CMAN: 69 case DA9150_GPADC_CRES_A: 70 case DA9150_GPADC_CRES_B: 71 case DA9150_CC_ICHG_RES_A: 72 case DA9150_CC_ICHG_RES_B: 73 case DA9150_CC_IAVG_RES_A: 74 case DA9150_CC_IAVG_RES_B: 75 case DA9150_TAUX_CTRL_A: 76 case DA9150_TAUX_VALUE_H: 77 case DA9150_TAUX_VALUE_L: 78 case DA9150_TBAT_RES_A: 79 case DA9150_TBAT_RES_B: 80 return true; 81 default: 82 return false; 83 } 84} 85 86static const struct regmap_range_cfg da9150_range_cfg[] = { 87 { 88 .range_min = DA9150_PAGE_CON, 89 .range_max = DA9150_TBAT_RES_B, 90 .selector_reg = DA9150_PAGE_CON, 91 .selector_mask = DA9150_I2C_PAGE_MASK, 92 .selector_shift = DA9150_I2C_PAGE_SHIFT, 93 .window_start = 0, 94 .window_len = 256, 95 }, 96}; 97 98static const struct regmap_config da9150_regmap_config = { 99 .reg_bits = 8, 100 .val_bits = 8, 101 .ranges = da9150_range_cfg, 102 .num_ranges = ARRAY_SIZE(da9150_range_cfg), 103 .max_register = DA9150_TBAT_RES_B, 104 105 .cache_type = REGCACHE_RBTREE, 106 107 .volatile_reg = da9150_volatile_reg, 108}; 109 110u8 da9150_reg_read(struct da9150 *da9150, u16 reg) 111{ 112 int val, ret; 113 114 ret = regmap_read(da9150->regmap, reg, &val); 115 if (ret) 116 dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n", 117 reg, ret); 118 119 return (u8) val; 120} 121EXPORT_SYMBOL_GPL(da9150_reg_read); 122 123void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val) 124{ 125 int ret; 126 127 ret = regmap_write(da9150->regmap, reg, val); 128 if (ret) 129 dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n", 130 reg, ret); 131} 132EXPORT_SYMBOL_GPL(da9150_reg_write); 133 134void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val) 135{ 136 int ret; 137 138 ret = regmap_update_bits(da9150->regmap, reg, mask, val); 139 if (ret) 140 dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n", 141 reg, ret); 142} 143EXPORT_SYMBOL_GPL(da9150_set_bits); 144 145void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf) 146{ 147 int ret; 148 149 ret = regmap_bulk_read(da9150->regmap, reg, buf, count); 150 if (ret) 151 dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n", 152 reg, ret); 153} 154EXPORT_SYMBOL_GPL(da9150_bulk_read); 155 156void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf) 157{ 158 int ret; 159 160 ret = regmap_raw_write(da9150->regmap, reg, buf, count); 161 if (ret) 162 dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n", 163 reg, ret); 164} 165EXPORT_SYMBOL_GPL(da9150_bulk_write); 166 167static struct regmap_irq da9150_irqs[] = { 168 [DA9150_IRQ_VBUS] = { 169 .reg_offset = 0, 170 .mask = DA9150_E_VBUS_MASK, 171 }, 172 [DA9150_IRQ_CHG] = { 173 .reg_offset = 0, 174 .mask = DA9150_E_CHG_MASK, 175 }, 176 [DA9150_IRQ_TCLASS] = { 177 .reg_offset = 0, 178 .mask = DA9150_E_TCLASS_MASK, 179 }, 180 [DA9150_IRQ_TJUNC] = { 181 .reg_offset = 0, 182 .mask = DA9150_E_TJUNC_MASK, 183 }, 184 [DA9150_IRQ_VFAULT] = { 185 .reg_offset = 0, 186 .mask = DA9150_E_VFAULT_MASK, 187 }, 188 [DA9150_IRQ_CONF] = { 189 .reg_offset = 1, 190 .mask = DA9150_E_CONF_MASK, 191 }, 192 [DA9150_IRQ_DAT] = { 193 .reg_offset = 1, 194 .mask = DA9150_E_DAT_MASK, 195 }, 196 [DA9150_IRQ_DTYPE] = { 197 .reg_offset = 1, 198 .mask = DA9150_E_DTYPE_MASK, 199 }, 200 [DA9150_IRQ_ID] = { 201 .reg_offset = 1, 202 .mask = DA9150_E_ID_MASK, 203 }, 204 [DA9150_IRQ_ADP] = { 205 .reg_offset = 1, 206 .mask = DA9150_E_ADP_MASK, 207 }, 208 [DA9150_IRQ_SESS_END] = { 209 .reg_offset = 1, 210 .mask = DA9150_E_SESS_END_MASK, 211 }, 212 [DA9150_IRQ_SESS_VLD] = { 213 .reg_offset = 1, 214 .mask = DA9150_E_SESS_VLD_MASK, 215 }, 216 [DA9150_IRQ_FG] = { 217 .reg_offset = 2, 218 .mask = DA9150_E_FG_MASK, 219 }, 220 [DA9150_IRQ_GP] = { 221 .reg_offset = 2, 222 .mask = DA9150_E_GP_MASK, 223 }, 224 [DA9150_IRQ_TBAT] = { 225 .reg_offset = 2, 226 .mask = DA9150_E_TBAT_MASK, 227 }, 228 [DA9150_IRQ_GPIOA] = { 229 .reg_offset = 2, 230 .mask = DA9150_E_GPIOA_MASK, 231 }, 232 [DA9150_IRQ_GPIOB] = { 233 .reg_offset = 2, 234 .mask = DA9150_E_GPIOB_MASK, 235 }, 236 [DA9150_IRQ_GPIOC] = { 237 .reg_offset = 2, 238 .mask = DA9150_E_GPIOC_MASK, 239 }, 240 [DA9150_IRQ_GPIOD] = { 241 .reg_offset = 2, 242 .mask = DA9150_E_GPIOD_MASK, 243 }, 244 [DA9150_IRQ_GPADC] = { 245 .reg_offset = 2, 246 .mask = DA9150_E_GPADC_MASK, 247 }, 248 [DA9150_IRQ_WKUP] = { 249 .reg_offset = 3, 250 .mask = DA9150_E_WKUP_MASK, 251 }, 252}; 253 254static struct regmap_irq_chip da9150_regmap_irq_chip = { 255 .name = "da9150_irq", 256 .status_base = DA9150_EVENT_E, 257 .mask_base = DA9150_IRQ_MASK_E, 258 .ack_base = DA9150_EVENT_E, 259 .num_regs = DA9150_NUM_IRQ_REGS, 260 .irqs = da9150_irqs, 261 .num_irqs = ARRAY_SIZE(da9150_irqs), 262}; 263 264static struct resource da9150_gpadc_resources[] = { 265 { 266 .name = "GPADC", 267 .start = DA9150_IRQ_GPADC, 268 .end = DA9150_IRQ_GPADC, 269 .flags = IORESOURCE_IRQ, 270 }, 271}; 272 273static struct resource da9150_charger_resources[] = { 274 { 275 .name = "CHG_STATUS", 276 .start = DA9150_IRQ_CHG, 277 .end = DA9150_IRQ_CHG, 278 .flags = IORESOURCE_IRQ, 279 }, 280 { 281 .name = "CHG_TJUNC", 282 .start = DA9150_IRQ_TJUNC, 283 .end = DA9150_IRQ_TJUNC, 284 .flags = IORESOURCE_IRQ, 285 }, 286 { 287 .name = "CHG_VFAULT", 288 .start = DA9150_IRQ_VFAULT, 289 .end = DA9150_IRQ_VFAULT, 290 .flags = IORESOURCE_IRQ, 291 }, 292 { 293 .name = "CHG_VBUS", 294 .start = DA9150_IRQ_VBUS, 295 .end = DA9150_IRQ_VBUS, 296 .flags = IORESOURCE_IRQ, 297 }, 298}; 299 300static struct mfd_cell da9150_devs[] = { 301 { 302 .name = "da9150-gpadc", 303 .of_compatible = "dlg,da9150-gpadc", 304 .resources = da9150_gpadc_resources, 305 .num_resources = ARRAY_SIZE(da9150_gpadc_resources), 306 }, 307 { 308 .name = "da9150-charger", 309 .of_compatible = "dlg,da9150-charger", 310 .resources = da9150_charger_resources, 311 .num_resources = ARRAY_SIZE(da9150_charger_resources), 312 }, 313}; 314 315static int da9150_probe(struct i2c_client *client, 316 const struct i2c_device_id *id) 317{ 318 struct da9150 *da9150; 319 struct da9150_pdata *pdata = dev_get_platdata(&client->dev); 320 int ret; 321 322 da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL); 323 if (!da9150) 324 return -ENOMEM; 325 326 da9150->dev = &client->dev; 327 da9150->irq = client->irq; 328 i2c_set_clientdata(client, da9150); 329 330 da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config); 331 if (IS_ERR(da9150->regmap)) { 332 ret = PTR_ERR(da9150->regmap); 333 dev_err(da9150->dev, "Failed to allocate register map: %d\n", 334 ret); 335 return ret; 336 } 337 338 da9150->irq_base = pdata ? pdata->irq_base : -1; 339 340 ret = regmap_add_irq_chip(da9150->regmap, da9150->irq, 341 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 342 da9150->irq_base, &da9150_regmap_irq_chip, 343 &da9150->regmap_irq_data); 344 if (ret) 345 return ret; 346 347 da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data); 348 enable_irq_wake(da9150->irq); 349 350 ret = mfd_add_devices(da9150->dev, -1, da9150_devs, 351 ARRAY_SIZE(da9150_devs), NULL, 352 da9150->irq_base, NULL); 353 if (ret) { 354 dev_err(da9150->dev, "Failed to add child devices: %d\n", ret); 355 regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); 356 return ret; 357 } 358 359 return 0; 360} 361 362static int da9150_remove(struct i2c_client *client) 363{ 364 struct da9150 *da9150 = i2c_get_clientdata(client); 365 366 regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); 367 mfd_remove_devices(da9150->dev); 368 369 return 0; 370} 371 372static void da9150_shutdown(struct i2c_client *client) 373{ 374 struct da9150 *da9150 = i2c_get_clientdata(client); 375 376 /* Make sure we have a wakup source for the device */ 377 da9150_set_bits(da9150, DA9150_CONFIG_D, 378 DA9150_WKUP_PM_EN_MASK, 379 DA9150_WKUP_PM_EN_MASK); 380 381 /* Set device to DISABLED mode */ 382 da9150_set_bits(da9150, DA9150_CONTROL_C, 383 DA9150_DISABLE_MASK, DA9150_DISABLE_MASK); 384} 385 386static const struct i2c_device_id da9150_i2c_id[] = { 387 { "da9150", }, 388 { } 389}; 390MODULE_DEVICE_TABLE(i2c, da9150_i2c_id); 391 392static const struct of_device_id da9150_of_match[] = { 393 { .compatible = "dlg,da9150", }, 394 { } 395}; 396MODULE_DEVICE_TABLE(of, da9150_of_match); 397 398static struct i2c_driver da9150_driver = { 399 .driver = { 400 .name = "da9150", 401 .of_match_table = of_match_ptr(da9150_of_match), 402 }, 403 .probe = da9150_probe, 404 .remove = da9150_remove, 405 .shutdown = da9150_shutdown, 406 .id_table = da9150_i2c_id, 407}; 408 409module_i2c_driver(da9150_driver); 410 411MODULE_DESCRIPTION("MFD Core Driver for DA9150"); 412MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); 413MODULE_LICENSE("GPL"); 414