1 /* 2 * Core driver for ams AS3722 PMICs 3 * 4 * Copyright (C) 2013 AMS AG 5 * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. 6 * 7 * Author: Florian Lobmaier <florian.lobmaier@ams.com> 8 * Author: Laxman Dewangan <ldewangan@nvidia.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25 #include <linux/err.h> 26 #include <linux/i2c.h> 27 #include <linux/interrupt.h> 28 #include <linux/irq.h> 29 #include <linux/kernel.h> 30 #include <linux/module.h> 31 #include <linux/mfd/core.h> 32 #include <linux/mfd/as3722.h> 33 #include <linux/of.h> 34 #include <linux/regmap.h> 35 #include <linux/slab.h> 36 37 #define AS3722_DEVICE_ID 0x0C 38 39 static const struct resource as3722_rtc_resource[] = { 40 { 41 .name = "as3722-rtc-alarm", 42 .start = AS3722_IRQ_RTC_ALARM, 43 .end = AS3722_IRQ_RTC_ALARM, 44 .flags = IORESOURCE_IRQ, 45 }, 46 }; 47 48 static const struct resource as3722_adc_resource[] = { 49 { 50 .name = "as3722-adc", 51 .start = AS3722_IRQ_ADC, 52 .end = AS3722_IRQ_ADC, 53 .flags = IORESOURCE_IRQ, 54 }, 55 }; 56 57 static const struct mfd_cell as3722_devs[] = { 58 { 59 .name = "as3722-pinctrl", 60 }, 61 { 62 .name = "as3722-regulator", 63 }, 64 { 65 .name = "as3722-rtc", 66 .num_resources = ARRAY_SIZE(as3722_rtc_resource), 67 .resources = as3722_rtc_resource, 68 }, 69 { 70 .name = "as3722-adc", 71 .num_resources = ARRAY_SIZE(as3722_adc_resource), 72 .resources = as3722_adc_resource, 73 }, 74 { 75 .name = "as3722-power-off", 76 }, 77 { 78 .name = "as3722-wdt", 79 }, 80 }; 81 82 static const struct regmap_irq as3722_irqs[] = { 83 /* INT1 IRQs */ 84 [AS3722_IRQ_LID] = { 85 .mask = AS3722_INTERRUPT_MASK1_LID, 86 }, 87 [AS3722_IRQ_ACOK] = { 88 .mask = AS3722_INTERRUPT_MASK1_ACOK, 89 }, 90 [AS3722_IRQ_ENABLE1] = { 91 .mask = AS3722_INTERRUPT_MASK1_ENABLE1, 92 }, 93 [AS3722_IRQ_OCCUR_ALARM_SD0] = { 94 .mask = AS3722_INTERRUPT_MASK1_OCURR_ALARM_SD0, 95 }, 96 [AS3722_IRQ_ONKEY_LONG_PRESS] = { 97 .mask = AS3722_INTERRUPT_MASK1_ONKEY_LONG, 98 }, 99 [AS3722_IRQ_ONKEY] = { 100 .mask = AS3722_INTERRUPT_MASK1_ONKEY, 101 }, 102 [AS3722_IRQ_OVTMP] = { 103 .mask = AS3722_INTERRUPT_MASK1_OVTMP, 104 }, 105 [AS3722_IRQ_LOWBAT] = { 106 .mask = AS3722_INTERRUPT_MASK1_LOWBAT, 107 }, 108 109 /* INT2 IRQs */ 110 [AS3722_IRQ_SD0_LV] = { 111 .mask = AS3722_INTERRUPT_MASK2_SD0_LV, 112 .reg_offset = 1, 113 }, 114 [AS3722_IRQ_SD1_LV] = { 115 .mask = AS3722_INTERRUPT_MASK2_SD1_LV, 116 .reg_offset = 1, 117 }, 118 [AS3722_IRQ_SD2_LV] = { 119 .mask = AS3722_INTERRUPT_MASK2_SD2345_LV, 120 .reg_offset = 1, 121 }, 122 [AS3722_IRQ_PWM1_OV_PROT] = { 123 .mask = AS3722_INTERRUPT_MASK2_PWM1_OV_PROT, 124 .reg_offset = 1, 125 }, 126 [AS3722_IRQ_PWM2_OV_PROT] = { 127 .mask = AS3722_INTERRUPT_MASK2_PWM2_OV_PROT, 128 .reg_offset = 1, 129 }, 130 [AS3722_IRQ_ENABLE2] = { 131 .mask = AS3722_INTERRUPT_MASK2_ENABLE2, 132 .reg_offset = 1, 133 }, 134 [AS3722_IRQ_SD6_LV] = { 135 .mask = AS3722_INTERRUPT_MASK2_SD6_LV, 136 .reg_offset = 1, 137 }, 138 [AS3722_IRQ_RTC_REP] = { 139 .mask = AS3722_INTERRUPT_MASK2_RTC_REP, 140 .reg_offset = 1, 141 }, 142 143 /* INT3 IRQs */ 144 [AS3722_IRQ_RTC_ALARM] = { 145 .mask = AS3722_INTERRUPT_MASK3_RTC_ALARM, 146 .reg_offset = 2, 147 }, 148 [AS3722_IRQ_GPIO1] = { 149 .mask = AS3722_INTERRUPT_MASK3_GPIO1, 150 .reg_offset = 2, 151 }, 152 [AS3722_IRQ_GPIO2] = { 153 .mask = AS3722_INTERRUPT_MASK3_GPIO2, 154 .reg_offset = 2, 155 }, 156 [AS3722_IRQ_GPIO3] = { 157 .mask = AS3722_INTERRUPT_MASK3_GPIO3, 158 .reg_offset = 2, 159 }, 160 [AS3722_IRQ_GPIO4] = { 161 .mask = AS3722_INTERRUPT_MASK3_GPIO4, 162 .reg_offset = 2, 163 }, 164 [AS3722_IRQ_GPIO5] = { 165 .mask = AS3722_INTERRUPT_MASK3_GPIO5, 166 .reg_offset = 2, 167 }, 168 [AS3722_IRQ_WATCHDOG] = { 169 .mask = AS3722_INTERRUPT_MASK3_WATCHDOG, 170 .reg_offset = 2, 171 }, 172 [AS3722_IRQ_ENABLE3] = { 173 .mask = AS3722_INTERRUPT_MASK3_ENABLE3, 174 .reg_offset = 2, 175 }, 176 177 /* INT4 IRQs */ 178 [AS3722_IRQ_TEMP_SD0_SHUTDOWN] = { 179 .mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_SHUTDOWN, 180 .reg_offset = 3, 181 }, 182 [AS3722_IRQ_TEMP_SD1_SHUTDOWN] = { 183 .mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_SHUTDOWN, 184 .reg_offset = 3, 185 }, 186 [AS3722_IRQ_TEMP_SD2_SHUTDOWN] = { 187 .mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_SHUTDOWN, 188 .reg_offset = 3, 189 }, 190 [AS3722_IRQ_TEMP_SD0_ALARM] = { 191 .mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_ALARM, 192 .reg_offset = 3, 193 }, 194 [AS3722_IRQ_TEMP_SD1_ALARM] = { 195 .mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_ALARM, 196 .reg_offset = 3, 197 }, 198 [AS3722_IRQ_TEMP_SD6_ALARM] = { 199 .mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_ALARM, 200 .reg_offset = 3, 201 }, 202 [AS3722_IRQ_OCCUR_ALARM_SD6] = { 203 .mask = AS3722_INTERRUPT_MASK4_OCCUR_ALARM_SD6, 204 .reg_offset = 3, 205 }, 206 [AS3722_IRQ_ADC] = { 207 .mask = AS3722_INTERRUPT_MASK4_ADC, 208 .reg_offset = 3, 209 }, 210 }; 211 212 static const struct regmap_irq_chip as3722_irq_chip = { 213 .name = "as3722", 214 .irqs = as3722_irqs, 215 .num_irqs = ARRAY_SIZE(as3722_irqs), 216 .num_regs = 4, 217 .status_base = AS3722_INTERRUPT_STATUS1_REG, 218 .mask_base = AS3722_INTERRUPT_MASK1_REG, 219 }; 220 221 static int as3722_check_device_id(struct as3722 *as3722) 222 { 223 u32 val; 224 int ret; 225 226 /* Check that this is actually a AS3722 */ 227 ret = as3722_read(as3722, AS3722_ASIC_ID1_REG, &val); 228 if (ret < 0) { 229 dev_err(as3722->dev, "ASIC_ID1 read failed: %d\n", ret); 230 return ret; 231 } 232 233 if (val != AS3722_DEVICE_ID) { 234 dev_err(as3722->dev, "Device is not AS3722, ID is 0x%x\n", val); 235 return -ENODEV; 236 } 237 238 ret = as3722_read(as3722, AS3722_ASIC_ID2_REG, &val); 239 if (ret < 0) { 240 dev_err(as3722->dev, "ASIC_ID2 read failed: %d\n", ret); 241 return ret; 242 } 243 244 dev_info(as3722->dev, "AS3722 with revision 0x%x found\n", val); 245 return 0; 246 } 247 248 static int as3722_configure_pullups(struct as3722 *as3722) 249 { 250 int ret; 251 u32 val = 0; 252 253 if (as3722->en_intern_int_pullup) 254 val |= AS3722_INT_PULL_UP; 255 if (as3722->en_intern_i2c_pullup) 256 val |= AS3722_I2C_PULL_UP; 257 258 ret = as3722_update_bits(as3722, AS3722_IOVOLTAGE_REG, 259 AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, val); 260 if (ret < 0) 261 dev_err(as3722->dev, "IOVOLTAGE_REG update failed: %d\n", ret); 262 return ret; 263 } 264 265 static const struct regmap_range as3722_readable_ranges[] = { 266 regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG), 267 regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG), 268 regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_REG_SEQU_MOD3_REG), 269 regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG), 270 regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG), 271 regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG, 272 AS3722_BATTERY_VOLTAGE_MONITOR2_REG), 273 regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG), 274 regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG), 275 regmap_reg_range(AS3722_RTC_ACCESS_REG, AS3722_RTC_ACCESS_REG), 276 regmap_reg_range(AS3722_RTC_STATUS_REG, AS3722_TEMP_STATUS_REG), 277 regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC_CONFIGURATION_REG), 278 regmap_reg_range(AS3722_ASIC_ID1_REG, AS3722_ASIC_ID2_REG), 279 regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG), 280 }; 281 282 static const struct regmap_access_table as3722_readable_table = { 283 .yes_ranges = as3722_readable_ranges, 284 .n_yes_ranges = ARRAY_SIZE(as3722_readable_ranges), 285 }; 286 287 static const struct regmap_range as3722_writable_ranges[] = { 288 regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG), 289 regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG), 290 regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_GPIO_SIGNAL_OUT_REG), 291 regmap_reg_range(AS3722_REG_SEQU_MOD1_REG, AS3722_REG_SEQU_MOD3_REG), 292 regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG), 293 regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG), 294 regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG, 295 AS3722_BATTERY_VOLTAGE_MONITOR2_REG), 296 regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG), 297 regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG), 298 regmap_reg_range(AS3722_INTERRUPT_MASK1_REG, AS3722_TEMP_STATUS_REG), 299 regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC1_CONTROL_REG), 300 regmap_reg_range(AS3722_ADC1_THRESHOLD_HI_MSB_REG, 301 AS3722_ADC_CONFIGURATION_REG), 302 regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG), 303 }; 304 305 static const struct regmap_access_table as3722_writable_table = { 306 .yes_ranges = as3722_writable_ranges, 307 .n_yes_ranges = ARRAY_SIZE(as3722_writable_ranges), 308 }; 309 310 static const struct regmap_range as3722_cacheable_ranges[] = { 311 regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_LDO11_VOLTAGE_REG), 312 regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_LDOCONTROL1_REG), 313 }; 314 315 static const struct regmap_access_table as3722_volatile_table = { 316 .no_ranges = as3722_cacheable_ranges, 317 .n_no_ranges = ARRAY_SIZE(as3722_cacheable_ranges), 318 }; 319 320 static const struct regmap_config as3722_regmap_config = { 321 .reg_bits = 8, 322 .val_bits = 8, 323 .max_register = AS3722_MAX_REGISTER, 324 .cache_type = REGCACHE_RBTREE, 325 .rd_table = &as3722_readable_table, 326 .wr_table = &as3722_writable_table, 327 .volatile_table = &as3722_volatile_table, 328 }; 329 330 static int as3722_i2c_of_probe(struct i2c_client *i2c, 331 struct as3722 *as3722) 332 { 333 struct device_node *np = i2c->dev.of_node; 334 struct irq_data *irq_data; 335 336 if (!np) { 337 dev_err(&i2c->dev, "Device Tree not found\n"); 338 return -EINVAL; 339 } 340 341 irq_data = irq_get_irq_data(i2c->irq); 342 if (!irq_data) { 343 dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq); 344 return -EINVAL; 345 } 346 347 as3722->en_intern_int_pullup = of_property_read_bool(np, 348 "ams,enable-internal-int-pullup"); 349 as3722->en_intern_i2c_pullup = of_property_read_bool(np, 350 "ams,enable-internal-i2c-pullup"); 351 as3722->irq_flags = irqd_get_trigger_type(irq_data); 352 dev_dbg(&i2c->dev, "IRQ flags are 0x%08lx\n", as3722->irq_flags); 353 return 0; 354 } 355 356 static int as3722_i2c_probe(struct i2c_client *i2c, 357 const struct i2c_device_id *id) 358 { 359 struct as3722 *as3722; 360 unsigned long irq_flags; 361 int ret; 362 363 as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL); 364 if (!as3722) 365 return -ENOMEM; 366 367 as3722->dev = &i2c->dev; 368 as3722->chip_irq = i2c->irq; 369 i2c_set_clientdata(i2c, as3722); 370 371 ret = as3722_i2c_of_probe(i2c, as3722); 372 if (ret < 0) 373 return ret; 374 375 as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config); 376 if (IS_ERR(as3722->regmap)) { 377 ret = PTR_ERR(as3722->regmap); 378 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 379 return ret; 380 } 381 382 ret = as3722_check_device_id(as3722); 383 if (ret < 0) 384 return ret; 385 386 irq_flags = as3722->irq_flags | IRQF_ONESHOT; 387 ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq, 388 irq_flags, -1, &as3722_irq_chip, 389 &as3722->irq_data); 390 if (ret < 0) { 391 dev_err(as3722->dev, "Failed to add regmap irq: %d\n", ret); 392 return ret; 393 } 394 395 ret = as3722_configure_pullups(as3722); 396 if (ret < 0) 397 goto scrub; 398 399 ret = mfd_add_devices(&i2c->dev, -1, as3722_devs, 400 ARRAY_SIZE(as3722_devs), NULL, 0, 401 regmap_irq_get_domain(as3722->irq_data)); 402 if (ret) { 403 dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret); 404 goto scrub; 405 } 406 407 dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n"); 408 return 0; 409 410 scrub: 411 regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data); 412 return ret; 413 } 414 415 static int as3722_i2c_remove(struct i2c_client *i2c) 416 { 417 struct as3722 *as3722 = i2c_get_clientdata(i2c); 418 419 mfd_remove_devices(as3722->dev); 420 regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data); 421 return 0; 422 } 423 424 static const struct of_device_id as3722_of_match[] = { 425 { .compatible = "ams,as3722", }, 426 {}, 427 }; 428 MODULE_DEVICE_TABLE(of, as3722_of_match); 429 430 static const struct i2c_device_id as3722_i2c_id[] = { 431 { "as3722", 0 }, 432 {}, 433 }; 434 MODULE_DEVICE_TABLE(i2c, as3722_i2c_id); 435 436 static struct i2c_driver as3722_i2c_driver = { 437 .driver = { 438 .name = "as3722", 439 .owner = THIS_MODULE, 440 .of_match_table = as3722_of_match, 441 }, 442 .probe = as3722_i2c_probe, 443 .remove = as3722_i2c_remove, 444 .id_table = as3722_i2c_id, 445 }; 446 447 module_i2c_driver(as3722_i2c_driver); 448 449 MODULE_DESCRIPTION("I2C support for AS3722 PMICs"); 450 MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); 451 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 452 MODULE_LICENSE("GPL"); 453