Immutable branch between MFD, GPIO, Input and PWM due for the v6.17 merge window

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmhlNWcACgkQUa+KL4f8
 d2FKARAAqS2hF4Kf86wdNBaQofYbabXFIZYCbB4OYN/9bHj0yI2Yz/Z8THbEFxVx
 e/C7ArAf6iVU9ojVUuTnjAB7Nn2qPQ6SqIkNuzF2M9iZM9P1e//7UBzBJDcPnEKA
 mYUw6XqrskI59QVqfEs8AC1TYa9QYgNDLtOyEHuQ4YdEn1J4BoO0hS8PRTXATISK
 aSy9n5OlqqgTmVHY18F/Sps39ZqWx2dDQxH4sfJ4hN3marfdk5AxEKYO+sWpHaVC
 ahi1qqBni1pUXCFpl5Yf09UhTCwDdvpBGwyoPf5bhH6YB3HXxnP8+53dUXNZh2y1
 CVILgPyMfdcMxBjYVSNP+uosnMdPVsM/88SLDiadBe7uAi4Qq2ZKWubXS4TQFkSI
 Du6uKKSIa630ovt8G9kfnN+wEMaxlPTpJ1sITGc6RScN6Q7h80lNnVXxfJZV961C
 fvbS1TPByMKr3NB0fqHW5DiKKwEdNgQwgK2uc+qyNIMiRMFMGzUja7c3hEWqGHE9
 4vGwiMo+Vfohnq2HAeG17N7CPJynSiqxRUL/aSJRmNRAlFwRW9cbqUQ9d7fkaD9j
 tiNqzTC8qb0bwhlFTxO8hR/VWPU1L4PY7OghKENYfDV2MyvP0njeHFWpZOw3c68A
 /lObItFnc4Tq4l2q1WZuuVHFfCvhtNV+ge7wNvfxGLzkK/uGfe0=
 =Vo0F
 -----END PGP SIGNATURE-----

Merge tag 'ib-mfd-gpio-input-pwm-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into gpio/for-next

Immutable branch between MFD, GPIO, Input and PWM due for the v6.17 merge window
This commit is contained in:
Bartosz Golaszewski 2025-07-03 10:35:04 +02:00
commit 93c0505787
12 changed files with 1797 additions and 1208 deletions

View File

@ -15,14 +15,21 @@ description:
properties:
compatible:
items:
- enum:
- adi,adp5585-00 # Default
- adi,adp5585-01 # 11 GPIOs
- adi,adp5585-02 # No pull-up resistors by default on special pins
- adi,adp5585-03 # Alternate I2C address
- adi,adp5585-04 # Pull-down resistors on all pins by default
- const: adi,adp5585
oneOf:
- items:
- enum:
- adi,adp5585-00 # Default
- adi,adp5585-01 # 11 GPIOs
- adi,adp5585-02 # No pull-up resistors by default on special pins
- adi,adp5585-03 # Alternate I2C address
- adi,adp5585-04 # Pull-down resistors on all pins by default
- const: adi,adp5585
- items:
- enum:
- adi,adp5589-00 # Default
- adi,adp5589-01 # R4 defaulted to RESET1 output
- adi,adp5589-02 # Pull-down resistors by default on special pins
- const: adi,adp5589
reg:
maxItems: 1
@ -32,6 +39,9 @@ properties:
vdd-supply: true
reset-gpios:
maxItems: 1
gpio-controller: true
'#gpio-cells':
@ -42,6 +52,84 @@ properties:
"#pwm-cells":
const: 3
interrupt-controller: true
'#interrupt-cells':
const: 2
poll-interval:
enum: [10, 20, 30, 40]
default: 10
adi,keypad-pins:
description: Specifies the pins used for the keypad matrix.
$ref: /schemas/types.yaml#/definitions/uint32-array
adi,unlock-events:
description:
Specifies a maximum of 2 events that can be used to unlock the keypad.
If this property is set, the keyboard will be locked and only unlocked
after these keys/gpis are pressed. The value 127 serves as a wildcard which
means any key can be used for unlocking.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 2
items:
anyOf:
- minimum: 1
maximum: 88
- minimum: 97
maximum: 115
- const: 127
adi,unlock-trigger-sec:
description:
Defines the time in which the second unlock event must occur after the
first unlock event has occurred.
maximum: 7
default: 0
adi,reset1-events:
description:
Defines the trigger events (key/gpi presses) that can generate reset
conditions one the reset1 block.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 3
adi,reset2-events:
description:
Defines the trigger events (key/gpi presses) that can generate reset
conditions one the reset2 block.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 2
adi,reset1-active-high:
description: Sets the reset1 signal as active high.
type: boolean
adi,reset2-active-high:
description: Sets the reset2 signal as active high.
type: boolean
adi,rst-passthrough-enable:
description: Allows the RST pin to override (OR with) the reset1 signal.
type: boolean
adi,reset-trigger-ms:
description:
Defines the length of time that the reset events must be active before a
reset signal is generated. All events must be active at the same time for
the same duration.
enum: [0, 1000, 1500, 2000, 2500, 3000, 3500, 4000]
default: 0
adi,reset-pulse-width-us:
description: Defines the pulse width of the reset signals.
enum: [500, 1000, 2000, 10000]
default: 500
patternProperties:
"-hog(-[0-9]+)?$":
type: object
@ -49,14 +137,28 @@ patternProperties:
required:
- gpio-hog
dependencies:
linux,keymap:
- adi,keypad-pins
- interrupts
interrupt-controller:
- interrupts
adi,unlock-trigger-sec:
- adi,unlock-events
adi,reset1-active-high:
- adi,reset1-events
adi,rst-passtrough-enable:
- adi,reset1-events
adi,reset2-active-high:
- adi,reset2-events
required:
- compatible
- reg
- gpio-controller
- "#gpio-cells"
- "#pwm-cells"
allOf:
- $ref: /schemas/input/matrix-keymap.yaml#
- $ref: /schemas/input/input.yaml#
- if:
properties:
compatible:
@ -64,9 +166,60 @@ allOf:
const: adi,adp5585-01
then:
properties:
adi,unlock-events: false
adi,unlock-trigger-sec: false
gpio-reserved-ranges: false
else:
reset-gpios: false
adi,keypad-pins:
minItems: 2
maxItems: 11
items:
minimum: 0
maximum: 10
adi,reset1-events:
items:
anyOf:
- minimum: 1
maximum: 30
- minimum: 37
maximum: 47
adi,reset2-events:
items:
anyOf:
- minimum: 1
maximum: 30
- minimum: 37
maximum: 47
- if:
properties:
compatible:
contains:
enum:
- adi,adp5585-00
- adi,adp5585-02
- adi,adp5585-03
- adi,adp5585-04
then:
properties:
adi,unlock-events: false
adi,unlock-trigger-sec: false
adi,keypad-pins:
minItems: 2
maxItems: 10
items:
enum: [0, 1, 2, 3, 4, 6, 7, 8, 9, 10]
adi,reset1-events:
items:
anyOf:
- minimum: 1
maximum: 25
- enum: [37, 38, 39, 40, 41, 43, 44, 45, 46, 47]
adi,reset2-events:
items:
anyOf:
- minimum: 1
maximum: 25
- enum: [37, 38, 39, 40, 41, 43, 44, 45, 46, 47]
gpio-reserved-ranges:
maxItems: 1
items:
@ -74,10 +227,44 @@ allOf:
- const: 5
- const: 1
additionalProperties: false
- if:
properties:
compatible:
contains:
enum:
- adi,adp5589-00
- adi,adp5589-01
- adi,adp5589-02
then:
properties:
gpio-reserved-ranges: false
adi,keypad-pins:
minItems: 2
maxItems: 19
items:
minimum: 0
maximum: 18
adi,reset1-events:
items:
anyOf:
- minimum: 1
maximum: 88
- minimum: 97
maximum: 115
adi,reset2-events:
items:
anyOf:
- minimum: 1
maximum: 88
- minimum: 97
maximum: 115
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
@ -93,6 +280,33 @@ examples:
gpio-reserved-ranges = <5 1>;
#pwm-cells = <3>;
interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,reset1-events = <1 43>;
adi,reset2-events = <2 3>;
adi,reset-trigger-ms = <2000>;
/*
* col0, col1, col2
* row0, row1, row2
*/
adi,keypad-pins = <0 1 2 6 7 8>;
linux,keymap = <
MATRIX_KEY(0x00, 0x00, KEY_1)
MATRIX_KEY(0x00, 0x01, KEY_2)
MATRIX_KEY(0x00, 0x02, KEY_3)
MATRIX_KEY(0x01, 0x00, KEY_A)
MATRIX_KEY(0x01, 0x01, KEY_B)
MATRIX_KEY(0x01, 0x02, KEY_C)
MATRIX_KEY(0x02, 0x00, BTN_1)
MATRIX_KEY(0x02, 0x01, BTN_2)
MATRIX_KEY(0x02, 0x02, BTN_3)
>;
};
};

View File

@ -39,8 +39,6 @@ properties:
- ad,adm9240
# AD5110 - Nonvolatile Digital Potentiometer
- adi,ad5110
# Analog Devices ADP5589 Keypad Decoder and I/O Expansion
- adi,adp5589
# Analog Devices LT7182S Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher
- adi,lt7182s
# AMS iAQ-Core VOC Sensor

View File

@ -550,6 +550,7 @@ L: linux-pwm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml
F: drivers/gpio/gpio-adp5585.c
F: drivers/input/keyboard/adp5585-keys.c
F: drivers/mfd/adp5585.c
F: drivers/pwm/pwm-adp5585.c
F: include/linux/mfd/adp5585.h

View File

