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