402 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Device access for Dialog DA9055 PMICs.4 *5 * Copyright(c) 2012 Dialog Semiconductor Ltd.6 *7 * Author: David Dajun Chen <dchen@diasemi.com>8 */9 10#include <linux/module.h>11#include <linux/device.h>12#include <linux/input.h>13#include <linux/irq.h>14#include <linux/mutex.h>15 16#include <linux/mfd/core.h>17#include <linux/mfd/da9055/core.h>18#include <linux/mfd/da9055/pdata.h>19#include <linux/mfd/da9055/reg.h>20 21#define DA9055_IRQ_NONKEY_MASK 0x0122#define DA9055_IRQ_ALM_MASK 0x0223#define DA9055_IRQ_TICK_MASK 0x0424#define DA9055_IRQ_ADC_MASK 0x0825#define DA9055_IRQ_BUCK_ILIM_MASK 0x0826 27static bool da9055_register_readable(struct device *dev, unsigned int reg)28{29 switch (reg) {30 case DA9055_REG_STATUS_A:31 case DA9055_REG_STATUS_B:32 case DA9055_REG_EVENT_A:33 case DA9055_REG_EVENT_B:34 case DA9055_REG_EVENT_C:35 case DA9055_REG_IRQ_MASK_A:36 case DA9055_REG_IRQ_MASK_B:37 case DA9055_REG_IRQ_MASK_C:38 39 case DA9055_REG_CONTROL_A:40 case DA9055_REG_CONTROL_B:41 case DA9055_REG_CONTROL_C:42 case DA9055_REG_CONTROL_D:43 case DA9055_REG_CONTROL_E:44 45 case DA9055_REG_ADC_MAN:46 case DA9055_REG_ADC_CONT:47 case DA9055_REG_VSYS_MON:48 case DA9055_REG_ADC_RES_L:49 case DA9055_REG_ADC_RES_H:50 case DA9055_REG_VSYS_RES:51 case DA9055_REG_ADCIN1_RES:52 case DA9055_REG_ADCIN2_RES:53 case DA9055_REG_ADCIN3_RES:54 55 case DA9055_REG_COUNT_S:56 case DA9055_REG_COUNT_MI:57 case DA9055_REG_COUNT_H:58 case DA9055_REG_COUNT_D:59 case DA9055_REG_COUNT_MO:60 case DA9055_REG_COUNT_Y:61 case DA9055_REG_ALARM_H:62 case DA9055_REG_ALARM_D:63 case DA9055_REG_ALARM_MI:64 case DA9055_REG_ALARM_MO:65 case DA9055_REG_ALARM_Y:66 67 case DA9055_REG_GPIO0_1:68 case DA9055_REG_GPIO2:69 case DA9055_REG_GPIO_MODE0_2:70 71 case DA9055_REG_BCORE_CONT:72 case DA9055_REG_BMEM_CONT:73 case DA9055_REG_LDO1_CONT:74 case DA9055_REG_LDO2_CONT:75 case DA9055_REG_LDO3_CONT:76 case DA9055_REG_LDO4_CONT:77 case DA9055_REG_LDO5_CONT:78 case DA9055_REG_LDO6_CONT:79 case DA9055_REG_BUCK_LIM:80 case DA9055_REG_BCORE_MODE:81 case DA9055_REG_VBCORE_A:82 case DA9055_REG_VBMEM_A:83 case DA9055_REG_VLDO1_A:84 case DA9055_REG_VLDO2_A:85 case DA9055_REG_VLDO3_A:86 case DA9055_REG_VLDO4_A:87 case DA9055_REG_VLDO5_A:88 case DA9055_REG_VLDO6_A:89 case DA9055_REG_VBCORE_B:90 case DA9055_REG_VBMEM_B:91 case DA9055_REG_VLDO1_B:92 case DA9055_REG_VLDO2_B:93 case DA9055_REG_VLDO3_B:94 case DA9055_REG_VLDO4_B:95 case DA9055_REG_VLDO5_B:96 case DA9055_REG_VLDO6_B:97 return true;98 default:99 return false;100 }101}102 103static bool da9055_register_writeable(struct device *dev, unsigned int reg)104{105 switch (reg) {106 case DA9055_REG_STATUS_A:107 case DA9055_REG_STATUS_B:108 case DA9055_REG_EVENT_A:109 case DA9055_REG_EVENT_B:110 case DA9055_REG_EVENT_C:111 case DA9055_REG_IRQ_MASK_A:112 case DA9055_REG_IRQ_MASK_B:113 case DA9055_REG_IRQ_MASK_C:114 115 case DA9055_REG_CONTROL_A:116 case DA9055_REG_CONTROL_B:117 case DA9055_REG_CONTROL_C:118 case DA9055_REG_CONTROL_D:119 case DA9055_REG_CONTROL_E:120 121 case DA9055_REG_ADC_MAN:122 case DA9055_REG_ADC_CONT:123 case DA9055_REG_VSYS_MON:124 case DA9055_REG_ADC_RES_L:125 case DA9055_REG_ADC_RES_H:126 case DA9055_REG_VSYS_RES:127 case DA9055_REG_ADCIN1_RES:128 case DA9055_REG_ADCIN2_RES:129 case DA9055_REG_ADCIN3_RES:130 131 case DA9055_REG_COUNT_S:132 case DA9055_REG_COUNT_MI:133 case DA9055_REG_COUNT_H:134 case DA9055_REG_COUNT_D:135 case DA9055_REG_COUNT_MO:136 case DA9055_REG_COUNT_Y:137 case DA9055_REG_ALARM_H:138 case DA9055_REG_ALARM_D:139 case DA9055_REG_ALARM_MI:140 case DA9055_REG_ALARM_MO:141 case DA9055_REG_ALARM_Y:142 143 case DA9055_REG_GPIO0_1:144 case DA9055_REG_GPIO2:145 case DA9055_REG_GPIO_MODE0_2:146 147 case DA9055_REG_BCORE_CONT:148 case DA9055_REG_BMEM_CONT:149 case DA9055_REG_LDO1_CONT:150 case DA9055_REG_LDO2_CONT:151 case DA9055_REG_LDO3_CONT:152 case DA9055_REG_LDO4_CONT:153 case DA9055_REG_LDO5_CONT:154 case DA9055_REG_LDO6_CONT:155 case DA9055_REG_BUCK_LIM:156 case DA9055_REG_BCORE_MODE:157 case DA9055_REG_VBCORE_A:158 case DA9055_REG_VBMEM_A:159 case DA9055_REG_VLDO1_A:160 case DA9055_REG_VLDO2_A:161 case DA9055_REG_VLDO3_A:162 case DA9055_REG_VLDO4_A:163 case DA9055_REG_VLDO5_A:164 case DA9055_REG_VLDO6_A:165 case DA9055_REG_VBCORE_B:166 case DA9055_REG_VBMEM_B:167 case DA9055_REG_VLDO1_B:168 case DA9055_REG_VLDO2_B:169 case DA9055_REG_VLDO3_B:170 case DA9055_REG_VLDO4_B:171 case DA9055_REG_VLDO5_B:172 case DA9055_REG_VLDO6_B:173 return true;174 default:175 return false;176 }177}178 179static bool da9055_register_volatile(struct device *dev, unsigned int reg)180{181 switch (reg) {182 case DA9055_REG_STATUS_A:183 case DA9055_REG_STATUS_B:184 case DA9055_REG_EVENT_A:185 case DA9055_REG_EVENT_B:186 case DA9055_REG_EVENT_C:187 188 case DA9055_REG_CONTROL_A:189 case DA9055_REG_CONTROL_E:190 191 case DA9055_REG_ADC_MAN:192 case DA9055_REG_ADC_RES_L:193 case DA9055_REG_ADC_RES_H:194 case DA9055_REG_VSYS_RES:195 case DA9055_REG_ADCIN1_RES:196 case DA9055_REG_ADCIN2_RES:197 case DA9055_REG_ADCIN3_RES:198 199 case DA9055_REG_COUNT_S:200 case DA9055_REG_COUNT_MI:201 case DA9055_REG_COUNT_H:202 case DA9055_REG_COUNT_D:203 case DA9055_REG_COUNT_MO:204 case DA9055_REG_COUNT_Y:205 case DA9055_REG_ALARM_MI:206 207 case DA9055_REG_BCORE_CONT:208 case DA9055_REG_BMEM_CONT:209 case DA9055_REG_LDO1_CONT:210 case DA9055_REG_LDO2_CONT:211 case DA9055_REG_LDO3_CONT:212 case DA9055_REG_LDO4_CONT:213 case DA9055_REG_LDO5_CONT:214 case DA9055_REG_LDO6_CONT:215 return true;216 default:217 return false;218 }219}220 221static const struct regmap_irq da9055_irqs[] = {222 [DA9055_IRQ_NONKEY] = {223 .reg_offset = 0,224 .mask = DA9055_IRQ_NONKEY_MASK,225 },226 [DA9055_IRQ_ALARM] = {227 .reg_offset = 0,228 .mask = DA9055_IRQ_ALM_MASK,229 },230 [DA9055_IRQ_TICK] = {231 .reg_offset = 0,232 .mask = DA9055_IRQ_TICK_MASK,233 },234 [DA9055_IRQ_HWMON] = {235 .reg_offset = 0,236 .mask = DA9055_IRQ_ADC_MASK,237 },238 [DA9055_IRQ_REGULATOR] = {239 .reg_offset = 1,240 .mask = DA9055_IRQ_BUCK_ILIM_MASK,241 },242};243 244const struct regmap_config da9055_regmap_config = {245 .reg_bits = 8,246 .val_bits = 8,247 248 .cache_type = REGCACHE_MAPLE,249 250 .max_register = DA9055_MAX_REGISTER_CNT,251 .readable_reg = da9055_register_readable,252 .writeable_reg = da9055_register_writeable,253 .volatile_reg = da9055_register_volatile,254};255EXPORT_SYMBOL_GPL(da9055_regmap_config);256 257static const struct resource da9055_onkey_resource =258 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_NONKEY, "ONKEY");259 260static const struct resource da9055_rtc_resource[] = {261 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_ALARM, "ALM"),262 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_TICK, "TICK"),263};264 265static const struct resource da9055_hwmon_resource =266 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_HWMON, "HWMON");267 268static const struct resource da9055_ld05_6_resource =269 DEFINE_RES_IRQ_NAMED(DA9055_IRQ_REGULATOR, "REGULATOR");270 271static const struct mfd_cell da9055_devs[] = {272 {273 .of_compatible = "dlg,da9055-gpio",274 .name = "da9055-gpio",275 },276 {277 .of_compatible = "dlg,da9055-regulator",278 .name = "da9055-regulator",279 .id = 1,280 },281 {282 .of_compatible = "dlg,da9055-regulator",283 .name = "da9055-regulator",284 .id = 2,285 },286 {287 .of_compatible = "dlg,da9055-regulator",288 .name = "da9055-regulator",289 .id = 3,290 },291 {292 .of_compatible = "dlg,da9055-regulator",293 .name = "da9055-regulator",294 .id = 4,295 },296 {297 .of_compatible = "dlg,da9055-regulator",298 .name = "da9055-regulator",299 .id = 5,300 },301 {302 .of_compatible = "dlg,da9055-regulator",303 .name = "da9055-regulator",304 .id = 6,305 },306 {307 .of_compatible = "dlg,da9055-regulator",308 .name = "da9055-regulator",309 .id = 7,310 .resources = &da9055_ld05_6_resource,311 .num_resources = 1,312 },313 {314 .of_compatible = "dlg,da9055-regulator",315 .name = "da9055-regulator",316 .resources = &da9055_ld05_6_resource,317 .num_resources = 1,318 .id = 8,319 },320 {321 .of_compatible = "dlg,da9055-onkey",322 .name = "da9055-onkey",323 .resources = &da9055_onkey_resource,324 .num_resources = 1,325 },326 {327 .of_compatible = "dlg,da9055-rtc",328 .name = "da9055-rtc",329 .resources = da9055_rtc_resource,330 .num_resources = ARRAY_SIZE(da9055_rtc_resource),331 },332 {333 .of_compatible = "dlg,da9055-hwmon",334 .name = "da9055-hwmon",335 .resources = &da9055_hwmon_resource,336 .num_resources = 1,337 },338 {339 .of_compatible = "dlg,da9055-watchdog",340 .name = "da9055-watchdog",341 },342};343 344static const struct regmap_irq_chip da9055_regmap_irq_chip = {345 .name = "da9055_irq",346 .status_base = DA9055_REG_EVENT_A,347 .mask_base = DA9055_REG_IRQ_MASK_A,348 .ack_base = DA9055_REG_EVENT_A,349 .num_regs = 3,350 .irqs = da9055_irqs,351 .num_irqs = ARRAY_SIZE(da9055_irqs),352};353 354int da9055_device_init(struct da9055 *da9055)355{356 struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);357 int ret;358 uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};359 360 if (pdata && pdata->init != NULL)361 pdata->init(da9055);362 363 if (!pdata || !pdata->irq_base)364 da9055->irq_base = -1;365 else366 da9055->irq_base = pdata->irq_base;367 368 ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);369 if (ret < 0)370 return ret;371 372 ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,373 IRQF_TRIGGER_LOW | IRQF_ONESHOT,374 da9055->irq_base, &da9055_regmap_irq_chip,375 &da9055->irq_data);376 if (ret < 0)377 return ret;378 379 da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);380 381 ret = mfd_add_devices(da9055->dev, -1,382 da9055_devs, ARRAY_SIZE(da9055_devs),383 NULL, da9055->irq_base, NULL);384 if (ret)385 goto err;386 387 return 0;388 389err:390 mfd_remove_devices(da9055->dev);391 return ret;392}393 394void da9055_device_exit(struct da9055 *da9055)395{396 regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);397 mfd_remove_devices(da9055->dev);398}399 400MODULE_DESCRIPTION("Core support for the DA9055 PMIC");401MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");402