max77714.c (4779B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Maxim MAX77714 Core Driver 4 * 5 * Copyright (C) 2022 Luca Ceresoli 6 * Author: Luca Ceresoli <luca@lucaceresoli.net> 7 */ 8 9#include <linux/i2c.h> 10#include <linux/interrupt.h> 11#include <linux/mfd/core.h> 12#include <linux/mfd/max77714.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/regmap.h> 16 17static const struct mfd_cell max77714_cells[] = { 18 { .name = "max77714-watchdog" }, 19 { .name = "max77714-rtc" }, 20}; 21 22static const struct regmap_range max77714_readable_ranges[] = { 23 regmap_reg_range(MAX77714_INT_TOP, MAX77714_INT_TOP), 24 regmap_reg_range(MAX77714_INT_TOPM, MAX77714_INT_TOPM), 25 regmap_reg_range(MAX77714_32K_STATUS, MAX77714_32K_CONFIG), 26 regmap_reg_range(MAX77714_CNFG_GLBL2, MAX77714_CNFG2_ONOFF), 27}; 28 29static const struct regmap_range max77714_writable_ranges[] = { 30 regmap_reg_range(MAX77714_INT_TOPM, MAX77714_INT_TOPM), 31 regmap_reg_range(MAX77714_32K_CONFIG, MAX77714_32K_CONFIG), 32 regmap_reg_range(MAX77714_CNFG_GLBL2, MAX77714_CNFG2_ONOFF), 33}; 34 35static const struct regmap_access_table max77714_readable_table = { 36 .yes_ranges = max77714_readable_ranges, 37 .n_yes_ranges = ARRAY_SIZE(max77714_readable_ranges), 38}; 39 40static const struct regmap_access_table max77714_writable_table = { 41 .yes_ranges = max77714_writable_ranges, 42 .n_yes_ranges = ARRAY_SIZE(max77714_writable_ranges), 43}; 44 45static const struct regmap_config max77714_regmap_config = { 46 .reg_bits = 8, 47 .val_bits = 8, 48 .max_register = MAX77714_CNFG2_ONOFF, 49 .rd_table = &max77714_readable_table, 50 .wr_table = &max77714_writable_table, 51}; 52 53static const struct regmap_irq max77714_top_irqs[] = { 54 REGMAP_IRQ_REG(MAX77714_IRQ_TOP_ONOFF, 0, MAX77714_INT_TOP_ONOFF), 55 REGMAP_IRQ_REG(MAX77714_IRQ_TOP_RTC, 0, MAX77714_INT_TOP_RTC), 56 REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GPIO, 0, MAX77714_INT_TOP_GPIO), 57 REGMAP_IRQ_REG(MAX77714_IRQ_TOP_LDO, 0, MAX77714_INT_TOP_LDO), 58 REGMAP_IRQ_REG(MAX77714_IRQ_TOP_SD, 0, MAX77714_INT_TOP_SD), 59 REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GLBL, 0, MAX77714_INT_TOP_GLBL), 60}; 61 62static const struct regmap_irq_chip max77714_irq_chip = { 63 .name = "max77714-pmic", 64 .status_base = MAX77714_INT_TOP, 65 .mask_base = MAX77714_INT_TOPM, 66 .num_regs = 1, 67 .irqs = max77714_top_irqs, 68 .num_irqs = ARRAY_SIZE(max77714_top_irqs), 69}; 70 71/* 72 * MAX77714 initially uses the internal, low precision oscillator. Enable 73 * the external oscillator by setting the XOSC_RETRY bit. If the external 74 * oscillator is not OK (probably not installed) this has no effect. 75 */ 76static int max77714_setup_xosc(struct device *dev, struct regmap *regmap) 77{ 78 /* Internal Crystal Load Capacitance, indexed by value of 32KLOAD bits */ 79 static const unsigned int load_cap[4] = {0, 10, 12, 22}; /* pF */ 80 unsigned int load_cap_idx; 81 unsigned int status; 82 int err; 83 84 err = regmap_update_bits(regmap, MAX77714_32K_CONFIG, 85 MAX77714_32K_CONFIG_XOSC_RETRY, 86 MAX77714_32K_CONFIG_XOSC_RETRY); 87 if (err) 88 return dev_err_probe(dev, err, "Failed to configure the external oscillator\n"); 89 90 err = regmap_read(regmap, MAX77714_32K_STATUS, &status); 91 if (err) 92 return dev_err_probe(dev, err, "Failed to read external oscillator status\n"); 93 94 load_cap_idx = (status >> MAX77714_32K_STATUS_32KLOAD_SHF) 95 & MAX77714_32K_STATUS_32KLOAD_MSK; 96 97 dev_info(dev, "Using %s oscillator, %d pF load cap\n", 98 status & MAX77714_32K_STATUS_32KSOURCE ? "internal" : "external", 99 load_cap[load_cap_idx]); 100 101 return 0; 102} 103 104static int max77714_probe(struct i2c_client *client) 105{ 106 struct device *dev = &client->dev; 107 struct regmap *regmap; 108 struct regmap_irq_chip_data *irq_data; 109 int err; 110 111 regmap = devm_regmap_init_i2c(client, &max77714_regmap_config); 112 if (IS_ERR(regmap)) 113 return dev_err_probe(dev, PTR_ERR(regmap), 114 "Failed to initialise regmap\n"); 115 116 err = max77714_setup_xosc(dev, regmap); 117 if (err) 118 return err; 119 120 err = devm_regmap_add_irq_chip(dev, regmap, client->irq, 121 IRQF_ONESHOT | IRQF_SHARED, 0, 122 &max77714_irq_chip, &irq_data); 123 if (err) 124 return dev_err_probe(dev, err, "Failed to add PMIC IRQ chip\n"); 125 126 err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, 127 max77714_cells, ARRAY_SIZE(max77714_cells), 128 NULL, 0, NULL); 129 if (err) 130 return dev_err_probe(dev, err, "Failed to register child devices\n"); 131 132 return 0; 133} 134 135static const struct of_device_id max77714_dt_match[] = { 136 { .compatible = "maxim,max77714" }, 137 {}, 138}; 139MODULE_DEVICE_TABLE(of, max77714_dt_match); 140 141static struct i2c_driver max77714_driver = { 142 .driver = { 143 .name = "max77714", 144 .of_match_table = max77714_dt_match, 145 }, 146 .probe_new = max77714_probe, 147}; 148module_i2c_driver(max77714_driver); 149 150MODULE_DESCRIPTION("Maxim MAX77714 MFD core driver"); 151MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>"); 152MODULE_LICENSE("GPL");