max77650.c (6829B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// Copyright (C) 2018 BayLibre SAS 4// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 5// 6// Core MFD driver for MAXIM 77650/77651 charger/power-supply. 7// Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf 8 9#include <linux/i2c.h> 10#include <linux/interrupt.h> 11#include <linux/irq.h> 12#include <linux/mfd/core.h> 13#include <linux/mfd/max77650.h> 14#include <linux/module.h> 15#include <linux/of.h> 16#include <linux/regmap.h> 17 18#define MAX77650_INT_GPI_F_MSK BIT(0) 19#define MAX77650_INT_GPI_R_MSK BIT(1) 20#define MAX77650_INT_GPI_MSK \ 21 (MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK) 22#define MAX77650_INT_nEN_F_MSK BIT(2) 23#define MAX77650_INT_nEN_R_MSK BIT(3) 24#define MAX77650_INT_TJAL1_R_MSK BIT(4) 25#define MAX77650_INT_TJAL2_R_MSK BIT(5) 26#define MAX77650_INT_DOD_R_MSK BIT(6) 27 28#define MAX77650_INT_THM_MSK BIT(0) 29#define MAX77650_INT_CHG_MSK BIT(1) 30#define MAX77650_INT_CHGIN_MSK BIT(2) 31#define MAX77650_INT_TJ_REG_MSK BIT(3) 32#define MAX77650_INT_CHGIN_CTRL_MSK BIT(4) 33#define MAX77650_INT_SYS_CTRL_MSK BIT(5) 34#define MAX77650_INT_SYS_CNFG_MSK BIT(6) 35 36#define MAX77650_INT_GLBL_OFFSET 0 37#define MAX77650_INT_CHG_OFFSET 1 38 39#define MAX77650_SBIA_LPM_MASK BIT(5) 40#define MAX77650_SBIA_LPM_DISABLED 0x00 41 42enum { 43 MAX77650_INT_GPI, 44 MAX77650_INT_nEN_F, 45 MAX77650_INT_nEN_R, 46 MAX77650_INT_TJAL1_R, 47 MAX77650_INT_TJAL2_R, 48 MAX77650_INT_DOD_R, 49 MAX77650_INT_THM, 50 MAX77650_INT_CHG, 51 MAX77650_INT_CHGIN, 52 MAX77650_INT_TJ_REG, 53 MAX77650_INT_CHGIN_CTRL, 54 MAX77650_INT_SYS_CTRL, 55 MAX77650_INT_SYS_CNFG, 56}; 57 58static const struct resource max77650_charger_resources[] = { 59 DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"), 60 DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"), 61}; 62 63static const struct resource max77650_gpio_resources[] = { 64 DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"), 65}; 66 67static const struct resource max77650_onkey_resources[] = { 68 DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"), 69 DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"), 70}; 71 72static const struct mfd_cell max77650_cells[] = { 73 { 74 .name = "max77650-regulator", 75 .of_compatible = "maxim,max77650-regulator", 76 }, { 77 .name = "max77650-charger", 78 .of_compatible = "maxim,max77650-charger", 79 .resources = max77650_charger_resources, 80 .num_resources = ARRAY_SIZE(max77650_charger_resources), 81 }, { 82 .name = "max77650-gpio", 83 .of_compatible = "maxim,max77650-gpio", 84 .resources = max77650_gpio_resources, 85 .num_resources = ARRAY_SIZE(max77650_gpio_resources), 86 }, { 87 .name = "max77650-led", 88 .of_compatible = "maxim,max77650-led", 89 }, { 90 .name = "max77650-onkey", 91 .of_compatible = "maxim,max77650-onkey", 92 .resources = max77650_onkey_resources, 93 .num_resources = ARRAY_SIZE(max77650_onkey_resources), 94 }, 95}; 96 97static const struct regmap_irq max77650_irqs[] = { 98 [MAX77650_INT_GPI] = { 99 .reg_offset = MAX77650_INT_GLBL_OFFSET, 100 .mask = MAX77650_INT_GPI_MSK, 101 .type = { 102 .type_falling_val = MAX77650_INT_GPI_F_MSK, 103 .type_rising_val = MAX77650_INT_GPI_R_MSK, 104 .types_supported = IRQ_TYPE_EDGE_BOTH, 105 }, 106 }, 107 REGMAP_IRQ_REG(MAX77650_INT_nEN_F, 108 MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK), 109 REGMAP_IRQ_REG(MAX77650_INT_nEN_R, 110 MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK), 111 REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R, 112 MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK), 113 REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R, 114 MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK), 115 REGMAP_IRQ_REG(MAX77650_INT_DOD_R, 116 MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK), 117 REGMAP_IRQ_REG(MAX77650_INT_THM, 118 MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK), 119 REGMAP_IRQ_REG(MAX77650_INT_CHG, 120 MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK), 121 REGMAP_IRQ_REG(MAX77650_INT_CHGIN, 122 MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK), 123 REGMAP_IRQ_REG(MAX77650_INT_TJ_REG, 124 MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK), 125 REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL, 126 MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK), 127 REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL, 128 MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK), 129 REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG, 130 MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK), 131}; 132 133static const struct regmap_irq_chip max77650_irq_chip = { 134 .name = "max77650-irq", 135 .irqs = max77650_irqs, 136 .num_irqs = ARRAY_SIZE(max77650_irqs), 137 .num_regs = 2, 138 .status_base = MAX77650_REG_INT_GLBL, 139 .mask_base = MAX77650_REG_INTM_GLBL, 140 .type_in_mask = true, 141 .type_invert = true, 142 .init_ack_masked = true, 143 .clear_on_unmask = true, 144}; 145 146static const struct regmap_config max77650_regmap_config = { 147 .name = "max77650", 148 .reg_bits = 8, 149 .val_bits = 8, 150}; 151 152static int max77650_i2c_probe(struct i2c_client *i2c) 153{ 154 struct regmap_irq_chip_data *irq_data; 155 struct device *dev = &i2c->dev; 156 struct irq_domain *domain; 157 struct regmap *map; 158 unsigned int val; 159 int rv, id; 160 161 map = devm_regmap_init_i2c(i2c, &max77650_regmap_config); 162 if (IS_ERR(map)) { 163 dev_err(dev, "Unable to initialise I2C Regmap\n"); 164 return PTR_ERR(map); 165 } 166 167 rv = regmap_read(map, MAX77650_REG_CID, &val); 168 if (rv) { 169 dev_err(dev, "Unable to read Chip ID\n"); 170 return rv; 171 } 172 173 id = MAX77650_CID_BITS(val); 174 switch (id) { 175 case MAX77650_CID_77650A: 176 case MAX77650_CID_77650C: 177 case MAX77650_CID_77651A: 178 case MAX77650_CID_77651B: 179 break; 180 default: 181 dev_err(dev, "Chip not supported - ID: 0x%02x\n", id); 182 return -ENODEV; 183 } 184 185 /* 186 * This IC has a low-power mode which reduces the quiescent current 187 * consumption to ~5.6uA but is only suitable for systems consuming 188 * less than ~2mA. Since this is not likely the case even on 189 * linux-based wearables - keep the chip in normal power mode. 190 */ 191 rv = regmap_update_bits(map, 192 MAX77650_REG_CNFG_GLBL, 193 MAX77650_SBIA_LPM_MASK, 194 MAX77650_SBIA_LPM_DISABLED); 195 if (rv) { 196 dev_err(dev, "Unable to change the power mode\n"); 197 return rv; 198 } 199 200 rv = devm_regmap_add_irq_chip(dev, map, i2c->irq, 201 IRQF_ONESHOT | IRQF_SHARED, 0, 202 &max77650_irq_chip, &irq_data); 203 if (rv) { 204 dev_err(dev, "Unable to add Regmap IRQ chip\n"); 205 return rv; 206 } 207 208 domain = regmap_irq_get_domain(irq_data); 209 210 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 211 max77650_cells, ARRAY_SIZE(max77650_cells), 212 NULL, 0, domain); 213} 214 215static const struct of_device_id max77650_of_match[] = { 216 { .compatible = "maxim,max77650" }, 217 { } 218}; 219MODULE_DEVICE_TABLE(of, max77650_of_match); 220 221static struct i2c_driver max77650_i2c_driver = { 222 .driver = { 223 .name = "max77650", 224 .of_match_table = max77650_of_match, 225 }, 226 .probe_new = max77650_i2c_probe, 227}; 228module_i2c_driver(max77650_i2c_driver); 229 230MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver"); 231MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); 232MODULE_LICENSE("GPL v2");