brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · d77c31c Raw
221 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2022 Analog Devices, Inc.4 * Driver for the MAX77540 and MAX775415 */6 7#include <linux/i2c.h>8#include <linux/interrupt.h>9#include <linux/mfd/core.h>10#include <linux/mfd/max77541.h>11#include <linux/property.h>12#include <linux/regmap.h>13 14static const struct regmap_config max77541_regmap_config = {15	.reg_bits   = 8,16	.val_bits   = 8,17};18 19static const struct regmap_irq max77541_src_irqs[] = {20	{ .mask = MAX77541_BIT_INT_SRC_TOPSYS },21	{ .mask = MAX77541_BIT_INT_SRC_BUCK },22};23 24static const struct regmap_irq_chip max77541_src_irq_chip = {25	.name		= "max77541-src",26	.status_base	= MAX77541_REG_INT_SRC,27	.mask_base	= MAX77541_REG_INT_SRC_M,28	.num_regs	= 1,29	.irqs		= max77541_src_irqs,30	.num_irqs       = ARRAY_SIZE(max77541_src_irqs),31};32 33static const struct regmap_irq max77541_topsys_irqs[] = {34	{ .mask = MAX77541_BIT_TOPSYS_INT_TJ_120C },35	{ .mask = MAX77541_BIT_TOPSYS_INT_TJ_140C },36	{ .mask = MAX77541_BIT_TOPSYS_INT_TSHDN },37	{ .mask = MAX77541_BIT_TOPSYS_INT_UVLO },38	{ .mask = MAX77541_BIT_TOPSYS_INT_ALT_SWO },39	{ .mask = MAX77541_BIT_TOPSYS_INT_EXT_FREQ_DET },40};41 42static const struct regmap_irq_chip max77541_topsys_irq_chip = {43	.name		= "max77541-topsys",44	.status_base	= MAX77541_REG_TOPSYS_INT,45	.mask_base	= MAX77541_REG_TOPSYS_INT_M,46	.num_regs	= 1,47	.irqs		= max77541_topsys_irqs,48	.num_irqs	= ARRAY_SIZE(max77541_topsys_irqs),49};50 51static const struct regmap_irq max77541_buck_irqs[] = {52	{ .mask = MAX77541_BIT_BUCK_INT_M1_POK_FLT },53	{ .mask = MAX77541_BIT_BUCK_INT_M2_POK_FLT },54	{ .mask = MAX77541_BIT_BUCK_INT_M1_SCFLT },55	{ .mask = MAX77541_BIT_BUCK_INT_M2_SCFLT },56};57 58static const struct regmap_irq_chip max77541_buck_irq_chip = {59	.name		= "max77541-buck",60	.status_base	= MAX77541_REG_BUCK_INT,61	.mask_base	= MAX77541_REG_BUCK_INT_M,62	.num_regs	= 1,63	.irqs		= max77541_buck_irqs,64	.num_irqs	= ARRAY_SIZE(max77541_buck_irqs),65};66 67static const struct regmap_irq max77541_adc_irqs[] = {68	{ .mask = MAX77541_BIT_ADC_INT_CH1_I },69	{ .mask = MAX77541_BIT_ADC_INT_CH2_I },70	{ .mask = MAX77541_BIT_ADC_INT_CH3_I },71	{ .mask = MAX77541_BIT_ADC_INT_CH6_I },72};73 74static const struct regmap_irq_chip max77541_adc_irq_chip = {75	.name		= "max77541-adc",76	.status_base	= MAX77541_REG_ADC_INT,77	.mask_base	= MAX77541_REG_ADC_INT_M,78	.num_regs	= 1,79	.irqs		= max77541_adc_irqs,80	.num_irqs	= ARRAY_SIZE(max77541_adc_irqs),81};82 83static const struct mfd_cell max77540_devs[] = {84	MFD_CELL_OF("max77540-regulator", NULL, NULL, 0, 0, NULL),85};86 87static const struct mfd_cell max77541_devs[] = {88	MFD_CELL_OF("max77541-regulator", NULL, NULL, 0, 0, NULL),89	MFD_CELL_OF("max77541-adc", NULL, NULL, 0, 0, NULL),90};91 92static int max77541_pmic_irq_init(struct device *dev)93{94	struct max77541 *max77541 = dev_get_drvdata(dev);95	int irq = max77541->i2c->irq;96	int ret;97 98	ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq,99				       IRQF_ONESHOT | IRQF_SHARED, 0,100				       &max77541_src_irq_chip,101				       &max77541->irq_data);102	if (ret)103		return ret;104 105	ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq,106				       IRQF_ONESHOT | IRQF_SHARED, 0,107				       &max77541_topsys_irq_chip,108				       &max77541->irq_topsys);109	if (ret)110		return ret;111 112	ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq,113				       IRQF_ONESHOT | IRQF_SHARED, 0,114				       &max77541_buck_irq_chip,115				       &max77541->irq_buck);116	if (ret)117		return ret;118 119	if (max77541->id == MAX77541) {120		ret = devm_regmap_add_irq_chip(dev, max77541->regmap, irq,121					       IRQF_ONESHOT | IRQF_SHARED, 0,122					       &max77541_adc_irq_chip,123					       &max77541->irq_adc);124		if (ret)125			return ret;126	}127 128	return 0;129}130 131static int max77541_pmic_setup(struct device *dev)132{133	struct max77541 *max77541 = dev_get_drvdata(dev);134	const struct mfd_cell *cells;135	int n_devs;136	int ret;137 138	switch (max77541->id) {139	case MAX77540:140		cells =  max77540_devs;141		n_devs = ARRAY_SIZE(max77540_devs);142		break;143	case MAX77541:144		cells =  max77541_devs;145		n_devs = ARRAY_SIZE(max77541_devs);146		break;147	default:148		return -EINVAL;149	}150 151	ret = max77541_pmic_irq_init(dev);152	if (ret)153		return dev_err_probe(dev, ret, "Failed to initialize IRQ\n");154 155	ret = device_init_wakeup(dev, true);156	if (ret)157		return dev_err_probe(dev, ret, "Unable to init wakeup\n");158 159	return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,160				    cells, n_devs, NULL, 0, NULL);161}162 163static int max77541_probe(struct i2c_client *client)164{165	struct device *dev = &client->dev;166	struct max77541 *max77541;167 168	max77541 = devm_kzalloc(dev, sizeof(*max77541), GFP_KERNEL);169	if (!max77541)170		return -ENOMEM;171 172	i2c_set_clientdata(client, max77541);173	max77541->i2c = client;174 175	max77541->id = (uintptr_t)i2c_get_match_data(client);176	if (!max77541->id)177		return -EINVAL;178 179	max77541->regmap = devm_regmap_init_i2c(client,180						&max77541_regmap_config);181	if (IS_ERR(max77541->regmap))182		return dev_err_probe(dev, PTR_ERR(max77541->regmap),183				     "Failed to allocate register map\n");184 185	return max77541_pmic_setup(dev);186}187 188static const struct of_device_id max77541_of_id[] = {189	{190		.compatible = "adi,max77540",191		.data = (void *)MAX77540,192	},193	{194		.compatible = "adi,max77541",195		.data = (void *)MAX77541,196	},197	{ }198};199MODULE_DEVICE_TABLE(of, max77541_of_id);200 201static const struct i2c_device_id max77541_id[] = {202	{ "max77540", MAX77540 },203	{ "max77541", MAX77541 },204	{ }205};206MODULE_DEVICE_TABLE(i2c, max77541_id);207 208static struct i2c_driver max77541_driver = {209	.driver = {210		.name = "max77541",211		.of_match_table = max77541_of_id,212	},213	.probe = max77541_probe,214	.id_table = max77541_id,215};216module_i2c_driver(max77541_driver);217 218MODULE_DESCRIPTION("MAX7740/MAX7741 Driver");219MODULE_AUTHOR("Okan Sahin <okan.sahin@analog.com>");220MODULE_LICENSE("GPL");221