@ -1263,6 +1263,7 @@ config GPIO_ADP5520
config GPIO_ADP5585
tristate "GPIO Support for ADP5585"
depends on MFD_ADP5585
select GPIOLIB_IRQCHIP
help
This option enables support for the GPIO function found in the Analog
Devices ADP5585.

View File

@ -4,67 +4,131 @@
*
* Copyright 2022 NXP
* Copyright 2024 Ideas on Board Oy
* Copyright 2025 Analog Devices, Inc.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/mfd/adp5585.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/types.h>
#define ADP5585_GPIO_MAX 11
/*
* Bank 0 covers pins "GPIO 1/R0" to "GPIO 6/R5", numbered 0 to 5 by the
* driver, and bank 1 covers pins "GPIO 7/C0" to "GPIO 11/C4", numbered 6 to
* 10. Some variants of the ADP5585 don't support "GPIO 6/R5". As the driver
* uses identical GPIO numbering for all variants to avoid confusion, GPIO 5 is
* marked as reserved in the device tree for variants that don't support it.
*/
#define ADP5585_BANK(n) ((n) >= 6 ? 1 : 0)
#define ADP5585_BIT(n) ((n) >= 6 ? BIT((n) - 6) : BIT(n))
/*
* Bank 0 covers pins "GPIO 1/R0" to "GPIO 8/R7", numbered 0 to 7 by the
* driver, bank 1 covers pins "GPIO 9/C0" to "GPIO 16/C7", numbered 8 to
* 15 and bank 3 covers pins "GPIO 17/C8" to "GPIO 19/C10", numbered 16 to 18.
*/
#define ADP5589_BANK(n) ((n) >> 3)
#define ADP5589_BIT(n) BIT((n) & 0x7)
struct adp5585_gpio_chip {
int (*bank)(unsigned int off);
int (*bit)(unsigned int off);
unsigned int debounce_dis_a;
unsigned int rpull_cfg_a;
unsigned int gpo_data_a;
unsigned int gpo_out_a;
unsigned int gpio_dir_a;
unsigned int gpi_stat_a;
unsigned int gpi_int_lvl_a;
unsigned int gpi_ev_a;
unsigned int gpi_ev_min;
unsigned int gpi_ev_max;
bool has_bias_hole;
};
struct adp5585_gpio_dev {
struct gpio_chip gpio_chip;
struct notifier_block nb;
const struct adp5585_gpio_chip *info;
struct regmap *regmap;
unsigned long irq_mask;
unsigned long irq_en;
unsigned long irq_active_high;
/* used for irqchip bus locking */
struct mutex bus_lock;
};
static int adp5585_gpio_bank(unsigned int off)
{
return ADP5585_BANK(off);
}
static int adp5585_gpio_bit(unsigned int off)
{
return ADP5585_BIT(off);
}
static int adp5589_gpio_bank(unsigned int off)
{
return ADP5589_BANK(off);
}
static int adp5589_gpio_bit(unsigned int off)
{
return ADP5589_BIT(off);
}
static int adp5585_gpio_get_direction(struct gpio_chip *chip, unsigned int off)
{
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int val;
regmap_read(adp5585_gpio->regmap, ADP5585_GPIO_DIRECTION_A + bank, &val);
regmap_read(adp5585_gpio->regmap, info->gpio_dir_a + info->bank(off), &val);
return val & bit ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
return val & info->bit(off) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
}
static int adp5585_gpio_direction_input(struct gpio_chip *chip, unsigned int off)
{
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
return regmap_clear_bits(adp5585_gpio->regmap,
ADP5585_GPIO_DIRECTION_A + bank, bit);
return regmap_clear_bits(adp5585_gpio->regmap, info->gpio_dir_a + info->bank(off),
info->bit(off));
}
static int adp5585_gpio_direction_output(struct gpio_chip *chip, unsigned int off, int val)
{
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int bank = info->bank(off);
unsigned int bit = info->bit(off);
int ret;
ret = regmap_update_bits(adp5585_gpio->regmap,
ADP5585_GPO_DATA_OUT_A + bank, bit,
val ? bit : 0);
ret = regmap_update_bits(adp5585_gpio->regmap, info->gpo_data_a + bank,
bit, val ? bit : 0);
if (ret)
return ret;
return regmap_set_bits(adp5585_gpio->regmap,
ADP5585_GPIO_DIRECTION_A + bank, bit);
return regmap_set_bits(adp5585_gpio->regmap, info->gpio_dir_a + bank,
bit);
}
static int adp5585_gpio_get_value(struct gpio_chip *chip, unsigned int off)
{
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int bank = info->bank(off);
unsigned int bit = info->bit(off);
unsigned int reg;
unsigned int val;
@ -79,8 +143,8 @@ static int adp5585_gpio_get_value(struct gpio_chip *chip, unsigned int off)
* .direction_input(), .direction_output() or .set() operations racing
* with this.
*/
regmap_read(adp5585_gpio->regmap, ADP5585_GPIO_DIRECTION_A + bank, &val);
reg = val & bit ? ADP5585_GPO_DATA_OUT_A : ADP5585_GPI_STATUS_A;
regmap_read(adp5585_gpio->regmap, info->gpio_dir_a + bank, &val);
reg = val & bit ? info->gpo_data_a : info->gpi_stat_a;
regmap_read(adp5585_gpio->regmap, reg + bank, &val);
return !!(val & bit);
@ -90,17 +154,17 @@ static int adp5585_gpio_set_value(struct gpio_chip *chip, unsigned int off,
int val)
{
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int bit = adp5585_gpio->info->bit(off);
return regmap_update_bits(adp5585_gpio->regmap,
ADP5585_GPO_DATA_OUT_A + bank,
return regmap_update_bits(adp5585_gpio->regmap, info->gpo_data_a + info->bank(off),
bit, val ? bit : 0);
}
static int adp5585_gpio_set_bias(struct adp5585_gpio_dev *adp5585_gpio,
unsigned int off, unsigned int bias)
{
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int bit, reg, mask, val;
/*
@ -108,8 +172,10 @@ static int adp5585_gpio_set_bias(struct adp5585_gpio_dev *adp5585_gpio,
* consecutive registers ADP5585_RPULL_CONFIG_*, with a hole of 4 bits
* after R5.
*/
bit = off * 2 + (off > 5 ? 4 : 0);
reg = ADP5585_RPULL_CONFIG_A + bit / 8;
bit = off * 2;
if (info->has_bias_hole)
bit += (off > 5 ? 4 : 0);
reg = info->rpull_cfg_a + bit / 8;
mask = ADP5585_Rx_PULL_CFG_MASK << (bit % 8);
val = bias << (bit % 8);
@ -119,22 +185,22 @@ static int adp5585_gpio_set_bias(struct adp5585_gpio_dev *adp5585_gpio,
static int adp5585_gpio_set_drive(struct adp5585_gpio_dev *adp5585_gpio,
unsigned int off, enum pin_config_param drive)
{
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int bit = adp5585_gpio->info->bit(off);
return regmap_update_bits(adp5585_gpio->regmap,
ADP5585_GPO_OUT_MODE_A + bank, bit,
info->gpo_out_a + info->bank(off), bit,
drive == PIN_CONFIG_DRIVE_OPEN_DRAIN ? bit : 0);
}
static int adp5585_gpio_set_debounce(struct adp5585_gpio_dev *adp5585_gpio,
unsigned int off, unsigned int debounce)
{
unsigned int bank = ADP5585_BANK(off);
unsigned int bit = ADP5585_BIT(off);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
unsigned int bit = adp5585_gpio->info->bit(off);
return regmap_update_bits(adp5585_gpio->regmap,
ADP5585_DEBOUNCE_DIS_A + bank, bit,
info->debounce_dis_a + info->bank(off), bit,
debounce ? 0 : bit);
}
@ -172,11 +238,175 @@ static int adp5585_gpio_set_config(struct gpio_chip *chip, unsigned int off,
};
}
static int adp5585_gpio_request(struct gpio_chip *chip, unsigned int off)
{
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
struct device *dev = chip->parent;
struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
const struct adp5585_regs *regs = adp5585->regs;
int ret;
ret = test_and_set_bit(off, adp5585->pin_usage);
if (ret)
return -EBUSY;
/* make sure it's configured for GPIO */
return regmap_clear_bits(adp5585_gpio->regmap,
regs->pin_cfg_a + info->bank(off),
info->bit(off));
}
static void adp5585_gpio_free(struct gpio_chip *chip, unsigned int off)
{
struct device *dev = chip->parent;
struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
clear_bit(off, adp5585->pin_usage);
}
static int adp5585_gpio_key_event(struct notifier_block *nb, unsigned long key,
void *data)
{
struct adp5585_gpio_dev *adp5585_gpio = container_of(nb, struct adp5585_gpio_dev, nb);
struct device *dev = adp5585_gpio->gpio_chip.parent;
unsigned long key_press = (unsigned long)data;
unsigned int irq, irq_type;
struct irq_data *irqd;
bool active_high;
unsigned int off;
/* make sure the event is for me */
if (key < adp5585_gpio->info->gpi_ev_min || key > adp5585_gpio->info->gpi_ev_max)
return NOTIFY_DONE;
off = key - adp5585_gpio->info->gpi_ev_min;
active_high = test_bit(off, &adp5585_gpio->irq_active_high);
irq = irq_find_mapping(adp5585_gpio->gpio_chip.irq.domain, off);
if (!irq)
return NOTIFY_BAD;
irqd = irq_get_irq_data(irq);
if (!irqd) {
dev_err(dev, "Could not get irq(%u) data\n", irq);
return NOTIFY_BAD;
}
dev_dbg_ratelimited(dev, "gpio-keys event(%u) press=%lu, a_high=%u\n",
off, key_press, active_high);
if (!active_high)
key_press = !key_press;
irq_type = irqd_get_trigger_type(irqd);
if ((irq_type & IRQ_TYPE_EDGE_RISING && key_press) ||
(irq_type & IRQ_TYPE_EDGE_FALLING && !key_press))
handle_nested_irq(irq);
return NOTIFY_STOP;
}
static void adp5585_irq_bus_lock(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc);
mutex_lock(&adp5585_gpio->bus_lock);
}
static void adp5585_irq_bus_sync_unlock(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip);
const struct adp5585_gpio_chip *info = adp5585_gpio->info;
irq_hw_number_t hwirq = irqd_to_hwirq(d);
bool active_high = test_bit(hwirq, &adp5585_gpio->irq_active_high);
bool enabled = test_bit(hwirq, &adp5585_gpio->irq_en);
bool masked = test_bit(hwirq, &adp5585_gpio->irq_mask);
unsigned int bank = adp5585_gpio->info->bank(hwirq);
unsigned int bit = adp5585_gpio->info->bit(hwirq);
if (masked && !enabled)
goto out_unlock;
if (!masked && enabled)
goto out_unlock;
regmap_update_bits(adp5585_gpio->regmap, info->gpi_int_lvl_a + bank, bit,
active_high ? bit : 0);
regmap_update_bits(adp5585_gpio->regmap, info->gpi_ev_a + bank, bit,
masked ? 0 : bit);
assign_bit(hwirq, &adp5585_gpio->irq_en, !masked);
out_unlock:
mutex_unlock(&adp5585_gpio->bus_lock);
}
static void adp5585_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
__set_bit(hwirq, &adp5585_gpio->irq_mask);
gpiochip_disable_irq(gc, hwirq);
}
static void adp5585_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
gpiochip_enable_irq(gc, hwirq);
__clear_bit(hwirq, &adp5585_gpio->irq_mask);
}
static int adp5585_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
if (!(type & IRQ_TYPE_EDGE_BOTH))
return -EINVAL;
assign_bit(hwirq, &adp5585_gpio->irq_active_high,
type == IRQ_TYPE_EDGE_RISING);
irq_set_handler_locked(d, handle_edge_irq);
return 0;
}
static const struct irq_chip adp5585_irq_chip = {
.name = "adp5585",
.irq_mask = adp5585_irq_mask,
.irq_unmask = adp5585_irq_unmask,
.irq_bus_lock = adp5585_irq_bus_lock,
.irq_bus_sync_unlock = adp5585_irq_bus_sync_unlock,
.irq_set_type = adp5585_irq_set_type,
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void adp5585_gpio_unreg_notifier(void *data)
{
struct adp5585_gpio_dev *adp5585_gpio = data;
struct device *dev = adp5585_gpio->gpio_chip.parent;
struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
blocking_notifier_chain_unregister(&adp5585->event_notifier,
&adp5585_gpio->nb);
}
static int adp5585_gpio_probe(struct platform_device *pdev)
{
struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent);
const struct platform_device_id *id = platform_get_device_id(pdev);
struct adp5585_gpio_dev *adp5585_gpio;
struct device *dev = &pdev->dev;
struct gpio_irq_chip *girq;
struct gpio_chip *gc;
int ret;
@ -186,6 +416,10 @@ static int adp5585_gpio_probe(struct platform_device *pdev)
adp5585_gpio->regmap = adp5585->regmap;
adp5585_gpio->info = (const struct adp5585_gpio_chip *)id->driver_data;
if (!adp5585_gpio->info)
return -ENODEV;
device_set_of_node_from_dev(dev, dev->parent);
gc = &adp5585_gpio->gpio_chip;
@ -196,13 +430,43 @@ static int adp5585_gpio_probe(struct platform_device *pdev)
gc->get = adp5585_gpio_get_value;
gc->set_rv = adp5585_gpio_set_value;
gc->set_config = adp5585_gpio_set_config;
gc->request = adp5585_gpio_request;
gc->free = adp5585_gpio_free;
gc->can_sleep = true;
gc->base = -1;
gc->ngpio = ADP5585_GPIO_MAX;
gc->ngpio = adp5585->n_pins;
gc->label = pdev->name;
gc->owner = THIS_MODULE;
if (device_property_present(dev->parent, "interrupt-controller")) {
if (!adp5585->irq)
return dev_err_probe(dev, -EINVAL,
"Unable to serve as interrupt controller without IRQ\n");
girq = &adp5585_gpio->gpio_chip.irq;
gpio_irq_chip_set_chip(girq, &adp5585_irq_chip);
girq->handler = handle_bad_irq;
girq->threaded = true;
adp5585_gpio->nb.notifier_call = adp5585_gpio_key_event;
ret = blocking_notifier_chain_register(&adp5585->event_notifier,
&adp5585_gpio->nb);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, adp5585_gpio_unreg_notifier,
adp5585_gpio);
if (ret)
return ret;
}
/* everything masked by default */
adp5585_gpio->irq_mask = ~0UL;
ret = devm_mutex_init(dev, &adp5585_gpio->bus_lock);
if (ret)
return ret;
ret = devm_gpiochip_add_data(dev, &adp5585_gpio->gpio_chip,
adp5585_gpio);
if (ret)
@ -211,8 +475,40 @@ static int adp5585_gpio_probe(struct platform_device *pdev)
return 0;
}
static const struct adp5585_gpio_chip adp5585_gpio_chip_info = {
.bank = adp5585_gpio_bank,
.bit = adp5585_gpio_bit,
.debounce_dis_a = ADP5585_DEBOUNCE_DIS_A,
.rpull_cfg_a = ADP5585_RPULL_CONFIG_A,
.gpo_data_a = ADP5585_GPO_DATA_OUT_A,
.gpo_out_a = ADP5585_GPO_OUT_MODE_A,
.gpio_dir_a = ADP5585_GPIO_DIRECTION_A,
.gpi_stat_a = ADP5585_GPI_STATUS_A,
.has_bias_hole = true,
.gpi_ev_min = ADP5585_GPI_EVENT_START,
.gpi_ev_max = ADP5585_GPI_EVENT_END,
.gpi_int_lvl_a = ADP5585_GPI_INT_LEVEL_A,
.gpi_ev_a = ADP5585_GPI_EVENT_EN_A,
};
static const struct adp5585_gpio_chip adp5589_gpio_chip_info = {
.bank = adp5589_gpio_bank,
.bit = adp5589_gpio_bit,
.debounce_dis_a = ADP5589_DEBOUNCE_DIS_A,
.rpull_cfg_a = ADP5589_RPULL_CONFIG_A,
.gpo_data_a = ADP5589_GPO_DATA_OUT_A,
.gpo_out_a = ADP5589_GPO_OUT_MODE_A,
.gpio_dir_a = ADP5589_GPIO_DIRECTION_A,
.gpi_stat_a = ADP5589_GPI_STATUS_A,
.gpi_ev_min = ADP5589_GPI_EVENT_START,
.gpi_ev_max = ADP5589_GPI_EVENT_END,
.gpi_int_lvl_a = ADP5589_GPI_INT_LEVEL_A,
.gpi_ev_a = ADP5589_GPI_EVENT_EN_A,
};
static const struct platform_device_id adp5585_gpio_id_table[] = {
{ "adp5585-gpio" },
{ "adp5585-gpio", (kernel_ulong_t)&adp5585_gpio_chip_info },
{ "adp5589-gpio", (kernel_ulong_t)&adp5589_gpio_chip_info },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(platform, adp5585_gpio_id_table);

View File

@ -37,6 +37,17 @@ config KEYBOARD_ADP5520
To compile this driver as a module, choose M here: the module will
be called adp5520-keys.
config KEYBOARD_ADP5585
tristate "ADP558x keypad support"
depends on MFD_ADP5585
select INPUT_MATRIXKMAP
help
This option enables support for the KEYPAD function found in the Analog
Devices ADP5585 and similar devices.
To compile this driver as a module, choose M here: the
module will be called adp5585-keys.
config KEYBOARD_ADP5588
tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander"
depends on I2C
@ -50,16 +61,6 @@ config KEYBOARD_ADP5588
To compile this driver as a module, choose M here: the
module will be called adp5588-keys.
config KEYBOARD_ADP5589
tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander"
depends on I2C
help
Say Y here if you want to use a ADP5585/ADP5589 attached to your
system I2C bus.
To compile this driver as a module, choose M here: the
module will be called adp5589-keys.
config KEYBOARD_AMIGA
tristate "Amiga keyboard"
depends on AMIGA

View File

@ -7,8 +7,8 @@
obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5585) += adp5585-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_APPLESPI) += applespi.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o

