Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Nuno Sá and committed by
Lee Jones
47a1f759 adf4932b

+186 -8
+168 -8
drivers/mfd/adp5585.c
··· 8 8 */ 9 9 10 10 #include <linux/array_size.h> 11 + #include <linux/bitfield.h> 11 12 #include <linux/device.h> 12 13 #include <linux/err.h> 13 14 #include <linux/i2c.h> ··· 166 165 167 166 static const struct adp5585_regs adp5585_regs = { 168 167 .ext_cfg = ADP5585_PIN_CONFIG_C, 168 + .int_en = ADP5585_INT_EN, 169 + .gen_cfg = ADP5585_GENERAL_CFG, 170 + .poll_ptime_cfg = ADP5585_POLL_PTIME_CFG, 169 171 }; 170 172 171 173 static const struct adp5585_regs adp5589_regs = { 172 174 .ext_cfg = ADP5589_PIN_CONFIG_D, 175 + .int_en = ADP5589_INT_EN, 176 + .gen_cfg = ADP5589_GENERAL_CFG, 177 + .poll_ptime_cfg = ADP5589_POLL_PTIME_CFG, 173 178 }; 174 179 175 180 static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp5585) ··· 248 241 regmap_write(adp5585->regmap, ADP5585_GENERAL_CFG, 0); 249 242 } 250 243 244 + static void adp5585_report_events(struct adp5585_dev *adp5585, int ev_cnt) 245 + { 246 + unsigned int i; 247 + 248 + for (i = 0; i < ev_cnt; i++) { 249 + unsigned long key_val, key_press; 250 + unsigned int key; 251 + int ret; 252 + 253 + ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &key); 254 + if (ret) 255 + return; 256 + 257 + key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key); 258 + key_press = FIELD_GET(ADP5585_KEV_EV_PRESS_MASK, key); 259 + 260 + blocking_notifier_call_chain(&adp5585->event_notifier, key_val, (void *)key_press); 261 + } 262 + } 263 + 264 + static irqreturn_t adp5585_irq(int irq, void *data) 265 + { 266 + struct adp5585_dev *adp5585 = data; 267 + unsigned int status, ev_cnt; 268 + int ret; 269 + 270 + ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &status); 271 + if (ret) 272 + return IRQ_HANDLED; 273 + 274 + if (status & ADP5585_OVRFLOW_INT) 275 + dev_err_ratelimited(adp5585->dev, "Event overflow error\n"); 276 + 277 + if (!(status & ADP5585_EVENT_INT)) 278 + goto out_irq; 279 + 280 + ret = regmap_read(adp5585->regmap, ADP5585_STATUS, &ev_cnt); 281 + if (ret) 282 + goto out_irq; 283 + 284 + ev_cnt = FIELD_GET(ADP5585_EC_MASK, ev_cnt); 285 + if (!ev_cnt) 286 + goto out_irq; 287 + 288 + adp5585_report_events(adp5585, ev_cnt); 289 + out_irq: 290 + regmap_write(adp5585->regmap, ADP5585_INT_STATUS, status); 291 + return IRQ_HANDLED; 292 + } 293 + 294 + static int adp5585_setup(struct adp5585_dev *adp5585) 295 + { 296 + const struct adp5585_regs *regs = adp5585->regs; 297 + unsigned int reg_val, i; 298 + int ret; 299 + 300 + /* Clear any possible event by reading all the FIFO entries */ 301 + for (i = 0; i < ADP5585_EV_MAX; i++) { 302 + ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &reg_val); 303 + if (ret) 304 + return ret; 305 + } 306 + 307 + ret = regmap_write(adp5585->regmap, regs->poll_ptime_cfg, adp5585->ev_poll_time); 308 + if (ret) 309 + return ret; 310 + 311 + /* 312 + * Enable the internal oscillator, as it's shared between multiple 313 + * functions. 314 + */ 315 + ret = regmap_write(adp5585->regmap, regs->gen_cfg, 316 + ADP5585_OSC_FREQ_500KHZ | ADP5585_INT_CFG | ADP5585_OSC_EN); 317 + if (ret) 318 + return ret; 319 + 320 + return devm_add_action_or_reset(adp5585->dev, adp5585_osc_disable, adp5585); 321 + } 322 + 323 + static int adp5585_parse_fw(struct adp5585_dev *adp5585) 324 + { 325 + unsigned int prop_val; 326 + int ret; 327 + 328 + ret = device_property_read_u32(adp5585->dev, "poll-interval", &prop_val); 329 + if (!ret) { 330 + adp5585->ev_poll_time = prop_val / 10 - 1; 331 + /* 332 + * ev_poll_time is the raw value to be written on the register and 0 to 3 are the 333 + * valid values. 334 + */ 335 + if (adp5585->ev_poll_time > 3) 336 + return dev_err_probe(adp5585->dev, -EINVAL, 337 + "Invalid value(%u) for poll-interval\n", prop_val); 338 + } 339 + 340 + return 0; 341 + } 342 + 343 + static void adp5585_irq_disable(void *data) 344 + { 345 + struct adp5585_dev *adp5585 = data; 346 + 347 + regmap_write(adp5585->regmap, adp5585->regs->int_en, 0); 348 + } 349 + 350 + static int adp5585_irq_enable(struct i2c_client *i2c, 351 + struct adp5585_dev *adp5585) 352 + { 353 + const struct adp5585_regs *regs = adp5585->regs; 354 + unsigned int stat; 355 + int ret; 356 + 357 + if (i2c->irq <= 0) 358 + return 0; 359 + 360 + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, adp5585_irq, 361 + IRQF_ONESHOT, i2c->name, adp5585); 362 + if (ret) 363 + return ret; 364 + 365 + /* 366 + * Clear any possible outstanding interrupt before enabling them. We do that by reading 367 + * the status register and writing back the same value. 368 + */ 369 + ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &stat); 370 + if (ret) 371 + return ret; 372 + 373 + ret = regmap_write(adp5585->regmap, ADP5585_INT_STATUS, stat); 374 + if (ret) 375 + return ret; 376 + 377 + ret = regmap_write(adp5585->regmap, regs->int_en, ADP5585_OVRFLOW_IEN | ADP5585_EVENT_IEN); 378 + if (ret) 379 + return ret; 380 + 381 + return devm_add_action_or_reset(&i2c->dev, adp5585_irq_disable, adp5585); 382 + } 383 + 251 384 static int adp5585_i2c_probe(struct i2c_client *i2c) 252 385 { 253 386 struct regmap_config *regmap_config; ··· 401 254 402 255 i2c_set_clientdata(i2c, adp5585); 403 256 adp5585->dev = &i2c->dev; 257 + adp5585->irq = i2c->irq; 258 + BLOCKING_INIT_NOTIFIER_HEAD(&adp5585->event_notifier); 404 259 405 260 adp5585->variant = (enum adp5585_variant)(uintptr_t)i2c_get_match_data(i2c); 406 261 if (!adp5585->variant) ··· 427 278 return dev_err_probe(&i2c->dev, -ENODEV, 428 279 "Invalid device ID 0x%02x\n", id); 429 280 430 - /* 431 - * Enable the internal oscillator, as it's shared between multiple 432 - * functions. 433 - */ 434 - ret = regmap_set_bits(adp5585->regmap, ADP5585_GENERAL_CFG, ADP5585_OSC_EN); 281 + ret = adp5585_parse_fw(adp5585); 435 282 if (ret) 436 283 return ret; 437 284 438 - ret = devm_add_action_or_reset(&i2c->dev, adp5585_osc_disable, adp5585); 285 + ret = adp5585_setup(adp5585); 439 286 if (ret) 440 287 return ret; 441 288 442 - return adp5585_add_devices(adp5585); 289 + ret = adp5585_add_devices(adp5585); 290 + if (ret) 291 + return ret; 292 + 293 + return adp5585_irq_enable(i2c, adp5585); 443 294 } 444 295 445 296 static int adp5585_suspend(struct device *dev) 446 297 { 447 298 struct adp5585_dev *adp5585 = dev_get_drvdata(dev); 299 + 300 + if (adp5585->irq) 301 + disable_irq(adp5585->irq); 448 302 449 303 regcache_cache_only(adp5585->regmap, true); 450 304 ··· 457 305 static int adp5585_resume(struct device *dev) 458 306 { 459 307 struct adp5585_dev *adp5585 = dev_get_drvdata(dev); 308 + int ret; 460 309 461 310 regcache_cache_only(adp5585->regmap, false); 462 311 regcache_mark_dirty(adp5585->regmap); 463 312 464 - return regcache_sync(adp5585->regmap); 313 + ret = regcache_sync(adp5585->regmap); 314 + if (ret) 315 + return ret; 316 + 317 + if (adp5585->irq) 318 + enable_irq(adp5585->irq); 319 + 320 + return 0; 465 321 } 466 322 467 323 static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume);
+18
include/linux/mfd/adp5585.h
··· 10 10 #define __MFD_ADP5585_H_ 11 11 12 12 #include <linux/bits.h> 13 + #include <linux/notifier.h> 13 14 14 15 #define ADP5585_ID 0x00 15 16 #define ADP5585_MAN_ID_VALUE 0x20 16 17 #define ADP5585_MAN_ID_MASK GENMASK(7, 4) 18 + #define ADP5585_REV_ID_MASK GENMASK(3, 0) 17 19 #define ADP5585_INT_STATUS 0x01 20 + #define ADP5585_OVRFLOW_INT BIT(2) 21 + #define ADP5585_EVENT_INT BIT(0) 18 22 #define ADP5585_STATUS 0x02 23 + #define ADP5585_EC_MASK GENMASK(4, 0) 19 24 #define ADP5585_FIFO_1 0x03 25 + #define ADP5585_KEV_EV_PRESS_MASK BIT(7) 26 + #define ADP5585_KEY_EVENT_MASK GENMASK(6, 0) 20 27 #define ADP5585_FIFO_2 0x04 21 28 #define ADP5585_FIFO_3 0x05 22 29 #define ADP5585_FIFO_4 0x06 ··· 39 32 #define ADP5585_FIFO_14 0x10 40 33 #define ADP5585_FIFO_15 0x11 41 34 #define ADP5585_FIFO_16 0x12 35 + #define ADP5585_EV_MAX (ADP5585_FIFO_16 - ADP5585_FIFO_1 + 1) 42 36 #define ADP5585_GPI_INT_STAT_A 0x13 43 37 #define ADP5585_GPI_INT_STAT_B 0x14 44 38 #define ADP5585_GPI_STATUS_A 0x15 ··· 112 104 #define ADP5585_INT_CFG BIT(1) 113 105 #define ADP5585_RST_CFG BIT(0) 114 106 #define ADP5585_INT_EN 0x3c 107 + #define ADP5585_OVRFLOW_IEN BIT(2) 108 + #define ADP5585_EVENT_IEN BIT(0) 115 109 116 110 #define ADP5585_MAX_REG ADP5585_INT_EN 117 111 ··· 131 121 #define ADP5589_PWM_OFFT_LOW 0x3e 132 122 #define ADP5589_PWM_ONT_LOW 0x40 133 123 #define ADP5589_PWM_CFG 0x42 124 + #define ADP5589_POLL_PTIME_CFG 0x48 134 125 #define ADP5589_PIN_CONFIG_D 0x4C 126 + #define ADP5589_GENERAL_CFG 0x4d 135 127 #define ADP5589_INT_EN 0x4e 136 128 #define ADP5589_MAX_REG ADP5589_INT_EN 137 129 ··· 154 142 }; 155 143 156 144 struct adp5585_regs { 145 + unsigned int gen_cfg; 157 146 unsigned int ext_cfg; 147 + unsigned int int_en; 148 + unsigned int poll_ptime_cfg; 158 149 }; 159 150 160 151 struct adp5585_dev { 161 152 struct device *dev; 162 153 struct regmap *regmap; 163 154 const struct adp5585_regs *regs; 155 + struct blocking_notifier_head event_notifier; 164 156 enum adp5585_variant variant; 165 157 unsigned int id; 158 + int irq; 159 + unsigned int ev_poll_time; 166 160 }; 167 161 168 162 #endif