| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Maxim MAX77620 MFD Driver | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | 
|  | 5 | * | 
|  | 6 | * Author: | 
|  | 7 | *	Laxman Dewangan <ldewangan@nvidia.com> | 
|  | 8 | *	Chaitanya Bandi <bandik@nvidia.com> | 
|  | 9 | *	Mallikarjun Kasoju <mkasoju@nvidia.com> | 
|  | 10 | * | 
|  | 11 | * This program is free software; you can redistribute it and/or modify | 
|  | 12 | * it under the terms of the GNU General Public License version 2 as | 
|  | 13 | * published by the Free Software Foundation. | 
|  | 14 | */ | 
|  | 15 |  | 
|  | 16 | /****************** Teminology used in driver ******************** | 
|  | 17 | * Here are some terminology used from datasheet for quick reference: | 
|  | 18 | * Flexible Power Sequence (FPS): | 
|  | 19 | * The Flexible Power Sequencer (FPS) allows each regulator to power up under | 
|  | 20 | * hardware or software control. Additionally, each regulator can power on | 
|  | 21 | * independently or among a group of other regulators with an adjustable | 
|  | 22 | * power-up and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can | 
|  | 23 | * be programmed to be part of a sequence allowing external regulators to be | 
|  | 24 | * sequenced along with internal regulators. 32KHz clock can be programmed to | 
|  | 25 | * be part of a sequence. | 
|  | 26 | * There is 3 FPS confguration registers and all resources are configured to | 
|  | 27 | * any of these FPS or no FPS. | 
|  | 28 | */ | 
|  | 29 |  | 
|  | 30 | #include <linux/i2c.h> | 
|  | 31 | #include <linux/interrupt.h> | 
|  | 32 | #include <linux/mfd/core.h> | 
|  | 33 | #include <linux/mfd/max77620.h> | 
|  | 34 | #include <linux/init.h> | 
|  | 35 | #include <linux/of.h> | 
|  | 36 | #include <linux/of_device.h> | 
|  | 37 | #include <linux/regmap.h> | 
|  | 38 | #include <linux/slab.h> | 
|  | 39 |  | 
|  | 40 | static const struct resource gpio_resources[] = { | 
|  | 41 | DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), | 
|  | 42 | }; | 
|  | 43 |  | 
|  | 44 | static const struct resource power_resources[] = { | 
|  | 45 | DEFINE_RES_IRQ(MAX77620_IRQ_LBT_MBATLOW), | 
|  | 46 | }; | 
|  | 47 |  | 
|  | 48 | static const struct resource rtc_resources[] = { | 
|  | 49 | DEFINE_RES_IRQ(MAX77620_IRQ_TOP_RTC), | 
|  | 50 | }; | 
|  | 51 |  | 
|  | 52 | static const struct resource thermal_resources[] = { | 
|  | 53 | DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM1), | 
|  | 54 | DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM2), | 
|  | 55 | }; | 
|  | 56 |  | 
|  | 57 | static const struct regmap_irq max77620_top_irqs[] = { | 
|  | 58 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GLBL, 0, MAX77620_IRQ_TOP_GLBL_MASK), | 
|  | 59 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_SD, 0, MAX77620_IRQ_TOP_SD_MASK), | 
|  | 60 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_LDO, 0, MAX77620_IRQ_TOP_LDO_MASK), | 
|  | 61 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GPIO, 0, MAX77620_IRQ_TOP_GPIO_MASK), | 
|  | 62 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_RTC, 0, MAX77620_IRQ_TOP_RTC_MASK), | 
|  | 63 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_32K, 0, MAX77620_IRQ_TOP_32K_MASK), | 
|  | 64 | REGMAP_IRQ_REG(MAX77620_IRQ_TOP_ONOFF, 0, MAX77620_IRQ_TOP_ONOFF_MASK), | 
|  | 65 | REGMAP_IRQ_REG(MAX77620_IRQ_LBT_MBATLOW, 1, MAX77620_IRQ_LBM_MASK), | 
|  | 66 | REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM1, 1, MAX77620_IRQ_TJALRM1_MASK), | 
|  | 67 | REGMAP_IRQ_REG(MAX77620_IRQ_LBT_TJALRM2, 1, MAX77620_IRQ_TJALRM2_MASK), | 
|  | 68 | }; | 
|  | 69 |  | 
|  | 70 | static const struct mfd_cell max77620_children[] = { | 
|  | 71 | { .name = "max77620-pinctrl", }, | 
|  | 72 | { .name = "max77620-clock", }, | 
|  | 73 | { .name = "max77620-pmic", }, | 
|  | 74 | { .name = "max77620-watchdog", }, | 
|  | 75 | { | 
|  | 76 | .name = "max77620-gpio", | 
|  | 77 | .resources = gpio_resources, | 
|  | 78 | .num_resources = ARRAY_SIZE(gpio_resources), | 
|  | 79 | }, { | 
|  | 80 | .name = "max77620-rtc", | 
|  | 81 | .resources = rtc_resources, | 
|  | 82 | .num_resources = ARRAY_SIZE(rtc_resources), | 
|  | 83 | }, { | 
|  | 84 | .name = "max77620-power", | 
|  | 85 | .resources = power_resources, | 
|  | 86 | .num_resources = ARRAY_SIZE(power_resources), | 
|  | 87 | }, { | 
|  | 88 | .name = "max77620-thermal", | 
|  | 89 | .resources = thermal_resources, | 
|  | 90 | .num_resources = ARRAY_SIZE(thermal_resources), | 
|  | 91 | }, | 
|  | 92 | }; | 
|  | 93 |  | 
|  | 94 | static const struct mfd_cell max20024_children[] = { | 
|  | 95 | { .name = "max20024-pinctrl", }, | 
|  | 96 | { .name = "max77620-clock", }, | 
|  | 97 | { .name = "max20024-pmic", }, | 
|  | 98 | { .name = "max77620-watchdog", }, | 
|  | 99 | { | 
|  | 100 | .name = "max77620-gpio", | 
|  | 101 | .resources = gpio_resources, | 
|  | 102 | .num_resources = ARRAY_SIZE(gpio_resources), | 
|  | 103 | }, { | 
|  | 104 | .name = "max77620-rtc", | 
|  | 105 | .resources = rtc_resources, | 
|  | 106 | .num_resources = ARRAY_SIZE(rtc_resources), | 
|  | 107 | }, { | 
|  | 108 | .name = "max20024-power", | 
|  | 109 | .resources = power_resources, | 
|  | 110 | .num_resources = ARRAY_SIZE(power_resources), | 
|  | 111 | }, | 
|  | 112 | }; | 
|  | 113 |  | 
|  | 114 | static const struct regmap_range max77620_readable_ranges[] = { | 
|  | 115 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), | 
|  | 116 | }; | 
|  | 117 |  | 
|  | 118 | static const struct regmap_access_table max77620_readable_table = { | 
|  | 119 | .yes_ranges = max77620_readable_ranges, | 
|  | 120 | .n_yes_ranges = ARRAY_SIZE(max77620_readable_ranges), | 
|  | 121 | }; | 
|  | 122 |  | 
|  | 123 | static const struct regmap_range max20024_readable_ranges[] = { | 
|  | 124 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), | 
|  | 125 | regmap_reg_range(MAX20024_REG_MAX_ADD, MAX20024_REG_MAX_ADD), | 
|  | 126 | }; | 
|  | 127 |  | 
|  | 128 | static const struct regmap_access_table max20024_readable_table = { | 
|  | 129 | .yes_ranges = max20024_readable_ranges, | 
|  | 130 | .n_yes_ranges = ARRAY_SIZE(max20024_readable_ranges), | 
|  | 131 | }; | 
|  | 132 |  | 
|  | 133 | static const struct regmap_range max77620_writable_ranges[] = { | 
|  | 134 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), | 
|  | 135 | }; | 
|  | 136 |  | 
|  | 137 | static const struct regmap_access_table max77620_writable_table = { | 
|  | 138 | .yes_ranges = max77620_writable_ranges, | 
|  | 139 | .n_yes_ranges = ARRAY_SIZE(max77620_writable_ranges), | 
|  | 140 | }; | 
|  | 141 |  | 
|  | 142 | static const struct regmap_range max77620_cacheable_ranges[] = { | 
|  | 143 | regmap_reg_range(MAX77620_REG_SD0_CFG, MAX77620_REG_LDO_CFG3), | 
|  | 144 | regmap_reg_range(MAX77620_REG_FPS_CFG0, MAX77620_REG_FPS_SD3), | 
|  | 145 | }; | 
|  | 146 |  | 
|  | 147 | static const struct regmap_access_table max77620_volatile_table = { | 
|  | 148 | .no_ranges = max77620_cacheable_ranges, | 
|  | 149 | .n_no_ranges = ARRAY_SIZE(max77620_cacheable_ranges), | 
|  | 150 | }; | 
|  | 151 |  | 
|  | 152 | static const struct regmap_config max77620_regmap_config = { | 
|  | 153 | .name = "power-slave", | 
|  | 154 | .reg_bits = 8, | 
|  | 155 | .val_bits = 8, | 
|  | 156 | .max_register = MAX77620_REG_DVSSD4 + 1, | 
|  | 157 | .cache_type = REGCACHE_RBTREE, | 
|  | 158 | .rd_table = &max77620_readable_table, | 
|  | 159 | .wr_table = &max77620_writable_table, | 
|  | 160 | .volatile_table = &max77620_volatile_table, | 
|  | 161 | }; | 
|  | 162 |  | 
|  | 163 | static const struct regmap_config max20024_regmap_config = { | 
|  | 164 | .name = "power-slave", | 
|  | 165 | .reg_bits = 8, | 
|  | 166 | .val_bits = 8, | 
|  | 167 | .max_register = MAX20024_REG_MAX_ADD + 1, | 
|  | 168 | .cache_type = REGCACHE_RBTREE, | 
|  | 169 | .rd_table = &max20024_readable_table, | 
|  | 170 | .wr_table = &max77620_writable_table, | 
|  | 171 | .volatile_table = &max77620_volatile_table, | 
|  | 172 | }; | 
|  | 173 |  | 
|  | 174 | /* | 
|  | 175 | * MAX77620 and MAX20024 has the following steps of the interrupt handling | 
|  | 176 | * for TOP interrupts: | 
|  | 177 | * 1. When interrupt occurs from PMIC, mask the PMIC interrupt by setting GLBLM. | 
|  | 178 | * 2. Read IRQTOP and service the interrupt. | 
|  | 179 | * 3. Once all interrupts has been checked and serviced, the interrupt service | 
|  | 180 | *    routine un-masks the hardware interrupt line by clearing GLBLM. | 
|  | 181 | */ | 
|  | 182 | static int max77620_irq_global_mask(void *irq_drv_data) | 
|  | 183 | { | 
|  | 184 | struct max77620_chip *chip = irq_drv_data; | 
|  | 185 | int ret; | 
|  | 186 |  | 
|  | 187 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, | 
|  | 188 | MAX77620_GLBLM_MASK, MAX77620_GLBLM_MASK); | 
|  | 189 | if (ret < 0) | 
|  | 190 | dev_err(chip->dev, "Failed to set GLBLM: %d\n", ret); | 
|  | 191 |  | 
|  | 192 | return ret; | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | static int max77620_irq_global_unmask(void *irq_drv_data) | 
|  | 196 | { | 
|  | 197 | struct max77620_chip *chip = irq_drv_data; | 
|  | 198 | int ret; | 
|  | 199 |  | 
|  | 200 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_INTENLBT, | 
|  | 201 | MAX77620_GLBLM_MASK, 0); | 
|  | 202 | if (ret < 0) | 
|  | 203 | dev_err(chip->dev, "Failed to reset GLBLM: %d\n", ret); | 
|  | 204 |  | 
|  | 205 | return ret; | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | static struct regmap_irq_chip max77620_top_irq_chip = { | 
|  | 209 | .name = "max77620-top", | 
|  | 210 | .irqs = max77620_top_irqs, | 
|  | 211 | .num_irqs = ARRAY_SIZE(max77620_top_irqs), | 
|  | 212 | .num_regs = 2, | 
|  | 213 | .status_base = MAX77620_REG_IRQTOP, | 
|  | 214 | .mask_base = MAX77620_REG_IRQTOPM, | 
|  | 215 | .handle_pre_irq = max77620_irq_global_mask, | 
|  | 216 | .handle_post_irq = max77620_irq_global_unmask, | 
|  | 217 | }; | 
|  | 218 |  | 
|  | 219 | /* max77620_get_fps_period_reg_value:  Get FPS bit field value from | 
|  | 220 | *				       requested periods. | 
|  | 221 | * MAX77620 supports the FPS period of 40, 80, 160, 320, 540, 1280, 2560 | 
|  | 222 | * and 5120 microseconds. MAX20024 supports the FPS period of 20, 40, 80, | 
|  | 223 | * 160, 320, 540, 1280 and 2560 microseconds. | 
|  | 224 | * The FPS register has 3 bits field to set the FPS period as | 
|  | 225 | * bits		max77620		max20024 | 
|  | 226 | * 000		40			20 | 
|  | 227 | * 001		80			40 | 
|  | 228 | * ::: | 
|  | 229 | */ | 
|  | 230 | static int max77620_get_fps_period_reg_value(struct max77620_chip *chip, | 
|  | 231 | int tperiod) | 
|  | 232 | { | 
|  | 233 | int fps_min_period; | 
|  | 234 | int i; | 
|  | 235 |  | 
|  | 236 | switch (chip->chip_id) { | 
|  | 237 | case MAX20024: | 
|  | 238 | fps_min_period = MAX20024_FPS_PERIOD_MIN_US; | 
|  | 239 | break; | 
|  | 240 | case MAX77620: | 
|  | 241 | fps_min_period = MAX77620_FPS_PERIOD_MIN_US; | 
|  | 242 | break; | 
|  | 243 | default: | 
|  | 244 | return -EINVAL; | 
|  | 245 | } | 
|  | 246 |  | 
|  | 247 | for (i = 0; i < 7; i++) { | 
|  | 248 | if (fps_min_period >= tperiod) | 
|  | 249 | return i; | 
|  | 250 | fps_min_period *= 2; | 
|  | 251 | } | 
|  | 252 |  | 
|  | 253 | return i; | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | /* max77620_config_fps: Configure FPS configuration registers | 
|  | 257 | *			based on platform specific information. | 
|  | 258 | */ | 
|  | 259 | static int max77620_config_fps(struct max77620_chip *chip, | 
|  | 260 | struct device_node *fps_np) | 
|  | 261 | { | 
|  | 262 | struct device *dev = chip->dev; | 
|  | 263 | unsigned int mask = 0, config = 0; | 
|  | 264 | u32 fps_max_period; | 
|  | 265 | u32 param_val; | 
|  | 266 | int tperiod, fps_id; | 
|  | 267 | int ret; | 
|  | 268 | char fps_name[10]; | 
|  | 269 |  | 
|  | 270 | switch (chip->chip_id) { | 
|  | 271 | case MAX20024: | 
|  | 272 | fps_max_period = MAX20024_FPS_PERIOD_MAX_US; | 
|  | 273 | break; | 
|  | 274 | case MAX77620: | 
|  | 275 | fps_max_period = MAX77620_FPS_PERIOD_MAX_US; | 
|  | 276 | break; | 
|  | 277 | default: | 
|  | 278 | return -EINVAL; | 
|  | 279 | } | 
|  | 280 |  | 
|  | 281 | for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { | 
|  | 282 | sprintf(fps_name, "fps%d", fps_id); | 
|  | 283 | if (!strcmp(fps_np->name, fps_name)) | 
|  | 284 | break; | 
|  | 285 | } | 
|  | 286 |  | 
|  | 287 | if (fps_id == MAX77620_FPS_COUNT) { | 
|  | 288 | dev_err(dev, "FPS node name %s is not valid\n", fps_np->name); | 
|  | 289 | return -EINVAL; | 
|  | 290 | } | 
|  | 291 |  | 
|  | 292 | ret = of_property_read_u32(fps_np, "maxim,shutdown-fps-time-period-us", | 
|  | 293 | ¶m_val); | 
|  | 294 | if (!ret) { | 
|  | 295 | mask |= MAX77620_FPS_TIME_PERIOD_MASK; | 
|  | 296 | chip->shutdown_fps_period[fps_id] = min(param_val, | 
|  | 297 | fps_max_period); | 
|  | 298 | tperiod = max77620_get_fps_period_reg_value(chip, | 
|  | 299 | chip->shutdown_fps_period[fps_id]); | 
|  | 300 | config |= tperiod << MAX77620_FPS_TIME_PERIOD_SHIFT; | 
|  | 301 | } | 
|  | 302 |  | 
|  | 303 | ret = of_property_read_u32(fps_np, "maxim,suspend-fps-time-period-us", | 
|  | 304 | ¶m_val); | 
|  | 305 | if (!ret) | 
|  | 306 | chip->suspend_fps_period[fps_id] = min(param_val, | 
|  | 307 | fps_max_period); | 
|  | 308 |  | 
|  | 309 | ret = of_property_read_u32(fps_np, "maxim,fps-event-source", | 
|  | 310 | ¶m_val); | 
|  | 311 | if (!ret) { | 
|  | 312 | if (param_val > 2) { | 
|  | 313 | dev_err(dev, "FPS%d event-source invalid\n", fps_id); | 
|  | 314 | return -EINVAL; | 
|  | 315 | } | 
|  | 316 | mask |= MAX77620_FPS_EN_SRC_MASK; | 
|  | 317 | config |= param_val << MAX77620_FPS_EN_SRC_SHIFT; | 
|  | 318 | if (param_val == 2) { | 
|  | 319 | mask |= MAX77620_FPS_ENFPS_SW_MASK; | 
|  | 320 | config |= MAX77620_FPS_ENFPS_SW; | 
|  | 321 | } | 
|  | 322 | } | 
|  | 323 |  | 
|  | 324 | if (!chip->sleep_enable && !chip->enable_global_lpm) { | 
|  | 325 | ret = of_property_read_u32(fps_np, | 
|  | 326 | "maxim,device-state-on-disabled-event", | 
|  | 327 | ¶m_val); | 
|  | 328 | if (!ret) { | 
|  | 329 | if (param_val == 0) | 
|  | 330 | chip->sleep_enable = true; | 
|  | 331 | else if (param_val == 1) | 
|  | 332 | chip->enable_global_lpm = true; | 
|  | 333 | } | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, | 
|  | 337 | mask, config); | 
|  | 338 | if (ret < 0) { | 
|  | 339 | dev_err(dev, "Failed to update FPS CFG: %d\n", ret); | 
|  | 340 | return ret; | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 | return 0; | 
|  | 344 | } | 
|  | 345 |  | 
|  | 346 | static int max77620_initialise_fps(struct max77620_chip *chip) | 
|  | 347 | { | 
|  | 348 | struct device *dev = chip->dev; | 
|  | 349 | struct device_node *fps_np, *fps_child; | 
|  | 350 | u8 config; | 
|  | 351 | int fps_id; | 
|  | 352 | int ret; | 
|  | 353 |  | 
|  | 354 | for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { | 
|  | 355 | chip->shutdown_fps_period[fps_id] = -1; | 
|  | 356 | chip->suspend_fps_period[fps_id] = -1; | 
|  | 357 | } | 
|  | 358 |  | 
|  | 359 | fps_np = of_get_child_by_name(dev->of_node, "fps"); | 
|  | 360 | if (!fps_np) | 
|  | 361 | goto skip_fps; | 
|  | 362 |  | 
|  | 363 | for_each_child_of_node(fps_np, fps_child) { | 
|  | 364 | ret = max77620_config_fps(chip, fps_child); | 
|  | 365 | if (ret < 0) | 
|  | 366 | return ret; | 
|  | 367 | } | 
|  | 368 |  | 
|  | 369 | config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0; | 
|  | 370 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, | 
|  | 371 | MAX77620_ONOFFCNFG2_SLP_LPM_MSK, config); | 
|  | 372 | if (ret < 0) { | 
|  | 373 | dev_err(dev, "Failed to update SLP_LPM: %d\n", ret); | 
|  | 374 | return ret; | 
|  | 375 | } | 
|  | 376 |  | 
|  | 377 | skip_fps: | 
|  | 378 | /* Enable wake on EN0 pin */ | 
|  | 379 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, | 
|  | 380 | MAX77620_ONOFFCNFG2_WK_EN0, | 
|  | 381 | MAX77620_ONOFFCNFG2_WK_EN0); | 
|  | 382 | if (ret < 0) { | 
|  | 383 | dev_err(dev, "Failed to update WK_EN0: %d\n", ret); | 
|  | 384 | return ret; | 
|  | 385 | } | 
|  | 386 |  | 
|  | 387 | /* For MAX20024, SLPEN will be POR reset if CLRSE is b11 */ | 
|  | 388 | if ((chip->chip_id == MAX20024) && chip->sleep_enable) { | 
|  | 389 | config = MAX77620_ONOFFCNFG1_SLPEN | MAX20024_ONOFFCNFG1_CLRSE; | 
|  | 390 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, | 
|  | 391 | config, config); | 
|  | 392 | if (ret < 0) { | 
|  | 393 | dev_err(dev, "Failed to update SLPEN: %d\n", ret); | 
|  | 394 | return ret; | 
|  | 395 | } | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | return 0; | 
|  | 399 | } | 
|  | 400 |  | 
|  | 401 | static int max77620_read_es_version(struct max77620_chip *chip) | 
|  | 402 | { | 
|  | 403 | unsigned int val; | 
|  | 404 | u8 cid_val[6]; | 
|  | 405 | int i; | 
|  | 406 | int ret; | 
|  | 407 |  | 
|  | 408 | for (i = MAX77620_REG_CID0; i <= MAX77620_REG_CID5; i++) { | 
|  | 409 | ret = regmap_read(chip->rmap, i, &val); | 
|  | 410 | if (ret < 0) { | 
|  | 411 | dev_err(chip->dev, "Failed to read CID: %d\n", ret); | 
|  | 412 | return ret; | 
|  | 413 | } | 
|  | 414 | dev_dbg(chip->dev, "CID%d: 0x%02x\n", | 
|  | 415 | i - MAX77620_REG_CID0, val); | 
|  | 416 | cid_val[i - MAX77620_REG_CID0] = val; | 
|  | 417 | } | 
|  | 418 |  | 
|  | 419 | /* CID4 is OTP Version  and CID5 is ES version */ | 
|  | 420 | dev_info(chip->dev, "PMIC Version OTP:0x%02X and ES:0x%X\n", | 
|  | 421 | cid_val[4], MAX77620_CID5_DIDM(cid_val[5])); | 
|  | 422 |  | 
|  | 423 | return ret; | 
|  | 424 | } | 
|  | 425 |  | 
|  | 426 | static int max77620_probe(struct i2c_client *client, | 
|  | 427 | const struct i2c_device_id *id) | 
|  | 428 | { | 
|  | 429 | const struct regmap_config *rmap_config; | 
|  | 430 | struct max77620_chip *chip; | 
|  | 431 | const struct mfd_cell *mfd_cells; | 
|  | 432 | int n_mfd_cells; | 
|  | 433 | int ret; | 
|  | 434 |  | 
|  | 435 | chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); | 
|  | 436 | if (!chip) | 
|  | 437 | return -ENOMEM; | 
|  | 438 |  | 
|  | 439 | i2c_set_clientdata(client, chip); | 
|  | 440 | chip->dev = &client->dev; | 
|  | 441 | chip->irq_base = -1; | 
|  | 442 | chip->chip_irq = client->irq; | 
|  | 443 | chip->chip_id = (enum max77620_chip_id)id->driver_data; | 
|  | 444 |  | 
|  | 445 | switch (chip->chip_id) { | 
|  | 446 | case MAX77620: | 
|  | 447 | mfd_cells = max77620_children; | 
|  | 448 | n_mfd_cells = ARRAY_SIZE(max77620_children); | 
|  | 449 | rmap_config = &max77620_regmap_config; | 
|  | 450 | break; | 
|  | 451 | case MAX20024: | 
|  | 452 | mfd_cells = max20024_children; | 
|  | 453 | n_mfd_cells = ARRAY_SIZE(max20024_children); | 
|  | 454 | rmap_config = &max20024_regmap_config; | 
|  | 455 | break; | 
|  | 456 | default: | 
|  | 457 | dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id); | 
|  | 458 | return -EINVAL; | 
|  | 459 | } | 
|  | 460 |  | 
|  | 461 | chip->rmap = devm_regmap_init_i2c(client, rmap_config); | 
|  | 462 | if (IS_ERR(chip->rmap)) { | 
|  | 463 | ret = PTR_ERR(chip->rmap); | 
|  | 464 | dev_err(chip->dev, "Failed to initialise regmap: %d\n", ret); | 
|  | 465 | return ret; | 
|  | 466 | } | 
|  | 467 |  | 
|  | 468 | ret = max77620_read_es_version(chip); | 
|  | 469 | if (ret < 0) | 
|  | 470 | return ret; | 
|  | 471 |  | 
|  | 472 | max77620_top_irq_chip.irq_drv_data = chip; | 
|  | 473 | ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq, | 
|  | 474 | IRQF_ONESHOT | IRQF_SHARED, | 
|  | 475 | chip->irq_base, &max77620_top_irq_chip, | 
|  | 476 | &chip->top_irq_data); | 
|  | 477 | if (ret < 0) { | 
|  | 478 | dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); | 
|  | 479 | return ret; | 
|  | 480 | } | 
|  | 481 |  | 
|  | 482 | ret = max77620_initialise_fps(chip); | 
|  | 483 | if (ret < 0) | 
|  | 484 | return ret; | 
|  | 485 |  | 
|  | 486 | ret =  devm_mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, | 
|  | 487 | mfd_cells, n_mfd_cells, NULL, 0, | 
|  | 488 | regmap_irq_get_domain(chip->top_irq_data)); | 
|  | 489 | if (ret < 0) { | 
|  | 490 | dev_err(chip->dev, "Failed to add MFD children: %d\n", ret); | 
|  | 491 | return ret; | 
|  | 492 | } | 
|  | 493 |  | 
|  | 494 | return 0; | 
|  | 495 | } | 
|  | 496 |  | 
|  | 497 | #ifdef CONFIG_PM_SLEEP | 
|  | 498 | static int max77620_set_fps_period(struct max77620_chip *chip, | 
|  | 499 | int fps_id, int time_period) | 
|  | 500 | { | 
|  | 501 | int period = max77620_get_fps_period_reg_value(chip, time_period); | 
|  | 502 | int ret; | 
|  | 503 |  | 
|  | 504 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_FPS_CFG0 + fps_id, | 
|  | 505 | MAX77620_FPS_TIME_PERIOD_MASK, | 
|  | 506 | period << MAX77620_FPS_TIME_PERIOD_SHIFT); | 
|  | 507 | if (ret < 0) { | 
|  | 508 | dev_err(chip->dev, "Failed to update FPS period: %d\n", ret); | 
|  | 509 | return ret; | 
|  | 510 | } | 
|  | 511 |  | 
|  | 512 | return 0; | 
|  | 513 | } | 
|  | 514 |  | 
|  | 515 | static int max77620_i2c_suspend(struct device *dev) | 
|  | 516 | { | 
|  | 517 | struct max77620_chip *chip = dev_get_drvdata(dev); | 
|  | 518 | struct i2c_client *client = to_i2c_client(dev); | 
|  | 519 | unsigned int config; | 
|  | 520 | int fps; | 
|  | 521 | int ret; | 
|  | 522 |  | 
|  | 523 | for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { | 
|  | 524 | if (chip->suspend_fps_period[fps] < 0) | 
|  | 525 | continue; | 
|  | 526 |  | 
|  | 527 | ret = max77620_set_fps_period(chip, fps, | 
|  | 528 | chip->suspend_fps_period[fps]); | 
|  | 529 | if (ret < 0) | 
|  | 530 | return ret; | 
|  | 531 | } | 
|  | 532 |  | 
|  | 533 | /* | 
|  | 534 | * For MAX20024: No need to configure SLPEN on suspend as | 
|  | 535 | * it will be configured on Init. | 
|  | 536 | */ | 
|  | 537 | if (chip->chip_id == MAX20024) | 
|  | 538 | goto out; | 
|  | 539 |  | 
|  | 540 | config = (chip->sleep_enable) ? MAX77620_ONOFFCNFG1_SLPEN : 0; | 
|  | 541 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, | 
|  | 542 | MAX77620_ONOFFCNFG1_SLPEN, | 
|  | 543 | config); | 
|  | 544 | if (ret < 0) { | 
|  | 545 | dev_err(dev, "Failed to configure sleep in suspend: %d\n", ret); | 
|  | 546 | return ret; | 
|  | 547 | } | 
|  | 548 |  | 
|  | 549 | /* Disable WK_EN0 */ | 
|  | 550 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, | 
|  | 551 | MAX77620_ONOFFCNFG2_WK_EN0, 0); | 
|  | 552 | if (ret < 0) { | 
|  | 553 | dev_err(dev, "Failed to configure WK_EN in suspend: %d\n", ret); | 
|  | 554 | return ret; | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | out: | 
|  | 558 | disable_irq(client->irq); | 
|  | 559 |  | 
|  | 560 | return 0; | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 | static int max77620_i2c_resume(struct device *dev) | 
|  | 564 | { | 
|  | 565 | struct max77620_chip *chip = dev_get_drvdata(dev); | 
|  | 566 | struct i2c_client *client = to_i2c_client(dev); | 
|  | 567 | int ret; | 
|  | 568 | int fps; | 
|  | 569 |  | 
|  | 570 | for (fps = 0; fps < MAX77620_FPS_COUNT; fps++) { | 
|  | 571 | if (chip->shutdown_fps_period[fps] < 0) | 
|  | 572 | continue; | 
|  | 573 |  | 
|  | 574 | ret = max77620_set_fps_period(chip, fps, | 
|  | 575 | chip->shutdown_fps_period[fps]); | 
|  | 576 | if (ret < 0) | 
|  | 577 | return ret; | 
|  | 578 | } | 
|  | 579 |  | 
|  | 580 | /* | 
|  | 581 | * For MAX20024: No need to configure WKEN0 on resume as | 
|  | 582 | * it is configured on Init. | 
|  | 583 | */ | 
|  | 584 | if (chip->chip_id == MAX20024) | 
|  | 585 | goto out; | 
|  | 586 |  | 
|  | 587 | /* Enable WK_EN0 */ | 
|  | 588 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, | 
|  | 589 | MAX77620_ONOFFCNFG2_WK_EN0, | 
|  | 590 | MAX77620_ONOFFCNFG2_WK_EN0); | 
|  | 591 | if (ret < 0) { | 
|  | 592 | dev_err(dev, "Failed to configure WK_EN0 n resume: %d\n", ret); | 
|  | 593 | return ret; | 
|  | 594 | } | 
|  | 595 |  | 
|  | 596 | out: | 
|  | 597 | enable_irq(client->irq); | 
|  | 598 |  | 
|  | 599 | return 0; | 
|  | 600 | } | 
|  | 601 | #endif | 
|  | 602 |  | 
|  | 603 | static const struct i2c_device_id max77620_id[] = { | 
|  | 604 | {"max77620", MAX77620}, | 
|  | 605 | {"max20024", MAX20024}, | 
|  | 606 | {}, | 
|  | 607 | }; | 
|  | 608 |  | 
|  | 609 | static const struct dev_pm_ops max77620_pm_ops = { | 
|  | 610 | SET_SYSTEM_SLEEP_PM_OPS(max77620_i2c_suspend, max77620_i2c_resume) | 
|  | 611 | }; | 
|  | 612 |  | 
|  | 613 | static struct i2c_driver max77620_driver = { | 
|  | 614 | .driver = { | 
|  | 615 | .name = "max77620", | 
|  | 616 | .pm = &max77620_pm_ops, | 
|  | 617 | }, | 
|  | 618 | .probe = max77620_probe, | 
|  | 619 | .id_table = max77620_id, | 
|  | 620 | }; | 
|  | 621 | builtin_i2c_driver(max77620_driver); |