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 42 enum { 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 58 static 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 63 static const struct resource max77650_gpio_resources[] = { 64 DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"), 65 }; 66 67 static 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 72 static 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 97 static 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 133 static 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 .init_ack_masked = true, 142 .clear_on_unmask = true, 143 }; 144 145 static const struct regmap_config max77650_regmap_config = { 146 .name = "max77650", 147 .reg_bits = 8, 148 .val_bits = 8, 149 }; 150 151 static int max77650_i2c_probe(struct i2c_client *i2c) 152 { 153 struct regmap_irq_chip_data *irq_data; 154 struct device *dev = &i2c->dev; 155 struct irq_domain *domain; 156 struct regmap *map; 157 unsigned int val; 158 int rv, id; 159 160 map = devm_regmap_init_i2c(i2c, &max77650_regmap_config); 161 if (IS_ERR(map)) { 162 dev_err(dev, "Unable to initialise I2C Regmap\n"); 163 return PTR_ERR(map); 164 } 165 166 rv = regmap_read(map, MAX77650_REG_CID, &val); 167 if (rv) { 168 dev_err(dev, "Unable to read Chip ID\n"); 169 return rv; 170 } 171 172 id = MAX77650_CID_BITS(val); 173 switch (id) { 174 case MAX77650_CID_77650A: 175 case MAX77650_CID_77650C: 176 case MAX77650_CID_77651A: 177 case MAX77650_CID_77651B: 178 break; 179 default: 180 dev_err(dev, "Chip not supported - ID: 0x%02x\n", id); 181 return -ENODEV; 182 } 183 184 /* 185 * This IC has a low-power mode which reduces the quiescent current 186 * consumption to ~5.6uA but is only suitable for systems consuming 187 * less than ~2mA. Since this is not likely the case even on 188 * linux-based wearables - keep the chip in normal power mode. 189 */ 190 rv = regmap_update_bits(map, 191 MAX77650_REG_CNFG_GLBL, 192 MAX77650_SBIA_LPM_MASK, 193 MAX77650_SBIA_LPM_DISABLED); 194 if (rv) { 195 dev_err(dev, "Unable to change the power mode\n"); 196 return rv; 197 } 198 199 rv = devm_regmap_add_irq_chip(dev, map, i2c->irq, 200 IRQF_ONESHOT | IRQF_SHARED, 0, 201 &max77650_irq_chip, &irq_data); 202 if (rv) { 203 dev_err(dev, "Unable to add Regmap IRQ chip\n"); 204 return rv; 205 } 206 207 domain = regmap_irq_get_domain(irq_data); 208 209 return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 210 max77650_cells, ARRAY_SIZE(max77650_cells), 211 NULL, 0, domain); 212 } 213 214 static const struct of_device_id max77650_of_match[] = { 215 { .compatible = "maxim,max77650" }, 216 { } 217 }; 218 MODULE_DEVICE_TABLE(of, max77650_of_match); 219 220 static struct i2c_driver max77650_i2c_driver = { 221 .driver = { 222 .name = "max77650", 223 .of_match_table = max77650_of_match, 224 }, 225 .probe = max77650_i2c_probe, 226 }; 227 module_i2c_driver(max77650_i2c_driver); 228 229 MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver"); 230 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); 231 MODULE_LICENSE("GPL v2"); 232