Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Maxim MAX77714 Core Driver
0004  *
0005  * Copyright (C) 2022 Luca Ceresoli
0006  * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
0007  */
0008 
0009 #include <linux/i2c.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/mfd/core.h>
0012 #include <linux/mfd/max77714.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/regmap.h>
0016 
0017 static const struct mfd_cell max77714_cells[] = {
0018     { .name = "max77714-watchdog" },
0019     { .name = "max77714-rtc" },
0020 };
0021 
0022 static const struct regmap_range max77714_readable_ranges[] = {
0023     regmap_reg_range(MAX77714_INT_TOP,     MAX77714_INT_TOP),
0024     regmap_reg_range(MAX77714_INT_TOPM,    MAX77714_INT_TOPM),
0025     regmap_reg_range(MAX77714_32K_STATUS,  MAX77714_32K_CONFIG),
0026     regmap_reg_range(MAX77714_CNFG_GLBL2,  MAX77714_CNFG2_ONOFF),
0027 };
0028 
0029 static const struct regmap_range max77714_writable_ranges[] = {
0030     regmap_reg_range(MAX77714_INT_TOPM,    MAX77714_INT_TOPM),
0031     regmap_reg_range(MAX77714_32K_CONFIG,  MAX77714_32K_CONFIG),
0032     regmap_reg_range(MAX77714_CNFG_GLBL2,  MAX77714_CNFG2_ONOFF),
0033 };
0034 
0035 static const struct regmap_access_table max77714_readable_table = {
0036     .yes_ranges = max77714_readable_ranges,
0037     .n_yes_ranges = ARRAY_SIZE(max77714_readable_ranges),
0038 };
0039 
0040 static const struct regmap_access_table max77714_writable_table = {
0041     .yes_ranges = max77714_writable_ranges,
0042     .n_yes_ranges = ARRAY_SIZE(max77714_writable_ranges),
0043 };
0044 
0045 static const struct regmap_config max77714_regmap_config = {
0046     .reg_bits = 8,
0047     .val_bits = 8,
0048     .max_register = MAX77714_CNFG2_ONOFF,
0049     .rd_table = &max77714_readable_table,
0050     .wr_table = &max77714_writable_table,
0051 };
0052 
0053 static const struct regmap_irq max77714_top_irqs[] = {
0054     REGMAP_IRQ_REG(MAX77714_IRQ_TOP_ONOFF,   0, MAX77714_INT_TOP_ONOFF),
0055     REGMAP_IRQ_REG(MAX77714_IRQ_TOP_RTC,     0, MAX77714_INT_TOP_RTC),
0056     REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GPIO,    0, MAX77714_INT_TOP_GPIO),
0057     REGMAP_IRQ_REG(MAX77714_IRQ_TOP_LDO,     0, MAX77714_INT_TOP_LDO),
0058     REGMAP_IRQ_REG(MAX77714_IRQ_TOP_SD,      0, MAX77714_INT_TOP_SD),
0059     REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GLBL,    0, MAX77714_INT_TOP_GLBL),
0060 };
0061 
0062 static const struct regmap_irq_chip max77714_irq_chip = {
0063     .name           = "max77714-pmic",
0064     .status_base        = MAX77714_INT_TOP,
0065     .mask_base      = MAX77714_INT_TOPM,
0066     .num_regs       = 1,
0067     .irqs           = max77714_top_irqs,
0068     .num_irqs       = ARRAY_SIZE(max77714_top_irqs),
0069 };
0070 
0071 /*
0072  * MAX77714 initially uses the internal, low precision oscillator. Enable
0073  * the external oscillator by setting the XOSC_RETRY bit. If the external
0074  * oscillator is not OK (probably not installed) this has no effect.
0075  */
0076 static int max77714_setup_xosc(struct device *dev, struct regmap *regmap)
0077 {
0078     /* Internal Crystal Load Capacitance, indexed by value of 32KLOAD bits */
0079     static const unsigned int load_cap[4] = {0, 10, 12, 22}; /* pF */
0080     unsigned int load_cap_idx;
0081     unsigned int status;
0082     int err;
0083 
0084     err = regmap_update_bits(regmap, MAX77714_32K_CONFIG,
0085                  MAX77714_32K_CONFIG_XOSC_RETRY,
0086                  MAX77714_32K_CONFIG_XOSC_RETRY);
0087     if (err)
0088         return dev_err_probe(dev, err, "Failed to configure the external oscillator\n");
0089 
0090     err = regmap_read(regmap, MAX77714_32K_STATUS, &status);
0091     if (err)
0092         return dev_err_probe(dev, err, "Failed to read external oscillator status\n");
0093 
0094     load_cap_idx = (status >> MAX77714_32K_STATUS_32KLOAD_SHF)
0095         & MAX77714_32K_STATUS_32KLOAD_MSK;
0096 
0097     dev_info(dev, "Using %s oscillator, %d pF load cap\n",
0098          status & MAX77714_32K_STATUS_32KSOURCE ? "internal" : "external",
0099          load_cap[load_cap_idx]);
0100 
0101     return 0;
0102 }
0103 
0104 static int max77714_probe(struct i2c_client *client)
0105 {
0106     struct device *dev = &client->dev;
0107     struct regmap *regmap;
0108     struct regmap_irq_chip_data *irq_data;
0109     int err;
0110 
0111     regmap = devm_regmap_init_i2c(client, &max77714_regmap_config);
0112     if (IS_ERR(regmap))
0113         return dev_err_probe(dev, PTR_ERR(regmap),
0114                      "Failed to initialise regmap\n");
0115 
0116     err = max77714_setup_xosc(dev, regmap);
0117     if (err)
0118         return err;
0119 
0120     err = devm_regmap_add_irq_chip(dev, regmap, client->irq,
0121                        IRQF_ONESHOT | IRQF_SHARED, 0,
0122                        &max77714_irq_chip, &irq_data);
0123     if (err)
0124         return dev_err_probe(dev, err, "Failed to add PMIC IRQ chip\n");
0125 
0126     err =  devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
0127                     max77714_cells, ARRAY_SIZE(max77714_cells),
0128                     NULL, 0, NULL);
0129     if (err)
0130         return dev_err_probe(dev, err, "Failed to register child devices\n");
0131 
0132     return 0;
0133 }
0134 
0135 static const struct of_device_id max77714_dt_match[] = {
0136     { .compatible = "maxim,max77714" },
0137     {},
0138 };
0139 MODULE_DEVICE_TABLE(of, max77714_dt_match);
0140 
0141 static struct i2c_driver max77714_driver = {
0142     .driver = {
0143         .name = "max77714",
0144         .of_match_table = max77714_dt_match,
0145     },
0146     .probe_new = max77714_probe,
0147 };
0148 module_i2c_driver(max77714_driver);
0149 
0150 MODULE_DESCRIPTION("Maxim MAX77714 MFD core driver");
0151 MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
0152 MODULE_LICENSE("GPL");