View File

@ -0,0 +1,371 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices ADP5585 Keys driver
*
* Copyright (C) 2025 Analog Devices, Inc.
*/
#include <linux/bitmap.h>
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/find.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/adp5585.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/types.h>
/* As needed for the matrix parsing code */
#define ADP5589_MAX_KEYMAPSIZE 123
struct adp5585_kpad_chip {
u8 key_ev_min;
u8 key_ev_max;
u8 max_rows;
u8 max_cols;
};
struct adp5585_kpad {
const struct adp5585_kpad_chip *info;
struct notifier_block nb;
struct input_dev *input;
unsigned short keycode[ADP5589_MAX_KEYMAPSIZE];
struct device *dev;
unsigned long keypad;
int row_shift;
};
static int adp5585_keys_validate_events(const struct adp5585_kpad *kpad,
const u32 *events, u32 n_events)
{
unsigned int ev;
u32 row, col;
for (ev = 0; ev < n_events; ev++) {
if (events[ev] < kpad->info->key_ev_min ||
events[ev] > kpad->info->key_ev_max)
continue;
/*
* if the event is to be generated by the keymap, we need to make
* sure that the pins are part of it!
*/
row = (events[ev] - 1) / kpad->info->max_cols;
col = (events[ev] - 1) % kpad->info->max_cols;
if (test_bit(row, &kpad->keypad) &&
test_bit(col + kpad->info->max_rows, &kpad->keypad))
continue;
return dev_err_probe(kpad->dev, -EINVAL,
"Invalid unlock/reset event(%u) not used in the keypad\n",
events[ev]);
}
return 0;
}
static int adp5585_keys_check_special_events(const struct adp5585_dev *adp5585,
const struct adp5585_kpad *kpad)
{
int error;
error = adp5585_keys_validate_events(kpad, adp5585->unlock_keys,
adp5585->nkeys_unlock);
if (error)
return error;
error = adp5585_keys_validate_events(kpad, adp5585->reset1_keys,
adp5585->nkeys_reset1);
if (error)
return error;
return adp5585_keys_validate_events(kpad, adp5585->reset2_keys,
adp5585->nkeys_reset2);
}
static void adp5585_keys_pins_free(void *data)
{
struct adp5585_kpad *kpad = data;
struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent);
unsigned int pin;
for_each_set_bit(pin, &kpad->keypad, adp5585->n_pins)
clear_bit(pin, adp5585->pin_usage);
}
static int adp5585_keys_parse_fw(const struct adp5585_dev *adp5585,
struct adp5585_kpad *kpad)
{
struct device *dev = kpad->dev;
u32 cols = 0, rows = 0, pin;
int error, n_pins;
/*
* We do not check for errors (or no value) since the input device is
* only added if this property is present in the first place.
*/
n_pins = device_property_count_u32(dev, "adi,keypad-pins");
if (n_pins > adp5585->n_pins)
return dev_err_probe(dev, -EINVAL,
"Too many keypad pins (%d) defined (max=%d)\n",
n_pins, adp5585->n_pins);
unsigned int *keypad_pins __free(kfree) = kcalloc(n_pins, sizeof(*keypad_pins),
GFP_KERNEL);
if (!keypad_pins)
return -ENOMEM;
error = device_property_read_u32_array(dev, "adi,keypad-pins",
keypad_pins, n_pins);
if (error)
return error;
/*
* We can add the action here since it makes the code easier and nothing
* "bad" will happen out of it. Worst case, it will be a no-op and no
* bit will set.
*/
error = devm_add_action_or_reset(dev, adp5585_keys_pins_free, kpad);
if (error)
return error;
for (pin = 0; pin < n_pins; pin++) {
if (keypad_pins[pin] >= adp5585->n_pins)
return dev_err_probe(dev, -EINVAL,
"Invalid keypad pin(%u) defined\n",
keypad_pins[pin]);
if (test_and_set_bit(keypad_pins[pin], adp5585->pin_usage))
return dev_err_probe(dev, -EBUSY,
"Keypad pin(%u) already used\n",
keypad_pins[pin]);
__set_bit(keypad_pins[pin], &kpad->keypad);
}
/*
* Note that given that we get a mask (and the HW allows it), we
* can have holes in our keypad (eg: row0, row1 and row7 enabled).
* However, for the matrix parsing functions we need to pass the
* number of rows/cols as the maximum row/col used plus 1. This
* pretty much means we will also have holes in our SW keypad.
*/
rows = find_last_bit(&kpad->keypad, kpad->info->max_rows) + 1;
if (rows == kpad->info->max_rows + 1)
return dev_err_probe(dev, -EINVAL,
"Now rows defined in the keypad!\n");
cols = find_last_bit(&kpad->keypad, kpad->info->max_cols + kpad->info->max_rows);
if (cols < kpad->info->max_rows)
return dev_err_probe(dev, -EINVAL,
"No columns defined in the keypad!\n");
cols = cols + 1 - kpad->info->max_rows;
error = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
kpad->keycode, kpad->input);
if (error)
return error;
kpad->row_shift = get_count_order(cols);
if (device_property_read_bool(kpad->dev, "autorepeat"))
__set_bit(EV_REP, kpad->input->evbit);
error = adp5585_keys_check_special_events(adp5585, kpad);
if (error)
return error;
return 0;
}
static int adp5585_keys_setup(const struct adp5585_dev *adp5585,
struct adp5585_kpad *kpad)
{
unsigned long keys_bits, start = 0, nbits = kpad->info->max_rows;
const struct adp5585_regs *regs = adp5585->regs;
unsigned int i = 0, max_cols = kpad->info->max_cols;
int error;
/*
* Take care as the below assumes max_rows is always less or equal than
* 8 which is true for the supported devices. If we happen to add
* another device we need to make sure this still holds true. Although
* adding a new device is very unlikely.
*/
do {
keys_bits = bitmap_read(&kpad->keypad, start, nbits);
if (keys_bits) {
error = regmap_write(adp5585->regmap, regs->pin_cfg_a + i,
keys_bits);
if (error)
return error;
}
start += nbits;
if (max_cols > 8) {
nbits = 8;
max_cols -= nbits;
} else {
nbits = max_cols;
}
i++;
} while (start < kpad->info->max_rows + kpad->info->max_cols);
return 0;
}
static int adp5585_keys_ev_handle(struct notifier_block *nb, unsigned long key,
void *data)
{
struct adp5585_kpad *kpad = container_of(nb, struct adp5585_kpad, nb);
unsigned long key_press = (unsigned long)data;
unsigned int row, col, code;
/* make sure the event is for us */
if (key < kpad->info->key_ev_min || key > kpad->info->key_ev_max)
return NOTIFY_DONE;
/*
* Unlikely but lets be on the safe side! We do not return any error
* because the event was indeed for us but with some weird value. So,
* we still want the caller know that the right handler was called.
*/
if (!key)
return NOTIFY_BAD;
row = (key - 1) / (kpad->info->max_cols);
col = (key - 1) % (kpad->info->max_cols);
code = MATRIX_SCAN_CODE(row, col, kpad->row_shift);
dev_dbg_ratelimited(kpad->dev, "report key(%lu) r(%d) c(%d) code(%d)\n",
key, row, col, kpad->keycode[code]);
input_report_key(kpad->input, kpad->keycode[code], key_press);
input_sync(kpad->input);
return NOTIFY_STOP;
}
static void adp5585_keys_unreg_notifier(void *data)
{
struct adp5585_kpad *kpad = data;
struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent);
blocking_notifier_chain_unregister(&adp5585->event_notifier,
&kpad->nb);
}
static int adp5585_keys_probe(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct adp5585_kpad *kpad;
unsigned int revid;
const char *phys;
int error;
kpad = devm_kzalloc(dev, sizeof(*kpad), GFP_KERNEL);
if (!kpad)
return -ENOMEM;
if (!adp5585->irq)
return dev_err_probe(dev, -EINVAL,
"IRQ is mandatory for the keypad\n");
kpad->dev = dev;
kpad->input = devm_input_allocate_device(dev);
if (!kpad->input)
return -ENOMEM;
kpad->info = (const struct adp5585_kpad_chip *)id->driver_data;
if (!kpad->info)
return -ENODEV;
error = regmap_read(adp5585->regmap, ADP5585_ID, &revid);
if (error)
return dev_err_probe(dev, error, "Failed to read device ID\n");
phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", pdev->name);
if (!phys)
return -ENOMEM;
kpad->input->name = pdev->name;
kpad->input->phys = phys;
kpad->input->id.bustype = BUS_I2C;
kpad->input->id.vendor = 0x0001;
kpad->input->id.product = 0x0001;
kpad->input->id.version = revid & ADP5585_REV_ID_MASK;
device_set_of_node_from_dev(dev, dev->parent);
error = adp5585_keys_parse_fw(adp5585, kpad);
if (error)
return error;
error = adp5585_keys_setup(adp5585, kpad);
if (error)
return error;
kpad->nb.notifier_call = adp5585_keys_ev_handle;
error = blocking_notifier_chain_register(&adp5585->event_notifier,
&kpad->nb);
if (error)
return error;
error = devm_add_action_or_reset(dev, adp5585_keys_unreg_notifier, kpad);
if (error)
return error;
error = input_register_device(kpad->input);
if (error)
return dev_err_probe(dev, error,
"Failed to register input device\n");
return 0;
}
static const struct adp5585_kpad_chip adp5585_kpad_chip_info = {
.max_rows = 6,
.max_cols = 5,
.key_ev_min = ADP5585_ROW5_KEY_EVENT_START,
.key_ev_max = ADP5585_ROW5_KEY_EVENT_END,
};
static const struct adp5585_kpad_chip adp5589_kpad_chip_info = {
.max_rows = 8,
.max_cols = 11,
.key_ev_min = ADP5589_KEY_EVENT_START,
.key_ev_max = ADP5589_KEY_EVENT_END,
};
static const struct platform_device_id adp5585_keys_id_table[] = {
{ "adp5585-keys", (kernel_ulong_t)&adp5585_kpad_chip_info },
{ "adp5589-keys", (kernel_ulong_t)&adp5589_kpad_chip_info },
{ }
};
MODULE_DEVICE_TABLE(platform, adp5585_keys_id_table);
static struct platform_driver adp5585_keys_driver = {
.driver = {
.name = "adp5585-keys",
},
.probe = adp5585_keys_probe,
.id_table = adp5585_keys_id_table,
};
module_platform_driver(adp5585_keys_driver);
MODULE_AUTHOR("Nuno Sá <nuno.sa@analog.com>");
MODULE_DESCRIPTION("ADP5585 Keys Driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -4,22 +4,40 @@
*
* Copyright 2022 NXP
* Copyright 2024 Ideas on Board Oy
* Copyright 2025 Analog Devices Inc.
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/gpio/consumer.h>
#include <linux/mfd/adp5585.h>
#include <linux/mfd/core.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
static const struct mfd_cell adp5585_devs[] = {
{ .name = "adp5585-gpio", },
{ .name = "adp5585-pwm", },
enum {
ADP5585_DEV_GPIO,
ADP5585_DEV_PWM,
ADP5585_DEV_INPUT,
ADP5585_DEV_MAX
};
static const struct mfd_cell adp5585_devs[ADP5585_DEV_MAX] = {
MFD_CELL_NAME("adp5585-gpio"),
MFD_CELL_NAME("adp5585-pwm"),
MFD_CELL_NAME("adp5585-keys"),
};
static const struct mfd_cell adp5589_devs[] = {
MFD_CELL_NAME("adp5589-gpio"),
MFD_CELL_NAME("adp5589-pwm"),
MFD_CELL_NAME("adp5589-keys"),
};
static const struct regmap_range adp5585_volatile_ranges[] = {
@ -31,6 +49,15 @@ static const struct regmap_access_table adp5585_volatile_regs = {
.n_yes_ranges = ARRAY_SIZE(adp5585_volatile_ranges),
};
static const struct regmap_range adp5589_volatile_ranges[] = {
regmap_reg_range(ADP5585_ID, ADP5589_GPI_STATUS_C),
};
static const struct regmap_access_table adp5589_volatile_regs = {
.yes_ranges = adp5589_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(adp5589_volatile_ranges),
};
/*
* Chip variants differ in the default configuration of pull-up and pull-down
* resistors, and therefore have different default register values:
@ -74,46 +101,597 @@ static const u8 adp5585_regmap_defaults_04[ADP5585_MAX_REG + 1] = {
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00,
};
enum adp5585_regmap_type {
ADP5585_REGMAP_00,
ADP5585_REGMAP_02,
ADP5585_REGMAP_04,
static const u8 adp5589_regmap_defaults_00[ADP5589_MAX_REG + 1] = {
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const struct regmap_config adp5585_regmap_configs[] = {
[ADP5585_REGMAP_00] = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ADP5585_MAX_REG,
.volatile_table = &adp5585_volatile_regs,
.cache_type = REGCACHE_MAPLE,
.reg_defaults_raw = adp5585_regmap_defaults_00,
.num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_00),
},
[ADP5585_REGMAP_02] = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ADP5585_MAX_REG,
.volatile_table = &adp5585_volatile_regs,
.cache_type = REGCACHE_MAPLE,
.reg_defaults_raw = adp5585_regmap_defaults_02,
.num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_02),
},
[ADP5585_REGMAP_04] = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ADP5585_MAX_REG,
.volatile_table = &adp5585_volatile_regs,
.cache_type = REGCACHE_MAPLE,
.reg_defaults_raw = adp5585_regmap_defaults_04,
.num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_04),
},
static const u8 adp5589_regmap_defaults_01[ADP5589_MAX_REG + 1] = {
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
/* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x48 */ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
};
static const u8 adp5589_regmap_defaults_02[ADP5589_MAX_REG + 1] = {
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x18 */ 0x00, 0x41, 0x01, 0x00, 0x11, 0x04, 0x00, 0x00,
/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const u8 *adp5585_regmap_defaults[ADP5585_MAX] = {
[ADP5585_00] = adp5585_regmap_defaults_00,
[ADP5585_01] = adp5585_regmap_defaults_00,
[ADP5585_02] = adp5585_regmap_defaults_02,
[ADP5585_03] = adp5585_regmap_defaults_00,
[ADP5585_04] = adp5585_regmap_defaults_04,
[ADP5589_00] = adp5589_regmap_defaults_00,
[ADP5589_01] = adp5589_regmap_defaults_01,
[ADP5589_02] = adp5589_regmap_defaults_02,
};
static const struct regmap_config adp5585_regmap_config_template = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ADP5585_MAX_REG,
.volatile_table = &adp5585_volatile_regs,
.cache_type = REGCACHE_MAPLE,
.num_reg_defaults_raw = ADP5585_MAX_REG + 1,
};
static const struct regmap_config adp5589_regmap_config_template = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ADP5589_MAX_REG,
.volatile_table = &adp5589_volatile_regs,
.cache_type = REGCACHE_MAPLE,
.num_reg_defaults_raw = ADP5589_MAX_REG + 1,
};
static const struct adp5585_regs adp5585_regs = {
.ext_cfg = ADP5585_PIN_CONFIG_C,
.int_en = ADP5585_INT_EN,
.gen_cfg = ADP5585_GENERAL_CFG,
.poll_ptime_cfg = ADP5585_POLL_PTIME_CFG,
.reset_cfg = ADP5585_RESET_CFG,
.reset1_event_a = ADP5585_RESET1_EVENT_A,
.reset2_event_a = ADP5585_RESET2_EVENT_A,
.pin_cfg_a = ADP5585_PIN_CONFIG_A,
};
static const struct adp5585_regs adp5589_regs = {
.ext_cfg = ADP5589_PIN_CONFIG_D,
.int_en = ADP5589_INT_EN,
.gen_cfg = ADP5589_GENERAL_CFG,
.poll_ptime_cfg = ADP5589_POLL_PTIME_CFG,
.reset_cfg = ADP5589_RESET_CFG,
.reset1_event_a = ADP5589_RESET1_EVENT_A,
.reset2_event_a = ADP5589_RESET2_EVENT_A,
.pin_cfg_a = ADP5589_PIN_CONFIG_A,
};
static int adp5585_validate_event(const struct adp5585_dev *adp5585, unsigned int ev)
{
if (adp5585->has_pin6) {
if (ev >= ADP5585_ROW5_KEY_EVENT_START && ev <= ADP5585_ROW5_KEY_EVENT_END)
return 0;
if (ev >= ADP5585_GPI_EVENT_START && ev <= ADP5585_GPI_EVENT_END)
return 0;
return dev_err_probe(adp5585->dev, -EINVAL,
"Invalid unlock/reset event(%u) for this device\n", ev);
}
if (ev >= ADP5585_KEY_EVENT_START && ev <= ADP5585_KEY_EVENT_END)
return 0;
if (ev >= ADP5585_GPI_EVENT_START && ev <= ADP5585_GPI_EVENT_END) {
/*
* Some variants of the adp5585 do not have the Row 5
* (meaning pin 6 or GPIO 6) available. Instead that pin serves
* as a reset pin. So, we need to make sure no event is
* configured for it.
*/
if (ev == (ADP5585_GPI_EVENT_START + 5))
return dev_err_probe(adp5585->dev, -EINVAL,
"Invalid unlock/reset event(%u). R5 not available\n",
ev);
return 0;
}
return dev_err_probe(adp5585->dev, -EINVAL,
"Invalid unlock/reset event(%u) for this device\n", ev);
}
static int adp5589_validate_event(const struct adp5585_dev *adp5585, unsigned int ev)
{
if (ev >= ADP5589_KEY_EVENT_START && ev <= ADP5589_KEY_EVENT_END)
return 0;
if (ev >= ADP5589_GPI_EVENT_START && ev <= ADP5589_GPI_EVENT_END)
return 0;
return dev_err_probe(adp5585->dev, -EINVAL,
"Invalid unlock/reset event(%u) for this device\n", ev);
}
static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp5585)
{
struct regmap_config *regmap_config;
switch (adp5585->variant) {
case ADP5585_00:
case ADP5585_01:
case ADP5585_02:
case ADP5585_03:
case ADP5585_04:
adp5585->id = ADP5585_MAN_ID_VALUE;
adp5585->regs = &adp5585_regs;
adp5585->n_pins = ADP5585_PIN_MAX;
adp5585->reset2_out = ADP5585_RESET2_OUT;
if (adp5585->variant == ADP5585_01)
adp5585->has_pin6 = true;
regmap_config = devm_kmemdup(adp5585->dev, &adp5585_regmap_config_template,
sizeof(*regmap_config), GFP_KERNEL);
break;
case ADP5589_00:
case ADP5589_01:
case ADP5589_02:
adp5585->id = ADP5589_MAN_ID_VALUE;
adp5585->regs = &adp5589_regs;
adp5585->has_unlock = true;
adp5585->has_pin6 = true;
adp5585->n_pins = ADP5589_PIN_MAX;
adp5585->reset2_out = ADP5589_RESET2_OUT;
regmap_config = devm_kmemdup(adp5585->dev, &adp5589_regmap_config_template,
sizeof(*regmap_config), GFP_KERNEL);
break;
default:
return ERR_PTR(-ENODEV);
}
if (!regmap_config)
return ERR_PTR(-ENOMEM);
regmap_config->reg_defaults_raw = adp5585_regmap_defaults[adp5585->variant];
return regmap_config;
}
static int adp5585_parse_ev_array(const struct adp5585_dev *adp5585, const char *prop, u32 *events,
u32 *n_events, u32 max_evs, bool reset_ev)
{
struct device *dev = adp5585->dev;
unsigned int ev;
int ret;
/*
* The device has the capability of handling special events through GPIs or a Keypad:
* unlock events: Unlock the keymap until one of the configured events is detected.
* reset events: Generate a reset pulse when one of the configured events is detected.
*/
ret = device_property_count_u32(dev, prop);
if (ret < 0)
return 0;
*n_events = ret;
if (!adp5585->has_unlock && !reset_ev)
return dev_err_probe(dev, -EOPNOTSUPP, "Unlock keys not supported\n");
if (*n_events > max_evs)
return dev_err_probe(dev, -EINVAL,
"Invalid number of keys(%u > %u) for %s\n",
*n_events, max_evs, prop);
ret = device_property_read_u32_array(dev, prop, events, *n_events);
if (ret)
return ret;
for (ev = 0; ev < *n_events; ev++) {
if (!reset_ev && events[ev] == ADP5589_UNLOCK_WILDCARD)
continue;
if (adp5585->id == ADP5585_MAN_ID_VALUE)
ret = adp5585_validate_event(adp5585, events[ev]);
else
ret = adp5589_validate_event(adp5585, events[ev]);
if (ret)
return ret;
}
return 0;
}
static int adp5585_unlock_ev_parse(struct adp5585_dev *adp5585)
{
struct device *dev = adp5585->dev;
int ret;
ret = adp5585_parse_ev_array(adp5585, "adi,unlock-events", adp5585->unlock_keys,
&adp5585->nkeys_unlock, ARRAY_SIZE(adp5585->unlock_keys),
false);
if (ret)
return ret;
if (!adp5585->nkeys_unlock)
return 0;
ret = device_property_read_u32(dev, "adi,unlock-trigger-sec", &adp5585->unlock_time);
if (!ret) {
if (adp5585->unlock_time > ADP5585_MAX_UNLOCK_TIME_SEC)
return dev_err_probe(dev, -EINVAL,
"Invalid unlock time(%u > %d)\n",
adp5585->unlock_time,
ADP5585_MAX_UNLOCK_TIME_SEC);
}
return 0;
}
static int adp5585_reset_ev_parse(struct adp5585_dev *adp5585)
{
struct device *dev = adp5585->dev;
u32 prop_val;
int ret;
ret = adp5585_parse_ev_array(adp5585, "adi,reset1-events", adp5585->reset1_keys,
&adp5585->nkeys_reset1,
ARRAY_SIZE(adp5585->reset1_keys), true);
if (ret)
return ret;
ret = adp5585_parse_ev_array(adp5585, "adi,reset2-events",
adp5585->reset2_keys,
&adp5585->nkeys_reset2,
ARRAY_SIZE(adp5585->reset2_keys), true);
if (ret)
return ret;
if (!adp5585->nkeys_reset1 && !adp5585->nkeys_reset2)
return 0;
if (adp5585->nkeys_reset1 && device_property_read_bool(dev, "adi,reset1-active-high"))
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET1_POL, 1);
if (adp5585->nkeys_reset2 && device_property_read_bool(dev, "adi,reset2-active-high"))
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET2_POL, 1);
if (device_property_read_bool(dev, "adi,rst-passthrough-enable"))
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RST_PASSTHRU_EN, 1);
ret = device_property_read_u32(dev, "adi,reset-trigger-ms", &prop_val);
if (!ret) {
switch (prop_val) {
case 0:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 0);
break;
case 1000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 1);
break;
case 1500:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 2);
break;
case 2000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 3);
break;
case 2500:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 4);
break;
case 3000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 5);
break;
case 3500:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 6);
break;
case 4000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 7);
break;
default:
return dev_err_probe(dev, -EINVAL,
"Invalid value(%u) for adi,reset-trigger-ms\n",
prop_val);
}
}
ret = device_property_read_u32(dev, "adi,reset-pulse-width-us", &prop_val);
if (!ret) {
switch (prop_val) {
case 500:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 0);
break;
case 1000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 1);
break;
case 2000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 2);
break;
case 10000:
adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 3);
break;
default:
return dev_err_probe(dev, -EINVAL,
"Invalid value(%u) for adi,reset-pulse-width-us\n",
prop_val);
}
return ret;
}
return 0;
}
static int adp5585_add_devices(const struct adp5585_dev *adp5585)
{
struct device *dev = adp5585->dev;
const struct mfd_cell *cells;
int ret;
if (adp5585->id == ADP5585_MAN_ID_VALUE)
cells = adp5585_devs;
else
cells = adp5589_devs;
if (device_property_present(dev, "#pwm-cells")) {
/* Make sure the PWM output pin is not used by the GPIO or INPUT devices */
__set_bit(ADP5585_PWM_OUT, adp5585->pin_usage);
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
&cells[ADP5585_DEV_PWM], 1, NULL, 0, NULL);
if (ret)
return dev_err_probe(dev, ret, "Failed to add PWM device\n");
}
if (device_property_present(dev, "#gpio-cells")) {
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
&cells[ADP5585_DEV_GPIO], 1, NULL, 0, NULL);
if (ret)
return dev_err_probe(dev, ret, "Failed to add GPIO device\n");
}
if (device_property_present(adp5585->dev, "adi,keypad-pins")) {
ret = devm_mfd_add_devices(adp5585->dev, PLATFORM_DEVID_AUTO,
&cells[ADP5585_DEV_INPUT], 1, NULL, 0, NULL);
if (ret)
return dev_err_probe(dev, ret, "Failed to add input device\n");
}
return 0;
}
static void adp5585_osc_disable(void *data)
{
const struct adp5585_dev *adp5585 = data;
regmap_write(adp5585->regmap, ADP5585_GENERAL_CFG, 0);
}
static void adp5585_report_events(struct adp5585_dev *adp5585, int ev_cnt)
{
unsigned int i;
for (i = 0; i < ev_cnt; i++) {
unsigned long key_val, key_press;
unsigned int key;
int ret;
ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &key);
if (ret)
return;
key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key);
key_press = FIELD_GET(ADP5585_KEV_EV_PRESS_MASK, key);
blocking_notifier_call_chain(&adp5585->event_notifier, key_val, (void *)key_press);
}
}
static irqreturn_t adp5585_irq(int irq, void *data)
{
struct adp5585_dev *adp5585 = data;
unsigned int status, ev_cnt;
int ret;
ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &status);
if (ret)
return IRQ_HANDLED;
if (status & ADP5585_OVRFLOW_INT)
dev_err_ratelimited(adp5585->dev, "Event overflow error\n");
if (!(status & ADP5585_EVENT_INT))
goto out_irq;
ret = regmap_read(adp5585->regmap, ADP5585_STATUS, &ev_cnt);
if (ret)
goto out_irq;
ev_cnt = FIELD_GET(ADP5585_EC_MASK, ev_cnt);
if (!ev_cnt)
goto out_irq;
adp5585_report_events(adp5585, ev_cnt);
out_irq:
regmap_write(adp5585->regmap, ADP5585_INT_STATUS, status);
return IRQ_HANDLED;
}
static int adp5585_setup(struct adp5585_dev *adp5585)
{
const struct adp5585_regs *regs = adp5585->regs;
unsigned int reg_val = 0, i;
int ret;
/* If pin_6 (ROW5/GPI6) is not available, make sure to mark it as "busy" */
if (!adp5585->has_pin6)
__set_bit(ADP5585_ROW5, adp5585->pin_usage);
/* Configure the device with reset and unlock events */
for (i = 0; i < adp5585->nkeys_unlock; i++) {
ret = regmap_write(adp5585->regmap, ADP5589_UNLOCK1 + i,
adp5585->unlock_keys[i] | ADP5589_UNLOCK_EV_PRESS);
if (ret)
return ret;
}
if (adp5585->nkeys_unlock) {
ret = regmap_update_bits(adp5585->regmap, ADP5589_UNLOCK_TIMERS,
ADP5589_UNLOCK_TIMER, adp5585->unlock_time);
if (ret)
return ret;
ret = regmap_set_bits(adp5585->regmap, ADP5589_LOCK_CFG, ADP5589_LOCK_EN);
if (ret)
return ret;
}
for (i = 0; i < adp5585->nkeys_reset1; i++) {
ret = regmap_write(adp5585->regmap, regs->reset1_event_a + i,
adp5585->reset1_keys[i] | ADP5585_RESET_EV_PRESS);
if (ret)
return ret;
/* Mark that pin as not usable for the INPUT and GPIO devices. */
__set_bit(ADP5585_RESET1_OUT, adp5585->pin_usage);
}
for (i = 0; i < adp5585->nkeys_reset2; i++) {
ret = regmap_write(adp5585->regmap, regs->reset2_event_a + i,
adp5585->reset2_keys[i] | ADP5585_RESET_EV_PRESS);
if (ret)
return ret;
__set_bit(adp5585->reset2_out, adp5585->pin_usage);
}
if (adp5585->nkeys_reset1 || adp5585->nkeys_reset2) {
ret = regmap_write(adp5585->regmap, regs->reset_cfg, adp5585->reset_cfg);
if (ret)
return ret;
/* If there's a reset1 event, then R4 is used as an output for the reset signal */
if (adp5585->nkeys_reset1)
reg_val = ADP5585_R4_EXTEND_CFG_RESET1;
/* If there's a reset2 event, then C4 is used as an output for the reset signal */
if (adp5585->nkeys_reset2)
reg_val |= ADP5585_C4_EXTEND_CFG_RESET2;
ret = regmap_update_bits(adp5585->regmap, regs->ext_cfg,
ADP5585_C4_EXTEND_CFG_MASK | ADP5585_R4_EXTEND_CFG_MASK,
reg_val);
if (ret)
return ret;
}
/* Clear any possible event by reading all the FIFO entries */
for (i = 0; i < ADP5585_EV_MAX; i++) {
ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &reg_val);
if (ret)
return ret;
}
ret = regmap_write(adp5585->regmap, regs->poll_ptime_cfg, adp5585->ev_poll_time);
if (ret)
return ret;
/*
* Enable the internal oscillator, as it's shared between multiple
* functions.
*/
ret = regmap_write(adp5585->regmap, regs->gen_cfg,
ADP5585_OSC_FREQ_500KHZ | ADP5585_INT_CFG | ADP5585_OSC_EN);
if (ret)
return ret;
return devm_add_action_or_reset(adp5585->dev, adp5585_osc_disable, adp5585);
}
static int adp5585_parse_fw(struct adp5585_dev *adp5585)
{
unsigned int prop_val;
int ret;
ret = device_property_read_u32(adp5585->dev, "poll-interval", &prop_val);
if (!ret) {
adp5585->ev_poll_time = prop_val / 10 - 1;
/*
* ev_poll_time is the raw value to be written on the register and 0 to 3 are the
* valid values.
*/
if (adp5585->ev_poll_time > 3)
return dev_err_probe(adp5585->dev, -EINVAL,
"Invalid value(%u) for poll-interval\n", prop_val);
}
ret = adp5585_unlock_ev_parse(adp5585);
if (ret)
return ret;
return adp5585_reset_ev_parse(adp5585);
}
static void adp5585_irq_disable(void *data)
{
struct adp5585_dev *adp5585 = data;
regmap_write(adp5585->regmap, adp5585->regs->int_en, 0);
}
static int adp5585_irq_enable(struct i2c_client *i2c,
struct adp5585_dev *adp5585)
{
const struct adp5585_regs *regs = adp5585->regs;
unsigned int stat;
int ret;
if (i2c->irq <= 0)
return 0;
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, adp5585_irq,
IRQF_ONESHOT, i2c->name, adp5585);
if (ret)
return ret;
/*
* Clear any possible outstanding interrupt before enabling them. We do that by reading
* the status register and writing back the same value.
*/
ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &stat);
if (ret)
return ret;
ret = regmap_write(adp5585->regmap, ADP5585_INT_STATUS, stat);
if (ret)
return ret;
ret = regmap_write(adp5585->regmap, regs->int_en, ADP5585_OVRFLOW_IEN | ADP5585_EVENT_IEN);
if (ret)
return ret;
return devm_add_action_or_reset(&i2c->dev, adp5585_irq_disable, adp5585);
}
static int adp5585_i2c_probe(struct i2c_client *i2c)
{
const struct regmap_config *regmap_config;
struct regmap_config *regmap_config;
struct adp5585_dev *adp5585;
struct gpio_desc *gpio;
unsigned int id;
int ret;
@ -122,8 +700,36 @@ static int adp5585_i2c_probe(struct i2c_client *i2c)
return -ENOMEM;
i2c_set_clientdata(i2c, adp5585);
adp5585->dev = &i2c->dev;
adp5585->irq = i2c->irq;
BLOCKING_INIT_NOTIFIER_HEAD(&adp5585->event_notifier);
adp5585->variant = (enum adp5585_variant)(uintptr_t)i2c_get_match_data(i2c);
if (!adp5585->variant)
return -ENODEV;
regmap_config = adp5585_fill_variant_config(adp5585);
if (IS_ERR(regmap_config))
return PTR_ERR(regmap_config);
ret = devm_regulator_get_enable(&i2c->dev, "vdd");
if (ret)
return ret;
gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
/*
* Note the timings are not documented anywhere in the datasheet. They are just
* reasonable values that work.
*/
if (gpio) {
fsleep(30);
gpiod_set_value_cansleep(gpio, 0);
fsleep(60);
}
regmap_config = i2c_get_match_data(i2c);
adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config);
if (IS_ERR(adp5585->regmap))
return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap),
@ -134,24 +740,37 @@ static int adp5585_i2c_probe(struct i2c_client *i2c)
return dev_err_probe(&i2c->dev, ret,
"Failed to read device ID\n");
if ((id & ADP5585_MAN_ID_MASK) != ADP5585_MAN_ID_VALUE)
id &= ADP5585_MAN_ID_MASK;
if (id != adp5585->id)
return dev_err_probe(&i2c->dev, -ENODEV,
"Invalid device ID 0x%02x\n", id);
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
adp5585_devs, ARRAY_SIZE(adp5585_devs),
NULL, 0, NULL);
if (ret)
return dev_err_probe(&i2c->dev, ret,
"Failed to add child devices\n");
adp5585->pin_usage = devm_bitmap_zalloc(&i2c->dev, adp5585->n_pins, GFP_KERNEL);
if (!adp5585->pin_usage)
return -ENOMEM;
return 0;
ret = adp5585_parse_fw(adp5585);
if (ret)
return ret;
ret = adp5585_setup(adp5585);
if (ret)
return ret;
ret = adp5585_add_devices(adp5585);
if (ret)
return ret;
return adp5585_irq_enable(i2c, adp5585);
}
static int adp5585_suspend(struct device *dev)
{
struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
if (adp5585->irq)
disable_irq(adp5585->irq);
regcache_cache_only(adp5585->regmap, true);
return 0;
@ -160,11 +779,19 @@ static int adp5585_suspend(struct device *dev)
static int adp5585_resume(struct device *dev)
{
struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
int ret;
regcache_cache_only(adp5585->regmap, false);
regcache_mark_dirty(adp5585->regmap);
return regcache_sync(adp5585->regmap);
ret = regcache_sync(adp5585->regmap);
if (ret)
return ret;
if (adp5585->irq)
enable_irq(adp5585->irq);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume);
@ -172,19 +799,31 @@ static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume);
static const struct of_device_id adp5585_of_match[] = {
{
.compatible = "adi,adp5585-00",
.data = &adp5585_regmap_configs[ADP5585_REGMAP_00],
.data = (void *)ADP5585_00,
}, {
.compatible = "adi,adp5585-01",
.data = &adp5585_regmap_configs[ADP5585_REGMAP_00],
.data = (void *)ADP5585_01,
}, {
.compatible = "adi,adp5585-02",
.data = &adp5585_regmap_configs[ADP5585_REGMAP_02],
.data = (void *)ADP5585_02,
}, {
.compatible = "adi,adp5585-03",
.data = &adp5585_regmap_configs[ADP5585_REGMAP_00],
.data = (void *)ADP5585_03,
}, {
.compatible = "adi,adp5585-04",
.data = &adp5585_regmap_configs[ADP5585_REGMAP_04],
.data = (void *)ADP5585_04,
}, {
.compatible = "adi,adp5589-00",
.data = (void *)ADP5589_00,
}, {
.compatible = "adi,adp5589-01",
.data = (void *)ADP5589_01,
}, {
.compatible = "adi,adp5589-02",
.data = (void *)ADP5589_02,
}, {
.compatible = "adi,adp5589",
.data = (void *)ADP5589_00,
},
{ /* sentinel */ }
};

