Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (C) 2018 BayLibre SAS
0004 // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
0005 //
0006 // Core MFD driver for MAXIM 77650/77651 charger/power-supply.
0007 // Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf
0008 
0009 #include <linux/i2c.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irq.h>
0012 #include <linux/mfd/core.h>
0013 #include <linux/mfd/max77650.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/regmap.h>
0017 
0018 #define MAX77650_INT_GPI_F_MSK      BIT(0)
0019 #define MAX77650_INT_GPI_R_MSK      BIT(1)
0020 #define MAX77650_INT_GPI_MSK \
0021             (MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK)
0022 #define MAX77650_INT_nEN_F_MSK      BIT(2)
0023 #define MAX77650_INT_nEN_R_MSK      BIT(3)
0024 #define MAX77650_INT_TJAL1_R_MSK    BIT(4)
0025 #define MAX77650_INT_TJAL2_R_MSK    BIT(5)
0026 #define MAX77650_INT_DOD_R_MSK      BIT(6)
0027 
0028 #define MAX77650_INT_THM_MSK        BIT(0)
0029 #define MAX77650_INT_CHG_MSK        BIT(1)
0030 #define MAX77650_INT_CHGIN_MSK      BIT(2)
0031 #define MAX77650_INT_TJ_REG_MSK     BIT(3)
0032 #define MAX77650_INT_CHGIN_CTRL_MSK BIT(4)
0033 #define MAX77650_INT_SYS_CTRL_MSK   BIT(5)
0034 #define MAX77650_INT_SYS_CNFG_MSK   BIT(6)
0035 
0036 #define MAX77650_INT_GLBL_OFFSET    0
0037 #define MAX77650_INT_CHG_OFFSET     1
0038 
0039 #define MAX77650_SBIA_LPM_MASK      BIT(5)
0040 #define MAX77650_SBIA_LPM_DISABLED  0x00
0041 
0042 enum {
0043     MAX77650_INT_GPI,
0044     MAX77650_INT_nEN_F,
0045     MAX77650_INT_nEN_R,
0046     MAX77650_INT_TJAL1_R,
0047     MAX77650_INT_TJAL2_R,
0048     MAX77650_INT_DOD_R,
0049     MAX77650_INT_THM,
0050     MAX77650_INT_CHG,
0051     MAX77650_INT_CHGIN,
0052     MAX77650_INT_TJ_REG,
0053     MAX77650_INT_CHGIN_CTRL,
0054     MAX77650_INT_SYS_CTRL,
0055     MAX77650_INT_SYS_CNFG,
0056 };
0057 
0058 static const struct resource max77650_charger_resources[] = {
0059     DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"),
0060     DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"),
0061 };
0062 
0063 static const struct resource max77650_gpio_resources[] = {
0064     DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"),
0065 };
0066 
0067 static const struct resource max77650_onkey_resources[] = {
0068     DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"),
0069     DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"),
0070 };
0071 
0072 static const struct mfd_cell max77650_cells[] = {
0073     {
0074         .name       = "max77650-regulator",
0075         .of_compatible  = "maxim,max77650-regulator",
0076     }, {
0077         .name       = "max77650-charger",
0078         .of_compatible  = "maxim,max77650-charger",
0079         .resources  = max77650_charger_resources,
0080         .num_resources  = ARRAY_SIZE(max77650_charger_resources),
0081     }, {
0082         .name       = "max77650-gpio",
0083         .of_compatible  = "maxim,max77650-gpio",
0084         .resources  = max77650_gpio_resources,
0085         .num_resources  = ARRAY_SIZE(max77650_gpio_resources),
0086     }, {
0087         .name       = "max77650-led",
0088         .of_compatible  = "maxim,max77650-led",
0089     }, {
0090         .name       = "max77650-onkey",
0091         .of_compatible  = "maxim,max77650-onkey",
0092         .resources  = max77650_onkey_resources,
0093         .num_resources  = ARRAY_SIZE(max77650_onkey_resources),
0094     },
0095 };
0096 
0097 static const struct regmap_irq max77650_irqs[] = {
0098     [MAX77650_INT_GPI] = {
0099         .reg_offset = MAX77650_INT_GLBL_OFFSET,
0100         .mask = MAX77650_INT_GPI_MSK,
0101         .type = {
0102             .type_falling_val = MAX77650_INT_GPI_F_MSK,
0103             .type_rising_val = MAX77650_INT_GPI_R_MSK,
0104             .types_supported = IRQ_TYPE_EDGE_BOTH,
0105         },
0106     },
0107     REGMAP_IRQ_REG(MAX77650_INT_nEN_F,
0108                MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK),
0109     REGMAP_IRQ_REG(MAX77650_INT_nEN_R,
0110                MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK),
0111     REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R,
0112                MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK),
0113     REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R,
0114                MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK),
0115     REGMAP_IRQ_REG(MAX77650_INT_DOD_R,
0116                MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK),
0117     REGMAP_IRQ_REG(MAX77650_INT_THM,
0118                MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK),
0119     REGMAP_IRQ_REG(MAX77650_INT_CHG,
0120                MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK),
0121     REGMAP_IRQ_REG(MAX77650_INT_CHGIN,
0122                MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK),
0123     REGMAP_IRQ_REG(MAX77650_INT_TJ_REG,
0124                MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK),
0125     REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL,
0126                MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK),
0127     REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL,
0128                MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK),
0129     REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG,
0130                MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK),
0131 };
0132 
0133 static const struct regmap_irq_chip max77650_irq_chip = {
0134     .name           = "max77650-irq",
0135     .irqs           = max77650_irqs,
0136     .num_irqs       = ARRAY_SIZE(max77650_irqs),
0137     .num_regs       = 2,
0138     .status_base        = MAX77650_REG_INT_GLBL,
0139     .mask_base      = MAX77650_REG_INTM_GLBL,
0140     .type_in_mask       = true,
0141     .type_invert        = true,
0142     .init_ack_masked    = true,
0143     .clear_on_unmask    = true,
0144 };
0145 
0146 static const struct regmap_config max77650_regmap_config = {
0147     .name       = "max77650",
0148     .reg_bits   = 8,
0149     .val_bits   = 8,
0150 };
0151 
0152 static int max77650_i2c_probe(struct i2c_client *i2c)
0153 {
0154     struct regmap_irq_chip_data *irq_data;
0155     struct device *dev = &i2c->dev;
0156     struct irq_domain *domain;
0157     struct regmap *map;
0158     unsigned int val;
0159     int rv, id;
0160 
0161     map = devm_regmap_init_i2c(i2c, &max77650_regmap_config);
0162     if (IS_ERR(map)) {
0163         dev_err(dev, "Unable to initialise I2C Regmap\n");
0164         return PTR_ERR(map);
0165     }
0166 
0167     rv = regmap_read(map, MAX77650_REG_CID, &val);
0168     if (rv) {
0169         dev_err(dev, "Unable to read Chip ID\n");
0170         return rv;
0171     }
0172 
0173     id = MAX77650_CID_BITS(val);
0174     switch (id) {
0175     case MAX77650_CID_77650A:
0176     case MAX77650_CID_77650C:
0177     case MAX77650_CID_77651A:
0178     case MAX77650_CID_77651B:
0179         break;
0180     default:
0181         dev_err(dev, "Chip not supported - ID: 0x%02x\n", id);
0182         return -ENODEV;
0183     }
0184 
0185     /*
0186      * This IC has a low-power mode which reduces the quiescent current
0187      * consumption to ~5.6uA but is only suitable for systems consuming
0188      * less than ~2mA. Since this is not likely the case even on
0189      * linux-based wearables - keep the chip in normal power mode.
0190      */
0191     rv = regmap_update_bits(map,
0192                 MAX77650_REG_CNFG_GLBL,
0193                 MAX77650_SBIA_LPM_MASK,
0194                 MAX77650_SBIA_LPM_DISABLED);
0195     if (rv) {
0196         dev_err(dev, "Unable to change the power mode\n");
0197         return rv;
0198     }
0199 
0200     rv = devm_regmap_add_irq_chip(dev, map, i2c->irq,
0201                       IRQF_ONESHOT | IRQF_SHARED, 0,
0202                       &max77650_irq_chip, &irq_data);
0203     if (rv) {
0204         dev_err(dev, "Unable to add Regmap IRQ chip\n");
0205         return rv;
0206     }
0207 
0208     domain = regmap_irq_get_domain(irq_data);
0209 
0210     return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
0211                     max77650_cells, ARRAY_SIZE(max77650_cells),
0212                     NULL, 0, domain);
0213 }
0214 
0215 static const struct of_device_id max77650_of_match[] = {
0216     { .compatible = "maxim,max77650" },
0217     { }
0218 };
0219 MODULE_DEVICE_TABLE(of, max77650_of_match);
0220 
0221 static struct i2c_driver max77650_i2c_driver = {
0222     .driver = {
0223         .name = "max77650",
0224         .of_match_table = max77650_of_match,
0225     },
0226     .probe_new = max77650_i2c_probe,
0227 };
0228 module_i2c_driver(max77650_i2c_driver);
0229 
0230 MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver");
0231 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
0232 MODULE_LICENSE("GPL v2");