Skip to content

Commit e0cbc20

Browse files
oknshnlag-linaro
authored andcommitted
mfd: max77541: Add ADI MAX77541/MAX77540 PMIC Support
MFD driver for MAX77541/MAX77540 to enable its sub devices. The MAX77541 is a multi-function devices. It includes buck converter and ADC. The MAX77540 is a high-efficiency buck converter with two 3A switching phases. They have same regmap except for ADC part of MAX77541. Signed-off-by: Okan Sahin <okan.sahin@analog.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20230412111256.40013-6-okan.sahin@analog.com Signed-off-by: Lee Jones <lee@kernel.org>
1 parent 9a096a8 commit e0cbc20

4 files changed

Lines changed: 329 additions & 0 deletions

File tree

drivers/mfd/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,19 @@ config MFD_MAX14577
784784
additional drivers must be enabled in order to use the functionality
785785
of the device.
786786

787+
config MFD_MAX77541
788+
tristate "Analog Devices MAX77541/77540 PMIC Support"
789+
depends on I2C=y
790+
select MFD_CORE
791+
select REGMAP_I2C
792+
select REGMAP_IRQ
793+
help
794+
Say yes here to add support for Analog Devices MAX77541 and
795+
MAX77540 Power Management ICs. This driver provides
796+
common support for accessing the device; additional drivers
797+
must be enabled in order to use the functionality of the device.
798+
There are regulators and adc.
799+
787800
config MFD_MAX77620
788801
bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
789802
depends on I2C=y

drivers/mfd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o
154154
obj-$(CONFIG_MFD_DA9150) += da9150-core.o
155155

156156
obj-$(CONFIG_MFD_MAX14577) += max14577.o
157+
obj-$(CONFIG_MFD_MAX77541) += max77541.o
157158
obj-$(CONFIG_MFD_MAX77620) += max77620.o
158159
obj-$(CONFIG_MFD_MAX77650) += max77650.o
159160
obj-$(CONFIG_MFD_MAX77686) += max77686.o

drivers/mfd/max77541.c

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2022 Analog Devices, Inc.
4+
* Driver for the MAX77540 and MAX77541
5+
*/
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+
14+
static const struct regmap_config max77541_regmap_config = {
15+
.reg_bits = 8,
16+
.val_bits = 8,
17+
};
18+
19+
static const struct regmap_irq max77541_src_irqs[] = {
20+
{ .mask = MAX77541_BIT_INT_SRC_TOPSYS },
21+
{ .mask = MAX77541_BIT_INT_SRC_BUCK },
22+
};
23+
24+
static 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+
33+
static 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+
42+
static 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+
51+
static 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+
58+
static 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+
67+
static 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+
74+
static 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+
83+
static const struct mfd_cell max77540_devs[] = {
84+
MFD_CELL_OF("max77540-regulator", NULL, NULL, 0, 0, NULL),
85+
};
86+
87+
static 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+
92+
static 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+
131+
static 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+
163+
static int max77541_probe(struct i2c_client *client)
164+
{
165+
const struct i2c_device_id *id = i2c_client_get_device_id(client);
166+
struct device *dev = &client->dev;
167+
struct max77541 *max77541;
168+
169+
max77541 = devm_kzalloc(dev, sizeof(*max77541), GFP_KERNEL);
170+
if (!max77541)
171+
return -ENOMEM;
172+
173+
i2c_set_clientdata(client, max77541);
174+
max77541->i2c = client;
175+
176+
max77541->id = (enum max7754x_ids)device_get_match_data(dev);
177+
if (!max77541->id)
178+
max77541->id = (enum max7754x_ids)id->driver_data;
179+
180+
if (!max77541->id)
181+
return -EINVAL;
182+
183+
max77541->regmap = devm_regmap_init_i2c(client,
184+
&max77541_regmap_config);
185+
if (IS_ERR(max77541->regmap))
186+
return dev_err_probe(dev, PTR_ERR(max77541->regmap),
187+
"Failed to allocate register map\n");
188+
189+
return max77541_pmic_setup(dev);
190+
}
191+
192+
static const struct of_device_id max77541_of_id[] = {
193+
{
194+
.compatible = "adi,max77540",
195+
.data = (void *)MAX77540,
196+
},
197+
{
198+
.compatible = "adi,max77541",
199+
.data = (void *)MAX77541,
200+
},
201+
{ }
202+
};
203+
MODULE_DEVICE_TABLE(of, max77541_of_id);
204+
205+
static const struct i2c_device_id max77541_id[] = {
206+
{ "max77540", MAX77540 },
207+
{ "max77541", MAX77541 },
208+
{ }
209+
};
210+
MODULE_DEVICE_TABLE(i2c, max77541_id);
211+
212+
static struct i2c_driver max77541_driver = {
213+
.driver = {
214+
.name = "max77541",
215+
.of_match_table = max77541_of_id,
216+
},
217+
.probe_new = max77541_probe,
218+
.id_table = max77541_id,
219+
};
220+
module_i2c_driver(max77541_driver);
221+
222+
MODULE_DESCRIPTION("MAX7740/MAX7741 Driver");
223+
MODULE_AUTHOR("Okan Sahin <okan.sahin@analog.com>");
224+
MODULE_LICENSE("GPL");