View File

@ -33,21 +33,33 @@
#define ADP5585_PWM_MIN_PERIOD_NS (2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
#define ADP5585_PWM_MAX_PERIOD_NS (2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
struct adp5585_pwm_chip {
unsigned int pwm_cfg;
unsigned int pwm_offt_low;
unsigned int pwm_ont_low;
};
struct adp5585_pwm {
const struct adp5585_pwm_chip *info;
struct regmap *regmap;
unsigned int ext_cfg;
};
static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct regmap *regmap = pwmchip_get_drvdata(chip);
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
/* Configure the R3 pin as PWM output. */
return regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C,
return regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
ADP5585_R3_EXTEND_CFG_MASK,
ADP5585_R3_EXTEND_CFG_PWM_OUT);
}
static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct regmap *regmap = pwmchip_get_drvdata(chip);
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C,
regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
ADP5585_R3_EXTEND_CFG_MASK,
ADP5585_R3_EXTEND_CFG_GPIO4);
}
@ -56,15 +68,16 @@ static int pwm_adp5585_apply(struct pwm_chip *chip,
struct pwm_device *pwm,
const struct pwm_state *state)
{
struct regmap *regmap = pwmchip_get_drvdata(chip);
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
const struct adp5585_pwm_chip *info = adp5585_pwm->info;
struct regmap *regmap = adp5585_pwm->regmap;
u64 period, duty_cycle;
u32 on, off;
__le16 val;
int ret;
if (!state->enabled) {
regmap_clear_bits(regmap, ADP5585_GENERAL_CFG, ADP5585_OSC_EN);
regmap_clear_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN);
regmap_clear_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
return 0;
}
@ -85,45 +98,43 @@ static int pwm_adp5585_apply(struct pwm_chip *chip,
off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on;
val = cpu_to_le16(off);
ret = regmap_bulk_write(regmap, ADP5585_PWM_OFFT_LOW, &val, 2);
ret = regmap_bulk_write(regmap, info->pwm_offt_low, &val, 2);
if (ret)
return ret;
val = cpu_to_le16(on);
ret = regmap_bulk_write(regmap, ADP5585_PWM_ONT_LOW, &val, 2);
ret = regmap_bulk_write(regmap, info->pwm_ont_low, &val, 2);
if (ret)
return ret;
/* Enable PWM in continuous mode and no external AND'ing. */
ret = regmap_update_bits(regmap, ADP5585_PWM_CFG,
ret = regmap_update_bits(regmap, info->pwm_cfg,
ADP5585_PWM_IN_AND | ADP5585_PWM_MODE |
ADP5585_PWM_EN, ADP5585_PWM_EN);
if (ret)
return ret;
ret = regmap_set_bits(regmap, ADP5585_GENERAL_CFG, ADP5585_OSC_EN);
if (ret)
return ret;
return regmap_set_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN);
return regmap_set_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
}
static int pwm_adp5585_get_state(struct pwm_chip *chip,
struct pwm_device *pwm,
struct pwm_state *state)
{
struct regmap *regmap = pwmchip_get_drvdata(chip);
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
const struct adp5585_pwm_chip *info = adp5585_pwm->info;
struct regmap *regmap = adp5585_pwm->regmap;
unsigned int on, off;
unsigned int val;
__le16 on_off;
int ret;
ret = regmap_bulk_read(regmap, ADP5585_PWM_OFFT_LOW, &on_off, 2);
ret = regmap_bulk_read(regmap, info->pwm_offt_low, &on_off, 2);
if (ret)
return ret;
off = le16_to_cpu(on_off);
ret = regmap_bulk_read(regmap, ADP5585_PWM_ONT_LOW, &on_off, 2);
ret = regmap_bulk_read(regmap, info->pwm_ont_low, &on_off, 2);
if (ret)
return ret;
on = le16_to_cpu(on_off);
@ -133,7 +144,7 @@ static int pwm_adp5585_get_state(struct pwm_chip *chip,
state->polarity = PWM_POLARITY_NORMAL;
regmap_read(regmap, ADP5585_PWM_CFG, &val);
regmap_read(regmap, info->pwm_cfg, &val);
state->enabled = !!(val & ADP5585_PWM_EN);
return 0;
@ -148,18 +159,28 @@ static const struct pwm_ops adp5585_pwm_ops = {
static int adp5585_pwm_probe(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
struct device *dev = &pdev->dev;
struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
struct adp5585_pwm *adp5585_pwm;
struct pwm_chip *chip;
int ret;
chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM, 0);
chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM,
sizeof(*adp5585_pwm));
if (IS_ERR(chip))
return PTR_ERR(chip);
adp5585_pwm = pwmchip_get_drvdata(chip);
adp5585_pwm->regmap = adp5585->regmap;
adp5585_pwm->ext_cfg = adp5585->regs->ext_cfg;
adp5585_pwm->info = (const struct adp5585_pwm_chip *)id->driver_data;
if (!adp5585_pwm->info)
return -ENODEV;
device_set_of_node_from_dev(dev, dev->parent);
pwmchip_set_drvdata(chip, adp5585->regmap);
chip->ops = &adp5585_pwm_ops;
ret = devm_pwmchip_add(dev, chip);
@ -169,8 +190,21 @@ static int adp5585_pwm_probe(struct platform_device *pdev)
return 0;
}
static const struct adp5585_pwm_chip adp5589_pwm_chip_info = {
.pwm_cfg = ADP5585_PWM_CFG,
.pwm_offt_low = ADP5585_PWM_OFFT_LOW,
.pwm_ont_low = ADP5585_PWM_ONT_LOW,
};
static const struct adp5585_pwm_chip adp5585_pwm_chip_info = {
.pwm_cfg = ADP5589_PWM_CFG,
.pwm_offt_low = ADP5589_PWM_OFFT_LOW,
.pwm_ont_low = ADP5589_PWM_ONT_LOW,
};
static const struct platform_device_id adp5585_pwm_id_table[] = {
{ "adp5585-pwm" },
{ "adp5585-pwm", (kernel_ulong_t)&adp5585_pwm_chip_info },
{ "adp5589-pwm", (kernel_ulong_t)&adp5589_pwm_chip_info },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(platform, adp5585_pwm_id_table);

View File

@ -10,13 +10,20 @@
#define __MFD_ADP5585_H_
#include <linux/bits.h>
#include <linux/notifier.h>
#define ADP5585_ID 0x00
#define ADP5585_MAN_ID_VALUE 0x20
#define ADP5585_MAN_ID_MASK GENMASK(7, 4)
#define ADP5585_REV_ID_MASK GENMASK(3, 0)
#define ADP5585_INT_STATUS 0x01
#define ADP5585_OVRFLOW_INT BIT(2)
#define ADP5585_EVENT_INT BIT(0)
#define ADP5585_STATUS 0x02
#define ADP5585_EC_MASK GENMASK(4, 0)
#define ADP5585_FIFO_1 0x03
#define ADP5585_KEV_EV_PRESS_MASK BIT(7)
#define ADP5585_KEY_EVENT_MASK GENMASK(6, 0)
#define ADP5585_FIFO_2 0x04
#define ADP5585_FIFO_3 0x05
#define ADP5585_FIFO_4 0x06
@ -32,6 +39,7 @@
#define ADP5585_FIFO_14 0x10
#define ADP5585_FIFO_15 0x11
#define ADP5585_FIFO_16 0x12
#define ADP5585_EV_MAX (ADP5585_FIFO_16 - ADP5585_FIFO_1 + 1)
#define ADP5585_GPI_INT_STAT_A 0x13
#define ADP5585_GPI_INT_STAT_B 0x14
#define ADP5585_GPI_STATUS_A 0x15
@ -60,6 +68,7 @@
#define ADP5585_GPIO_DIRECTION_A 0x27
#define ADP5585_GPIO_DIRECTION_B 0x28
#define ADP5585_RESET1_EVENT_A 0x29
#define ADP5585_RESET_EV_PRESS BIT(7)
#define ADP5585_RESET1_EVENT_B 0x2a
#define ADP5585_RESET1_EVENT_C 0x2b
#define ADP5585_RESET2_EVENT_A 0x2c
@ -104,23 +113,114 @@
#define ADP5585_INT_CFG BIT(1)
#define ADP5585_RST_CFG BIT(0)
#define ADP5585_INT_EN 0x3c
#define ADP5585_OVRFLOW_IEN BIT(2)
#define ADP5585_EVENT_IEN BIT(0)
#define ADP5585_MAX_REG ADP5585_INT_EN
/*
* Bank 0 covers pins "GPIO 1/R0" to "GPIO 6/R5", numbered 0 to 5 by the
* driver, and bank 1 covers pins "GPIO 7/C0" to "GPIO 11/C4", numbered 6 to
* 10. Some variants of the ADP5585 don't support "GPIO 6/R5". As the driver
* uses identical GPIO numbering for all variants to avoid confusion, GPIO 5 is
* marked as reserved in the device tree for variants that don't support it.
*/
#define ADP5585_BANK(n) ((n) >= 6 ? 1 : 0)
#define ADP5585_BIT(n) ((n) >= 6 ? BIT((n) - 6) : BIT(n))
#define ADP5585_PIN_MAX 11
#define ADP5585_MAX_UNLOCK_TIME_SEC 7
#define ADP5585_KEY_EVENT_START 1
#define ADP5585_KEY_EVENT_END 25
#define ADP5585_GPI_EVENT_START 37
#define ADP5585_GPI_EVENT_END 47
#define ADP5585_ROW5_KEY_EVENT_START 1
#define ADP5585_ROW5_KEY_EVENT_END 30
#define ADP5585_PWM_OUT 3
#define ADP5585_RESET1_OUT 4
#define ADP5585_RESET2_OUT 9
#define ADP5585_ROW5 5
/* ADP5589 */
#define ADP5589_MAN_ID_VALUE 0x10
#define ADP5589_GPI_STATUS_A 0x16
#define ADP5589_GPI_STATUS_C 0x18
#define ADP5589_RPULL_CONFIG_A 0x19
#define ADP5589_GPI_INT_LEVEL_A 0x1e
#define ADP5589_GPI_EVENT_EN_A 0x21
#define ADP5589_DEBOUNCE_DIS_A 0x27
#define ADP5589_GPO_DATA_OUT_A 0x2a
#define ADP5589_GPO_OUT_MODE_A 0x2d
#define ADP5589_GPIO_DIRECTION_A 0x30
#define ADP5589_UNLOCK1 0x33
#define ADP5589_UNLOCK_EV_PRESS BIT(7)
#define ADP5589_UNLOCK_TIMERS 0x36
#define ADP5589_UNLOCK_TIMER GENMASK(2, 0)
#define ADP5589_LOCK_CFG 0x37
#define ADP5589_LOCK_EN BIT(0)
#define ADP5589_RESET1_EVENT_A 0x38
#define ADP5589_RESET2_EVENT_A 0x3B
#define ADP5589_RESET_CFG 0x3D
#define ADP5585_RESET2_POL BIT(7)
#define ADP5585_RESET1_POL BIT(6)
#define ADP5585_RST_PASSTHRU_EN BIT(5)
#define ADP5585_RESET_TRIG_TIME GENMASK(4, 2)
#define ADP5585_PULSE_WIDTH GENMASK(1, 0)
#define ADP5589_PWM_OFFT_LOW 0x3e
#define ADP5589_PWM_ONT_LOW 0x40
#define ADP5589_PWM_CFG 0x42
#define ADP5589_POLL_PTIME_CFG 0x48
#define ADP5589_PIN_CONFIG_A 0x49
#define ADP5589_PIN_CONFIG_D 0x4C
#define ADP5589_GENERAL_CFG 0x4d
#define ADP5589_INT_EN 0x4e
#define ADP5589_MAX_REG ADP5589_INT_EN
#define ADP5589_PIN_MAX 19
#define ADP5589_KEY_EVENT_START 1
#define ADP5589_KEY_EVENT_END 88
#define ADP5589_GPI_EVENT_START 97
#define ADP5589_GPI_EVENT_END 115
#define ADP5589_UNLOCK_WILDCARD 127
#define ADP5589_RESET2_OUT 12
struct regmap;
enum adp5585_variant {
ADP5585_00 = 1,
ADP5585_01,
ADP5585_02,
ADP5585_03,
ADP5585_04,
ADP5589_00,
ADP5589_01,
ADP5589_02,
ADP5585_MAX
};
struct adp5585_regs {
unsigned int gen_cfg;
unsigned int ext_cfg;
unsigned int int_en;
unsigned int poll_ptime_cfg;
unsigned int reset_cfg;
unsigned int reset1_event_a;
unsigned int reset2_event_a;
unsigned int pin_cfg_a;
};
struct adp5585_dev {
struct device *dev;
struct regmap *regmap;
const struct adp5585_regs *regs;
struct blocking_notifier_head event_notifier;
unsigned long *pin_usage;
unsigned int n_pins;
unsigned int reset2_out;
enum adp5585_variant variant;
unsigned int id;
bool has_unlock;
bool has_pin6;
int irq;
unsigned int ev_poll_time;
unsigned int unlock_time;
unsigned int unlock_keys[2];
unsigned int nkeys_unlock;
unsigned int reset1_keys[3];
unsigned int nkeys_reset1;
unsigned int reset2_keys[2];
unsigned int nkeys_reset2;
u8 reset_cfg;
};
#endif