root/drivers/mfd/as3722.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. as3722_check_device_id
  2. as3722_configure_pullups
  3. as3722_i2c_of_probe
  4. as3722_i2c_probe
  5. as3722_i2c_suspend
  6. as3722_i2c_resume

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

/* [<][>][^][v][top][bottom][index][help] */