Skip to content

Commit 480a8ad

Browse files
Haibo Chenlag-linaro
authored andcommitted
mfd: adp5585: Add Analog Devices ADP5585 core support
The ADP5585 is a 10/11 input/output port expander with a built in keypad matrix decoder, programmable logic, reset generator, and PWM generator. This driver supports the chip by modelling it as an MFD device, with two child devices for the GPIO and PWM functions. The driver is derived from an initial implementation from NXP, available in commit 8059835bee19 ("MLK-25917-1 mfd: adp5585: add ADI adp5585 core support") in their BSP kernel tree. It has been extensively rewritten. Signed-off-by: Haibo Chen <[email protected]> Signed-off-by: Laurent Pinchart <[email protected]> Reviewed-by: Frank Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Lee Jones <[email protected]>
1 parent 312fc21 commit 480a8ad

File tree

5 files changed

+346
-0
lines changed

5 files changed

+346
-0
lines changed

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,8 @@ L: [email protected]
543543
544544
S: Maintained
545545
F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml
546+
F: drivers/mfd/adp5585.c
547+
F: include/linux/mfd/adp5585.h
546548

547549
ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
548550
M: Michael Hennerich <[email protected]>

drivers/mfd/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ config MFD_CS5535
2020
This is the core driver for CS5535/CS5536 MFD functions. This is
2121
necessary for using the board's GPIO and MFGPT functionality.
2222

23+
config MFD_ADP5585
24+
tristate "Analog Devices ADP5585 keypad decoder and I/O expander driver"
25+
select MFD_CORE
26+
select REGMAP_I2C
27+
depends on I2C
28+
depends on OF || COMPILE_TEST
29+
help
30+
Say yes here to add support for the Analog Devices ADP5585 GPIO
31+
expander, PWM and keypad controller. This includes the I2C driver and
32+
the core APIs _only_, you have to select individual components like
33+
the GPIO and PWM functions under the corresponding menus.
34+
2335
config MFD_ALTERA_A10SR
2436
bool "Altera Arria10 DevKit System Resource chip"
2537
depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF

drivers/mfd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
193193
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
194194
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
195195
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
196+
obj-$(CONFIG_MFD_ADP5585) += adp5585.o
196197
obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o
197198
obj-$(CONFIG_MFD_INTEL_QUARK_I2C_GPIO) += intel_quark_i2c_gpio.o
198199
obj-$(CONFIG_LPC_SCH) += lpc_sch.o

