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 39static 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 48static 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 57static 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 82static 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 212static 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 221static 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 248static 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 265static 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 regmap_reg_range(AS3722_FUSE7_REG, AS3722_FUSE7_REG), 281}; 282 283static const struct regmap_access_table as3722_readable_table = { 284 .yes_ranges = as3722_readable_ranges, 285 .n_yes_ranges = ARRAY_SIZE(as3722_readable_ranges), 286}; 287 288static const struct regmap_range as3722_writable_ranges[] = { 289 regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG), 290 regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG), 291 regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_GPIO_SIGNAL_OUT_REG), 292 regmap_reg_range(AS3722_REG_SEQU_MOD1_REG, AS3722_REG_SEQU_MOD3_REG), 293 regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG), 294 regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG), 295 regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG, 296 AS3722_BATTERY_VOLTAGE_MONITOR2_REG), 297 regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG), 298 regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG), 299 regmap_reg_range(AS3722_INTERRUPT_MASK1_REG, AS3722_TEMP_STATUS_REG), 300 regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC1_CONTROL_REG), 301 regmap_reg_range(AS3722_ADC1_THRESHOLD_HI_MSB_REG, 302 AS3722_ADC_CONFIGURATION_REG), 303 regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG), 304}; 305 306static const struct regmap_access_table as3722_writable_table = { 307 .yes_ranges = as3722_writable_ranges, 308 .n_yes_ranges = ARRAY_SIZE(as3722_writable_ranges), 309}; 310 311static const struct regmap_range as3722_cacheable_ranges[] = { 312 regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_LDO11_VOLTAGE_REG), 313 regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_LDOCONTROL1_REG), 314}; 315 316static const struct regmap_access_table as3722_volatile_table = { 317 .no_ranges = as3722_cacheable_ranges, 318 .n_no_ranges = ARRAY_SIZE(as3722_cacheable_ranges), 319}; 320 321static const struct regmap_config as3722_regmap_config = { 322 .reg_bits = 8, 323 .val_bits = 8, 324 .max_register = AS3722_MAX_REGISTER, 325 .cache_type = REGCACHE_RBTREE, 326 .rd_table = &as3722_readable_table, 327 .wr_table = &as3722_writable_table, 328 .volatile_table = &as3722_volatile_table, 329}; 330 331static int as3722_i2c_of_probe(struct i2c_client *i2c, 332 struct as3722 *as3722) 333{ 334 struct device_node *np = i2c->dev.of_node; 335 struct irq_data *irq_data; 336 337 if (!np) { 338 dev_err(&i2c->dev, "Device Tree not found\n"); 339 return -EINVAL; 340 } 341 342 irq_data = irq_get_irq_data(i2c->irq); 343 if (!irq_data) { 344 dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq); 345 return -EINVAL; 346 } 347 348 as3722->en_intern_int_pullup = of_property_read_bool(np, 349 "ams,enable-internal-int-pullup"); 350 as3722->en_intern_i2c_pullup = of_property_read_bool(np, 351 "ams,enable-internal-i2c-pullup"); 352 as3722->irq_flags = irqd_get_trigger_type(irq_data); 353 dev_dbg(&i2c->dev, "IRQ flags are 0x%08lx\n", as3722->irq_flags); 354 return 0; 355} 356 357static int as3722_i2c_probe(struct i2c_client *i2c, 358 const struct i2c_device_id *id) 359{ 360 struct as3722 *as3722; 361 unsigned long irq_flags; 362 int ret; 363 364 as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL); 365 if (!as3722) 366 return -ENOMEM; 367 368 as3722->dev = &i2c->dev; 369 as3722->chip_irq = i2c->irq; 370 i2c_set_clientdata(i2c, as3722); 371 372 ret = as3722_i2c_of_probe(i2c, as3722); 373 if (ret < 0) 374 return ret; 375 376 as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config); 377 if (IS_ERR(as3722->regmap)) { 378 ret = PTR_ERR(as3722->regmap); 379 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 380 return ret; 381 } 382 383 ret = as3722_check_device_id(as3722); 384 if (ret < 0) 385 return ret; 386 387 irq_flags = as3722->irq_flags | IRQF_ONESHOT; 388 ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq, 389 irq_flags, -1, &as3722_irq_chip, 390 &as3722->irq_data); 391 if (ret < 0) { 392 dev_err(as3722->dev, "Failed to add regmap irq: %d\n", ret); 393 return ret; 394 } 395 396 ret = as3722_configure_pullups(as3722); 397 if (ret < 0) 398 goto scrub; 399 400 ret = mfd_add_devices(&i2c->dev, -1, as3722_devs, 401 ARRAY_SIZE(as3722_devs), NULL, 0, 402 regmap_irq_get_domain(as3722->irq_data)); 403 if (ret) { 404 dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret); 405 goto scrub; 406 } 407 408 dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n"); 409 return 0; 410 411scrub: 412 regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data); 413 return ret; 414} 415 416static int as3722_i2c_remove(struct i2c_client *i2c) 417{ 418 struct as3722 *as3722 = i2c_get_clientdata(i2c); 419 420 mfd_remove_devices(as3722->dev); 421 regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data); 422 return 0; 423} 424 425static const struct of_device_id as3722_of_match[] = { 426 { .compatible = "ams,as3722", }, 427 {}, 428}; 429MODULE_DEVICE_TABLE(of, as3722_of_match); 430 431static const struct i2c_device_id as3722_i2c_id[] = { 432 { "as3722", 0 }, 433 {}, 434}; 435MODULE_DEVICE_TABLE(i2c, as3722_i2c_id); 436 437static struct i2c_driver as3722_i2c_driver = { 438 .driver = { 439 .name = "as3722", 440 .owner = THIS_MODULE, 441 .of_match_table = as3722_of_match, 442 }, 443 .probe = as3722_i2c_probe, 444 .remove = as3722_i2c_remove, 445 .id_table = as3722_i2c_id, 446}; 447 448module_i2c_driver(as3722_i2c_driver); 449 450MODULE_DESCRIPTION("I2C support for AS3722 PMICs"); 451MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); 452MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 453MODULE_LICENSE("GPL"); 454