include/linux/mfd/max77541.h

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
3+
#ifndef __MFD_MAX77541_H
4+
#define __MFD_MAX77541_H
5+
6+
#include <linux/bits.h>
7+
#include <linux/types.h>
8+
9+
/* REGISTERS */
10+
#define MAX77541_REG_INT_SRC 0x00
11+
#define MAX77541_REG_INT_SRC_M 0x01
12+
13+
#define MAX77541_BIT_INT_SRC_TOPSYS BIT(0)
14+
#define MAX77541_BIT_INT_SRC_BUCK BIT(1)
15+
16+
#define MAX77541_REG_TOPSYS_INT 0x02
17+
#define MAX77541_REG_TOPSYS_INT_M 0x03
18+
19+
#define MAX77541_BIT_TOPSYS_INT_TJ_120C BIT(0)
20+
#define MAX77541_BIT_TOPSYS_INT_TJ_140C BIT(1)
21+
#define MAX77541_BIT_TOPSYS_INT_TSHDN BIT(2)
22+
#define MAX77541_BIT_TOPSYS_INT_UVLO BIT(3)
23+
#define MAX77541_BIT_TOPSYS_INT_ALT_SWO BIT(4)
24+
#define MAX77541_BIT_TOPSYS_INT_EXT_FREQ_DET BIT(5)
25+
26+
/* REGULATORS */
27+
#define MAX77541_REG_BUCK_INT 0x20
28+
#define MAX77541_REG_BUCK_INT_M 0x21
29+
30+
#define MAX77541_BIT_BUCK_INT_M1_POK_FLT BIT(0)
31+
#define MAX77541_BIT_BUCK_INT_M2_POK_FLT BIT(1)
32+
#define MAX77541_BIT_BUCK_INT_M1_SCFLT BIT(4)
33+
#define MAX77541_BIT_BUCK_INT_M2_SCFLT BIT(5)
34+
35+
#define MAX77541_REG_EN_CTRL 0x0B
36+
37+
#define MAX77541_BIT_M1_EN BIT(0)
38+
#define MAX77541_BIT_M2_EN BIT(1)
39+
40+
#define MAX77541_REG_M1_VOUT 0x23
41+
#define MAX77541_REG_M2_VOUT 0x33
42+
43+
#define MAX77541_BITS_MX_VOUT GENMASK(7, 0)
44+
45+
#define MAX77541_REG_M1_CFG1 0x25
46+
#define MAX77541_REG_M2_CFG1 0x35
47+
48+
#define MAX77541_BITS_MX_CFG1_RNG GENMASK(7, 6)
49+
50+
/* ADC */
51+
#define MAX77541_REG_ADC_INT 0x70
52+
#define MAX77541_REG_ADC_INT_M 0x71
53+
54+
#define MAX77541_BIT_ADC_INT_CH1_I BIT(0)
55+
#define MAX77541_BIT_ADC_INT_CH2_I BIT(1)
56+
#define MAX77541_BIT_ADC_INT_CH3_I BIT(2)
57+
#define MAX77541_BIT_ADC_INT_CH6_I BIT(5)
58+
59+
#define MAX77541_REG_ADC_DATA_CH1 0x72
60+
#define MAX77541_REG_ADC_DATA_CH2 0x73
61+
#define MAX77541_REG_ADC_DATA_CH3 0x74
62+
#define MAX77541_REG_ADC_DATA_CH6 0x77
63+
64+
/* INTERRUPT MASKS*/
65+
#define MAX77541_REG_INT_SRC_MASK 0x00
66+
#define MAX77541_REG_TOPSYS_INT_MASK 0x00
67+
#define MAX77541_REG_BUCK_INT_MASK 0x00
68+
69+
#define MAX77541_MAX_REGULATORS 2
70+
71+
enum max7754x_ids {
72+
MAX77540 = 1,
73+
MAX77541,
74+
};
75+
76+
struct regmap;
77+
struct regmap_irq_chip_data;
78+
struct i2c_client;
79+
80+
struct max77541 {
81+
struct i2c_client *i2c;
82+
struct regmap *regmap;
83+
enum max7754x_ids id;
84+
85+
struct regmap_irq_chip_data *irq_data;
86+
struct regmap_irq_chip_data *irq_buck;
87+
struct regmap_irq_chip_data *irq_topsys;
88+
struct regmap_irq_chip_data *irq_adc;
89+
};
90+
91+
#endif /* __MFD_MAX77541_H */

0 commit comments

Comments
 (0)