drivers/mfd/adp5585.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Analog Devices ADP5585 I/O expander, PWM controller and keypad controller
4+
*
5+
* Copyright 2022 NXP
6+
* Copyright 2024 Ideas on Board Oy
7+
*/
8+
9+
#include <linux/array_size.h>
10+
#include <linux/device.h>
11+
#include <linux/err.h>
12+
#include <linux/i2c.h>
13+
#include <linux/mfd/adp5585.h>
14+
#include <linux/mfd/core.h>
15+
#include <linux/mod_devicetable.h>
16+
#include <linux/module.h>
17+
#include <linux/regmap.h>
18+
#include <linux/types.h>
19+
20+
static const struct mfd_cell adp5585_devs[] = {
21+
{ .name = "adp5585-gpio", },
22+
{ .name = "adp5585-pwm", },
23+
};
24+
25+
static const struct regmap_range adp5585_volatile_ranges[] = {
26+
regmap_reg_range(ADP5585_ID, ADP5585_GPI_STATUS_B),
27+
};
28+
29+
static const struct regmap_access_table adp5585_volatile_regs = {
30+
.yes_ranges = adp5585_volatile_ranges,
31+
.n_yes_ranges = ARRAY_SIZE(adp5585_volatile_ranges),
32+
};
33+
34+
/*
35+
* Chip variants differ in the default configuration of pull-up and pull-down
36+
* resistors, and therefore have different default register values:
37+
*
38+
* - The -00, -01 and -03 variants (collectively referred to as
39+
* ADP5585_REGMAP_00) have pull-up on all GPIO pins by default.
40+
* - The -02 variant has no default pull-up or pull-down resistors.
41+
* - The -04 variant has default pull-down resistors on all GPIO pins.
42+
*/
43+
44+
static const u8 adp5585_regmap_defaults_00[ADP5585_MAX_REG + 1] = {
45+
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46+
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47+
/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48+
/* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49+
/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50+
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51+
/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52+
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00,
53+
};
54+
55+
static const u8 adp5585_regmap_defaults_02[ADP5585_MAX_REG + 1] = {
56+
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57+
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58+
/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3,
59+
/* 0x18 */ 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
60+
/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61+
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62+
/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63+
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00,
64+
};
65+
66+
static const u8 adp5585_regmap_defaults_04[ADP5585_MAX_REG + 1] = {
67+
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68+
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69+
/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
70+
/* 0x18 */ 0x05, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
71+
/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72+
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73+
/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74+
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00,
75+
};
76+
77+
enum adp5585_regmap_type {
78+
ADP5585_REGMAP_00,
79+
ADP5585_REGMAP_02,
80+
ADP5585_REGMAP_04,
81+
};
82+
83+
static const struct regmap_config adp5585_regmap_configs[] = {
84+
[ADP5585_REGMAP_00] = {
85+
.reg_bits = 8,
86+
.val_bits = 8,
87+
.max_register = ADP5585_MAX_REG,
88+
.volatile_table = &adp5585_volatile_regs,
89+
.cache_type = REGCACHE_MAPLE,
90+
.reg_defaults_raw = adp5585_regmap_defaults_00,
91+
.num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_00),
92+
},
93+
[ADP5585_REGMAP_02] = {
94+
.reg_bits = 8,
95+
.val_bits = 8,
96+
.max_register = ADP5585_MAX_REG,
97+
.volatile_table = &adp5585_volatile_regs,
98+
.cache_type = REGCACHE_MAPLE,
99+
.reg_defaults_raw = adp5585_regmap_defaults_02,
100+
.num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_02),
101+
},
102+
[ADP5585_REGMAP_04] = {
103+
.reg_bits = 8,
104+
.val_bits = 8,
105+
.max_register = ADP5585_MAX_REG,
106+
.volatile_table = &adp5585_volatile_regs,
107+
.cache_type = REGCACHE_MAPLE,
108+
.reg_defaults_raw = adp5585_regmap_defaults_04,
109+
.num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_04),
110+
},
111+
};
112+
113+
static int adp5585_i2c_probe(struct i2c_client *i2c)
114+
{
115+
const struct regmap_config *regmap_config;
116+
struct adp5585_dev *adp5585;
117+
unsigned int id;
118+
int ret;
119+
120+
adp5585 = devm_kzalloc(&i2c->dev, sizeof(*adp5585), GFP_KERNEL);
121+
if (!adp5585)
122+
return -ENOMEM;
123+
124+
i2c_set_clientdata(i2c, adp5585);
125+
126+
regmap_config = i2c_get_match_data(i2c);
127+
adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config);
128+
if (IS_ERR(adp5585->regmap))
129+
return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap),
130+
"Failed to initialize register map\n");
131+
132+
ret = regmap_read(adp5585->regmap, ADP5585_ID, &id);
133+
if (ret)
134+
return dev_err_probe(&i2c->dev, ret,
135+
"Failed to read device ID\n");
136+
137+
if ((id & ADP5585_MAN_ID_MASK) != ADP5585_MAN_ID_VALUE)
138+
return dev_err_probe(&i2c->dev, -ENODEV,
139+
"Invalid device ID 0x%02x\n", id);
140+
141+
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
142+
adp5585_devs, ARRAY_SIZE(adp5585_devs),
143+
NULL, 0, NULL);
144+
if (ret)
145+
return dev_err_probe(&i2c->dev, ret,
146+
"Failed to add child devices\n");
147+
148+
return 0;
149+
}
150+
151+
static int adp5585_suspend(struct device *dev)
152+
{
153+
struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
154+
155+
regcache_cache_only(adp5585->regmap, true);
156+
157+
return 0;
158+
}
159+
160+
static int adp5585_resume(struct device *dev)
161+
{
162+
struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
163+
164+
regcache_cache_only(adp5585->regmap, false);
165+
regcache_mark_dirty(adp5585->regmap);
166+
167+
return regcache_sync(adp5585->regmap);
168+
}
169+
170+
static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume);
171+
172+
static const struct of_device_id adp5585_of_match[] = {
173+
{
174+
.compatible = "adi,adp5585-00",
175+
.data = &adp5585_regmap_configs[ADP5585_REGMAP_00],
176+
}, {
177+
.compatible = "adi,adp5585-01",
178+
.data = &adp5585_regmap_configs[ADP5585_REGMAP_00],
179+
}, {
180+
.compatible = "adi,adp5585-02",
181+
.data = &adp5585_regmap_configs[ADP5585_REGMAP_02],
182+
}, {
183+
.compatible = "adi,adp5585-03",
184+
.data = &adp5585_regmap_configs[ADP5585_REGMAP_00],
185+
}, {
186+
.compatible = "adi,adp5585-04",
187+
.data = &adp5585_regmap_configs[ADP5585_REGMAP_04],
188+
},
189+
{ /* sentinel */ }
190+
};
191+
MODULE_DEVICE_TABLE(of, adp5585_of_match);
192+
193+
static struct i2c_driver adp5585_i2c_driver = {
194+
.driver = {
195+
.name = "adp5585",
196+
.of_match_table = adp5585_of_match,
197+
.pm = pm_sleep_ptr(&adp5585_pm),
198+
},
199+
.probe = adp5585_i2c_probe,
200+
};
201+
module_i2c_driver(adp5585_i2c_driver);
202+
203+
MODULE_DESCRIPTION("ADP5585 core driver");
204+
MODULE_AUTHOR("Haibo Chen <[email protected]>");
205+
MODULE_LICENSE("GPL");

