Skip to content

Commit 47a1f75

Browse files
nunojsalag-linaro
authored andcommitted
mfd: adp5585: Add support for event handling
These devices are capable of generate FIFO based events based on KEY or GPI presses. Add support for handling these events. This is in preparation of adding full support for keymap and gpis based events. Reviewed-by: Lee Jones <lee@kernel.org> Signed-off-by: Nuno Sá <nuno.sa@analog.com> Link: https://lore.kernel.org/r/20250701-dev-adp5589-fw-v7-12-b1fcfe9e9826@analog.com Signed-off-by: Lee Jones <lee@kernel.org>
1 parent adf4932 commit 47a1f75

2 files changed

Lines changed: 186 additions & 8 deletions

File tree

drivers/mfd/adp5585.c

Lines changed: 168 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <linux/array_size.h>
11+
#include <linux/bitfield.h>
1112
#include <linux/device.h>
1213
#include <linux/err.h>
1314
#include <linux/i2c.h>
@@ -165,10 +166,16 @@ static const struct regmap_config adp5589_regmap_config_template = {
165166

166167
static const struct adp5585_regs adp5585_regs = {
167168
.ext_cfg = ADP5585_PIN_CONFIG_C,
169+
.int_en = ADP5585_INT_EN,
170+
.gen_cfg = ADP5585_GENERAL_CFG,
171+
.poll_ptime_cfg = ADP5585_POLL_PTIME_CFG,
168172
};
169173

170174
static const struct adp5585_regs adp5589_regs = {
171175
.ext_cfg = ADP5589_PIN_CONFIG_D,
176+
.int_en = ADP5589_INT_EN,
177+
.gen_cfg = ADP5589_GENERAL_CFG,
178+
.poll_ptime_cfg = ADP5589_POLL_PTIME_CFG,
172179
};
173180

174181
static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp5585)
@@ -241,6 +248,146 @@ static void adp5585_osc_disable(void *data)
241248
regmap_write(adp5585->regmap, ADP5585_GENERAL_CFG, 0);
242249
}
243250

251+
static void adp5585_report_events(struct adp5585_dev *adp5585, int ev_cnt)
252+
{
253+
unsigned int i;
254+
255+
for (i = 0; i < ev_cnt; i++) {
256+
unsigned long key_val, key_press;
257+
unsigned int key;
258+
int ret;
259+
260+
ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &key);
261+
if (ret)
262+
return;
263+
264+
key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key);
265+
key_press = FIELD_GET(ADP5585_KEV_EV_PRESS_MASK, key);
266+
267+
blocking_notifier_call_chain(&adp5585->event_notifier, key_val, (void *)key_press);
268+
}
269+
}
270+
271+
static irqreturn_t adp5585_irq(int irq, void *data)
272+
{
273+
struct adp5585_dev *adp5585 = data;
274+
unsigned int status, ev_cnt;
275+
int ret;
276+
277+
ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &status);
278+
if (ret)
279+
return IRQ_HANDLED;
280+
281+
if (status & ADP5585_OVRFLOW_INT)
282+
dev_err_ratelimited(adp5585->dev, "Event overflow error\n");
283+
284+
if (!(status & ADP5585_EVENT_INT))
285+
goto out_irq;
286+
287+
ret = regmap_read(adp5585->regmap, ADP5585_STATUS, &ev_cnt);
288+
if (ret)
289+
goto out_irq;
290+
291+
ev_cnt = FIELD_GET(ADP5585_EC_MASK, ev_cnt);
292+
if (!ev_cnt)
293+
goto out_irq;
294+
295+
adp5585_report_events(adp5585, ev_cnt);
296+
out_irq:
297+
regmap_write(adp5585->regmap, ADP5585_INT_STATUS, status);
298+
return IRQ_HANDLED;
299+
}
300+
301+
static int adp5585_setup(struct adp5585_dev *adp5585)
302+
{
303+
const struct adp5585_regs *regs = adp5585->regs;
304+
unsigned int reg_val, i;
305+
int ret;
306+
307+
/* Clear any possible event by reading all the FIFO entries */
308+
for (i = 0; i < ADP5585_EV_MAX; i++) {
309+
ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &reg_val);
310+
if (ret)
311+
return ret;
312+
}
313+
314+
ret = regmap_write(adp5585->regmap, regs->poll_ptime_cfg, adp5585->ev_poll_time);
315+
if (ret)
316+
return ret;
317+
318+
/*
319+
* Enable the internal oscillator, as it's shared between multiple
320+
* functions.
321+
*/
322+
ret = regmap_write(adp5585->regmap, regs->gen_cfg,
323+
ADP5585_OSC_FREQ_500KHZ | ADP5585_INT_CFG | ADP5585_OSC_EN);
324+
if (ret)
325+
return ret;
326+
327+
return devm_add_action_or_reset(adp5585->dev, adp5585_osc_disable, adp5585);
328+
}
329+
330+
static int adp5585_parse_fw(struct adp5585_dev *adp5585)
331+
{
332+
unsigned int prop_val;
333+
int ret;
334+
335+
ret = device_property_read_u32(adp5585->dev, "poll-interval", &prop_val);
336+
if (!ret) {
337+
adp5585->ev_poll_time = prop_val / 10 - 1;
338+
/*
339+
* ev_poll_time is the raw value to be written on the register and 0 to 3 are the
340+
* valid values.
341+
*/
342+
if (adp5585->ev_poll_time > 3)
343+
return dev_err_probe(adp5585->dev, -EINVAL,
344+
"Invalid value(%u) for poll-interval\n", prop_val);
345+
}
346+
347+
return 0;
348+
}
349+
350+
static void adp5585_irq_disable(void *data)
351+
{
352+
struct adp5585_dev *adp5585 = data;
353+
354+
regmap_write(adp5585->regmap, adp5585->regs->int_en, 0);
355+
}
356+
357+
static int adp5585_irq_enable(struct i2c_client *i2c,
358+
struct adp5585_dev *adp5585)
359+
{
360+
const struct adp5585_regs *regs = adp5585->regs;
361+
unsigned int stat;
362+
int ret;
363+
364+
if (i2c->irq <= 0)
365+
return 0;
366+
367+
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, adp5585_irq,
368+
IRQF_ONESHOT, i2c->name, adp5585);
369+
if (ret)
370+
return ret;
371+
372+
/*
373+
* Clear any possible outstanding interrupt before enabling them. We do that by reading
374+
* the status register and writing back the same value.
375+
*/
376+
ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &stat);
377+
if (ret)
378+
return ret;
379+
380+
ret = regmap_write(adp5585->regmap, ADP5585_INT_STATUS, stat);
381+
if (ret)
382+
return ret;
383+
384+
ret = regmap_write(adp5585->regmap, regs->int_en, ADP5585_OVRFLOW_IEN | ADP5585_EVENT_IEN);
385+
if (ret)
386+
return ret;
387+
388+
return devm_add_action_or_reset(&i2c->dev, adp5585_irq_disable, adp5585);
389+
}
390+
244391
static int adp5585_i2c_probe(struct i2c_client *i2c)
245392
{
246393
struct regmap_config *regmap_config;
@@ -254,6 +401,8 @@ static int adp5585_i2c_probe(struct i2c_client *i2c)
254401

255402
i2c_set_clientdata(i2c, adp5585);
256403
adp5585->dev = &i2c->dev;
404+
adp5585->irq = i2c->irq;
405+
BLOCKING_INIT_NOTIFIER_HEAD(&adp5585->event_notifier);
257406

258407
adp5585->variant = (enum adp5585_variant)(uintptr_t)i2c_get_match_data(i2c);
259408
if (!adp5585->variant)
@@ -278,25 +427,28 @@ static int adp5585_i2c_probe(struct i2c_client *i2c)
278427
return dev_err_probe(&i2c->dev, -ENODEV,
279428
"Invalid device ID 0x%02x\n", id);
280429

281-
/*
282-
* Enable the internal oscillator, as it's shared between multiple
283-
* functions.
284-
*/
285-
ret = regmap_set_bits(adp5585->regmap, ADP5585_GENERAL_CFG, ADP5585_OSC_EN);
430+
ret = adp5585_parse_fw(adp5585);
286431
if (ret)
287432
return ret;
288433

289-
ret = devm_add_action_or_reset(&i2c->dev, adp5585_osc_disable, adp5585);
434+
ret = adp5585_setup(adp5585);
290435
if (ret)
291436
return ret;
292437

293-
return adp5585_add_devices(adp5585);
438+
ret = adp5585_add_devices(adp5585);
439+
if (ret)
440+
return ret;
441+
442+
return adp5585_irq_enable(i2c, adp5585);
294443
}
295444