include/linux/mfd/adp5585.h

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Analog Devices ADP5585 I/O expander, PWM controller and keypad controller
4+
*
5+
* Copyright 2022 NXP
6+
* Copyright 2024 Ideas on Board Oy
7+
*/
8+
9+
#ifndef __MFD_ADP5585_H_
10+
#define __MFD_ADP5585_H_
11+
12+
#include <linux/bits.h>
13+
14+
#define ADP5585_ID 0x00
15+
#define ADP5585_MAN_ID_VALUE 0x20
16+
#define ADP5585_MAN_ID_MASK GENMASK(7, 4)
17+
#define ADP5585_INT_STATUS 0x01
18+
#define ADP5585_STATUS 0x02
19+
#define ADP5585_FIFO_1 0x03
20+
#define ADP5585_FIFO_2 0x04
21+
#define ADP5585_FIFO_3 0x05
22+
#define ADP5585_FIFO_4 0x06
23+
#define ADP5585_FIFO_5 0x07
24+
#define ADP5585_FIFO_6 0x08
25+
#define ADP5585_FIFO_7 0x09
26+
#define ADP5585_FIFO_8 0x0a
27+
#define ADP5585_FIFO_9 0x0b
28+
#define ADP5585_FIFO_10 0x0c
29+
#define ADP5585_FIFO_11 0x0d
30+
#define ADP5585_FIFO_12 0x0e
31+
#define ADP5585_FIFO_13 0x0f
32+
#define ADP5585_FIFO_14 0x10
33+
#define ADP5585_FIFO_15 0x11
34+
#define ADP5585_FIFO_16 0x12
35+
#define ADP5585_GPI_INT_STAT_A 0x13
36+
#define ADP5585_GPI_INT_STAT_B 0x14
37+
#define ADP5585_GPI_STATUS_A 0x15
38+
#define ADP5585_GPI_STATUS_B 0x16
39+
#define ADP5585_RPULL_CONFIG_A 0x17
40+
#define ADP5585_RPULL_CONFIG_B 0x18
41+
#define ADP5585_RPULL_CONFIG_C 0x19
42+
#define ADP5585_RPULL_CONFIG_D 0x1a
43+
#define ADP5585_Rx_PULL_CFG_PU_300K 0
44+
#define ADP5585_Rx_PULL_CFG_PD_300K 1
45+
#define ADP5585_Rx_PULL_CFG_PU_100K 2
46+
#define ADP5585_Rx_PULL_CFG_DISABLE 3
47+
#define ADP5585_Rx_PULL_CFG_MASK 3
48+
#define ADP5585_GPI_INT_LEVEL_A 0x1b
49+
#define ADP5585_GPI_INT_LEVEL_B 0x1c
50+
#define ADP5585_GPI_EVENT_EN_A 0x1d
51+
#define ADP5585_GPI_EVENT_EN_B 0x1e
52+
#define ADP5585_GPI_INTERRUPT_EN_A 0x1f
53+
#define ADP5585_GPI_INTERRUPT_EN_B 0x20
54+
#define ADP5585_DEBOUNCE_DIS_A 0x21
55+
#define ADP5585_DEBOUNCE_DIS_B 0x22
56+
#define ADP5585_GPO_DATA_OUT_A 0x23
57+
#define ADP5585_GPO_DATA_OUT_B 0x24
58+
#define ADP5585_GPO_OUT_MODE_A 0x25
59+
#define ADP5585_GPO_OUT_MODE_B 0x26
60+
#define ADP5585_GPIO_DIRECTION_A 0x27
61+
#define ADP5585_GPIO_DIRECTION_B 0x28
62+
#define ADP5585_RESET1_EVENT_A 0x29
63+
#define ADP5585_RESET1_EVENT_B 0x2a
64+
#define ADP5585_RESET1_EVENT_C 0x2b
65+
#define ADP5585_RESET2_EVENT_A 0x2c
66+
#define ADP5585_RESET2_EVENT_B 0x2d
67+
#define ADP5585_RESET_CFG 0x2e
68+
#define ADP5585_PWM_OFFT_LOW 0x2f
69+
#define ADP5585_PWM_OFFT_HIGH 0x30
70+
#define ADP5585_PWM_ONT_LOW 0x31
71+
#define ADP5585_PWM_ONT_HIGH 0x32
72+
#define ADP5585_PWM_CFG 0x33
73+
#define ADP5585_PWM_IN_AND BIT(2)
74+
#define ADP5585_PWM_MODE BIT(1)
75+
#define ADP5585_PWM_EN BIT(0)
76+
#define ADP5585_LOGIC_CFG 0x34
77+
#define ADP5585_LOGIC_FF_CFG 0x35
78+
#define ADP5585_LOGIC_INT_EVENT_EN 0x36
79+
#define ADP5585_POLL_PTIME_CFG 0x37
80+
#define ADP5585_PIN_CONFIG_A 0x38
81+
#define ADP5585_PIN_CONFIG_B 0x39
82+
#define ADP5585_PIN_CONFIG_C 0x3a
83+
#define ADP5585_PULL_SELECT BIT(7)
84+
#define ADP5585_C4_EXTEND_CFG_GPIO11 (0U << 6)
85+
#define ADP5585_C4_EXTEND_CFG_RESET2 (1U << 6)
86+
#define ADP5585_C4_EXTEND_CFG_MASK GENMASK(6, 6)
87+
#define ADP5585_R4_EXTEND_CFG_GPIO5 (0U << 5)
88+
#define ADP5585_R4_EXTEND_CFG_RESET1 (1U << 5)
89+
#define ADP5585_R4_EXTEND_CFG_MASK GENMASK(5, 5)
90+
#define ADP5585_R3_EXTEND_CFG_GPIO4 (0U << 2)
91+
#define ADP5585_R3_EXTEND_CFG_LC (1U << 2)
92+
#define ADP5585_R3_EXTEND_CFG_PWM_OUT (2U << 2)
93+
#define ADP5585_R3_EXTEND_CFG_MASK GENMASK(3, 2)
94+
#define ADP5585_R0_EXTEND_CFG_GPIO1 (0U << 0)
95+
#define ADP5585_R0_EXTEND_CFG_LY (1U << 0)
96+
#define ADP5585_R0_EXTEND_CFG_MASK GENMASK(0, 0)
97+
#define ADP5585_GENERAL_CFG 0x3b
98+
#define ADP5585_OSC_EN BIT(7)
99+
#define ADP5585_OSC_FREQ_50KHZ (0U << 5)
100+
#define ADP5585_OSC_FREQ_100KHZ (1U << 5)
101+
#define ADP5585_OSC_FREQ_200KHZ (2U << 5)
102+
#define ADP5585_OSC_FREQ_500KHZ (3U << 5)
103+
#define ADP5585_OSC_FREQ_MASK GENMASK(6, 5)
104+
#define ADP5585_INT_CFG BIT(1)
105+
#define ADP5585_RST_CFG BIT(0)
106+
#define ADP5585_INT_EN 0x3c
107+
108+
#define ADP5585_MAX_REG ADP5585_INT_EN
109+
110+
/*
111+
* Bank 0 covers pins "GPIO 1/R0" to "GPIO 6/R5", numbered 0 to 5 by the
112+
* driver, and bank 1 covers pins "GPIO 7/C0" to "GPIO 11/C4", numbered 6 to
113+
* 10. Some variants of the ADP5585 don't support "GPIO 6/R5". As the driver
114+
* uses identical GPIO numbering for all variants to avoid confusion, GPIO 5 is
115+
* marked as reserved in the device tree for variants that don't support it.
116+
*/
117+
#define ADP5585_BANK(n) ((n) >= 6 ? 1 : 0)
118+
#define ADP5585_BIT(n) ((n) >= 6 ? BIT((n) - 6) : BIT(n))
119+
120+
struct regmap;
121+
122+
struct adp5585_dev {
123+
struct regmap *regmap;
124+
};
125+
126+
#endif

0 commit comments

Comments
 (0)