296445
static int adp5585_suspend(struct device *dev)
297446
{
298447
struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
299448

449+
if (adp5585->irq)
450+
disable_irq(adp5585->irq);
451+
300452
regcache_cache_only(adp5585->regmap, true);
301453

302454
return 0;
@@ -305,11 +457,19 @@ static int adp5585_suspend(struct device *dev)
305457
static int adp5585_resume(struct device *dev)
306458
{
307459
struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
460+
int ret;
308461

309462
regcache_cache_only(adp5585->regmap, false);
310463
regcache_mark_dirty(adp5585->regmap);
311464

312-
return regcache_sync(adp5585->regmap);
465+
ret = regcache_sync(adp5585->regmap);
466+
if (ret)
467+
return ret;
468+
469+
if (adp5585->irq)
470+
enable_irq(adp5585->irq);
471+
472+
return 0;
313473
}
314474

315475
static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume);

include/linux/mfd/adp5585.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,20 @@
1010
#define __MFD_ADP5585_H_
1111

1212
#include <linux/bits.h>
13+
#include <linux/notifier.h>
1314

1415
#define ADP5585_ID 0x00
1516
#define ADP5585_MAN_ID_VALUE 0x20
1617
#define ADP5585_MAN_ID_MASK GENMASK(7, 4)
18+
#define ADP5585_REV_ID_MASK GENMASK(3, 0)
1719
#define ADP5585_INT_STATUS 0x01
20+
#define ADP5585_OVRFLOW_INT BIT(2)
21+
#define ADP5585_EVENT_INT BIT(0)
1822
#define ADP5585_STATUS 0x02
23+
#define ADP5585_EC_MASK GENMASK(4, 0)
1924
#define ADP5585_FIFO_1 0x03
25+
#define ADP5585_KEV_EV_PRESS_MASK BIT(7)
26+
#define ADP5585_KEY_EVENT_MASK GENMASK(6, 0)
2027
#define ADP5585_FIFO_2 0x04
2128
#define ADP5585_FIFO_3 0x05
2229
#define ADP5585_FIFO_4 0x06
@@ -32,6 +39,7 @@
3239
#define ADP5585_FIFO_14 0x10
3340
#define ADP5585_FIFO_15 0x11
3441
#define ADP5585_FIFO_16 0x12
42+
#define ADP5585_EV_MAX (ADP5585_FIFO_16 - ADP5585_FIFO_1 + 1)
3543
#define ADP5585_GPI_INT_STAT_A 0x13
3644
#define ADP5585_GPI_INT_STAT_B 0x14
3745
#define ADP5585_GPI_STATUS_A 0x15
@@ -104,6 +112,8 @@
104112
#define ADP5585_INT_CFG BIT(1)
105113
#define ADP5585_RST_CFG BIT(0)
106114
#define ADP5585_INT_EN 0x3c
115+
#define ADP5585_OVRFLOW_IEN BIT(2)
116+
#define ADP5585_EVENT_IEN BIT(0)
107117

108118
#define ADP5585_MAX_REG ADP5585_INT_EN
109119

@@ -121,7 +131,9 @@
121131
#define ADP5589_PWM_OFFT_LOW 0x3e
122132
#define ADP5589_PWM_ONT_LOW 0x40
123133
#define ADP5589_PWM_CFG 0x42
134+
#define ADP5589_POLL_PTIME_CFG 0x48
124135
#define ADP5589_PIN_CONFIG_D 0x4C
136+
#define ADP5589_GENERAL_CFG 0x4d
125137
#define ADP5589_INT_EN 0x4e
126138
#define ADP5589_MAX_REG ADP5589_INT_EN
127139

@@ -142,15 +154,21 @@ enum adp5585_variant {
142154
};
143155

144156
struct adp5585_regs {
157+
unsigned int gen_cfg;
145158
unsigned int ext_cfg;
159+
unsigned int int_en;
160+
unsigned int poll_ptime_cfg;
146161
};
147162

148163
struct adp5585_dev {
149164
struct device *dev;
150165
struct regmap *regmap;
151166
const struct adp5585_regs *regs;
167+
struct blocking_notifier_head event_notifier;
152168
enum adp5585_variant variant;
153169
unsigned int id;
170+
int irq;
171+
unsigned int ev_poll_time;
154172
};
155173

156174
#endif

0 commit comments

Comments
 (0)