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.

Merge branches 'ib-mfd-for-iio-power-6.12' and 'ib-mfd-gpio-pwm-6.12' into ibs-for-mfd-merged

+876 -4
+92
Documentation/devicetree/bindings/mfd/adi,adp5585.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mfd/adi,adp5585.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Analog Devices ADP5585 Keypad Decoder and I/O Expansion 8 + 9 + maintainers: 10 + - Laurent Pinchart <laurent.pinchart@ideasonboard.com> 11 + 12 + description: 13 + The ADP5585 is a 10/11 input/output port expander with a built in keypad 14 + matrix decoder, programmable logic, reset generator, and PWM generator. 15 + 16 + properties: 17 + compatible: 18 + items: 19 + - enum: 20 + - adi,adp5585-00 # Default 21 + - adi,adp5585-01 # 11 GPIOs 22 + - adi,adp5585-02 # No pull-up resistors by default on special pins 23 + - adi,adp5585-03 # Alternate I2C address 24 + - adi,adp5585-04 # Pull-down resistors on all pins by default 25 + - const: adi,adp5585 26 + 27 + reg: 28 + maxItems: 1 29 + 30 + interrupts: 31 + maxItems: 1 32 + 33 + vdd-supply: true 34 + 35 + gpio-controller: true 36 + 37 + '#gpio-cells': 38 + const: 2 39 + 40 + gpio-reserved-ranges: true 41 + 42 + "#pwm-cells": 43 + const: 3 44 + 45 + required: 46 + - compatible 47 + - reg 48 + - gpio-controller 49 + - "#gpio-cells" 50 + - "#pwm-cells" 51 + 52 + allOf: 53 + - if: 54 + properties: 55 + compatible: 56 + contains: 57 + const: adi,adp5585-01 58 + then: 59 + properties: 60 + gpio-reserved-ranges: false 61 + else: 62 + properties: 63 + gpio-reserved-ranges: 64 + maxItems: 1 65 + items: 66 + items: 67 + - const: 5 68 + - const: 1 69 + 70 + additionalProperties: false 71 + 72 + examples: 73 + - | 74 + i2c { 75 + #address-cells = <1>; 76 + #size-cells = <0>; 77 + 78 + io-expander@34 { 79 + compatible = "adi,adp5585-00", "adi,adp5585"; 80 + reg = <0x34>; 81 + 82 + vdd-supply = <&reg_3v3>; 83 + 84 + gpio-controller; 85 + #gpio-cells = <2>; 86 + gpio-reserved-ranges = <5 1>; 87 + 88 + #pwm-cells = <3>; 89 + }; 90 + }; 91 + 92 + ...
-4
Documentation/devicetree/bindings/trivial-devices.yaml
··· 38 38 - ad,adm9240 39 39 # AD5110 - Nonvolatile Digital Potentiometer 40 40 - adi,ad5110 41 - # Analog Devices ADP5585 Keypad Decoder and I/O Expansion 42 - - adi,adp5585 43 - # Analog Devices ADP5585 Keypad Decoder and I/O Expansion with support for Row5 44 - - adi,adp5585-02 45 41 # Analog Devices ADP5589 Keypad Decoder and I/O Expansion 46 42 - adi,adp5589 47 43 # Analog Devices LT7182S Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher
+11
MAINTAINERS
··· 537 537 F: drivers/mfd/adp5520.c 538 538 F: drivers/video/backlight/adp5520_bl.c 539 539 540 + ADP5585 GPIO EXPANDER, PWM AND KEYPAD CONTROLLER DRIVER 541 + M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 542 + L: linux-gpio@vger.kernel.org 543 + L: linux-pwm@vger.kernel.org 544 + S: Maintained 545 + F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml 546 + F: drivers/gpio/gpio-adp5585.c 547 + F: drivers/mfd/adp5585.c 548 + F: drivers/pwm/pwm-adp5585.c 549 + F: include/linux/mfd/adp5585.h 550 + 540 551 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) 541 552 M: Michael Hennerich <michael.hennerich@analog.com> 542 553 S: Supported
+7
drivers/gpio/Kconfig
··· 1233 1233 This option enables support for on-chip GPIO found 1234 1234 on Analog Devices ADP5520 PMICs. 1235 1235 1236 + config GPIO_ADP5585 1237 + tristate "GPIO Support for ADP5585" 1238 + depends on MFD_ADP5585 1239 + help 1240 + This option enables support for the GPIO function found in the Analog 1241 + Devices ADP5585. 1242 + 1236 1243 config GPIO_ALTERA_A10SR 1237 1244 tristate "Altera Arria10 System Resource GPIO" 1238 1245 depends on MFD_ALTERA_A10SR
+1
drivers/gpio/Makefile
··· 26 26 obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o 27 27 obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o 28 28 obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o 29 + obj-$(CONFIG_GPIO_ADP5585) += gpio-adp5585.o 29 30 obj-$(CONFIG_GPIO_AGGREGATOR) += gpio-aggregator.o 30 31 obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o 31 32 obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
+229
drivers/gpio/gpio-adp5585.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Analog Devices ADP5585 GPIO driver 4 + * 5 + * Copyright 2022 NXP 6 + * Copyright 2024 Ideas on Board Oy 7 + */ 8 + 9 + #include <linux/device.h> 10 + #include <linux/gpio/driver.h> 11 + #include <linux/mfd/adp5585.h> 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/types.h> 16 + 17 + #define ADP5585_GPIO_MAX 11 18 + 19 + struct adp5585_gpio_dev { 20 + struct gpio_chip gpio_chip; 21 + struct regmap *regmap; 22 + }; 23 + 24 + static int adp5585_gpio_get_direction(struct gpio_chip *chip, unsigned int off) 25 + { 26 + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); 27 + unsigned int bank = ADP5585_BANK(off); 28 + unsigned int bit = ADP5585_BIT(off); 29 + unsigned int val; 30 + 31 + regmap_read(adp5585_gpio->regmap, ADP5585_GPIO_DIRECTION_A + bank, &val); 32 + 33 + return val & bit ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; 34 + } 35 + 36 + static int adp5585_gpio_direction_input(struct gpio_chip *chip, unsigned int off) 37 + { 38 + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); 39 + unsigned int bank = ADP5585_BANK(off); 40 + unsigned int bit = ADP5585_BIT(off); 41 + 42 + return regmap_clear_bits(adp5585_gpio->regmap, 43 + ADP5585_GPIO_DIRECTION_A + bank, bit); 44 + } 45 + 46 + static int adp5585_gpio_direction_output(struct gpio_chip *chip, unsigned int off, int val) 47 + { 48 + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); 49 + unsigned int bank = ADP5585_BANK(off); 50 + unsigned int bit = ADP5585_BIT(off); 51 + int ret; 52 + 53 + ret = regmap_update_bits(adp5585_gpio->regmap, 54 + ADP5585_GPO_DATA_OUT_A + bank, bit, 55 + val ? bit : 0); 56 + if (ret) 57 + return ret; 58 + 59 + return regmap_set_bits(adp5585_gpio->regmap, 60 + ADP5585_GPIO_DIRECTION_A + bank, bit); 61 + } 62 + 63 + static int adp5585_gpio_get_value(struct gpio_chip *chip, unsigned int off) 64 + { 65 + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); 66 + unsigned int bank = ADP5585_BANK(off); 67 + unsigned int bit = ADP5585_BIT(off); 68 + unsigned int reg; 69 + unsigned int val; 70 + 71 + /* 72 + * The input status register doesn't reflect the pin state when the 73 + * GPIO is configured as an output. Check the direction, and read the 74 + * input status from GPI_STATUS or output value from GPO_DATA_OUT 75 + * accordingly. 76 + * 77 + * We don't need any locking, as concurrent access to the same GPIO 78 + * isn't allowed by the GPIO API, so there's no risk of the 79 + * .direction_input(), .direction_output() or .set() operations racing 80 + * with this. 81 + */ 82 + regmap_read(adp5585_gpio->regmap, ADP5585_GPIO_DIRECTION_A + bank, &val); 83 + reg = val & bit ? ADP5585_GPO_DATA_OUT_A : ADP5585_GPI_STATUS_A; 84 + regmap_read(adp5585_gpio->regmap, reg + bank, &val); 85 + 86 + return !!(val & bit); 87 + } 88 + 89 + static void adp5585_gpio_set_value(struct gpio_chip *chip, unsigned int off, int val) 90 + { 91 + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); 92 + unsigned int bank = ADP5585_BANK(off); 93 + unsigned int bit = ADP5585_BIT(off); 94 + 95 + regmap_update_bits(adp5585_gpio->regmap, ADP5585_GPO_DATA_OUT_A + bank, 96 + bit, val ? bit : 0); 97 + } 98 + 99 + static int adp5585_gpio_set_bias(struct adp5585_gpio_dev *adp5585_gpio, 100 + unsigned int off, unsigned int bias) 101 + { 102 + unsigned int bit, reg, mask, val; 103 + 104 + /* 105 + * The bias configuration fields are 2 bits wide and laid down in 106 + * consecutive registers ADP5585_RPULL_CONFIG_*, with a hole of 4 bits 107 + * after R5. 108 + */ 109 + bit = off * 2 + (off > 5 ? 4 : 0); 110 + reg = ADP5585_RPULL_CONFIG_A + bit / 8; 111 + mask = ADP5585_Rx_PULL_CFG_MASK << (bit % 8); 112 + val = bias << (bit % 8); 113 + 114 + return regmap_update_bits(adp5585_gpio->regmap, reg, mask, val); 115 + } 116 + 117 + static int adp5585_gpio_set_drive(struct adp5585_gpio_dev *adp5585_gpio, 118 + unsigned int off, enum pin_config_param drive) 119 + { 120 + unsigned int bank = ADP5585_BANK(off); 121 + unsigned int bit = ADP5585_BIT(off); 122 + 123 + return regmap_update_bits(adp5585_gpio->regmap, 124 + ADP5585_GPO_OUT_MODE_A + bank, bit, 125 + drive == PIN_CONFIG_DRIVE_OPEN_DRAIN ? bit : 0); 126 + } 127 + 128 + static int adp5585_gpio_set_debounce(struct adp5585_gpio_dev *adp5585_gpio, 129 + unsigned int off, unsigned int debounce) 130 + { 131 + unsigned int bank = ADP5585_BANK(off); 132 + unsigned int bit = ADP5585_BIT(off); 133 + 134 + return regmap_update_bits(adp5585_gpio->regmap, 135 + ADP5585_DEBOUNCE_DIS_A + bank, bit, 136 + debounce ? 0 : bit); 137 + } 138 + 139 + static int adp5585_gpio_set_config(struct gpio_chip *chip, unsigned int off, 140 + unsigned long config) 141 + { 142 + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); 143 + enum pin_config_param param = pinconf_to_config_param(config); 144 + u32 arg = pinconf_to_config_argument(config); 145 + 146 + switch (param) { 147 + case PIN_CONFIG_BIAS_DISABLE: 148 + return adp5585_gpio_set_bias(adp5585_gpio, off, 149 + ADP5585_Rx_PULL_CFG_DISABLE); 150 + 151 + case PIN_CONFIG_BIAS_PULL_DOWN: 152 + return adp5585_gpio_set_bias(adp5585_gpio, off, arg ? 153 + ADP5585_Rx_PULL_CFG_PD_300K : 154 + ADP5585_Rx_PULL_CFG_DISABLE); 155 + 156 + case PIN_CONFIG_BIAS_PULL_UP: 157 + return adp5585_gpio_set_bias(adp5585_gpio, off, arg ? 158 + ADP5585_Rx_PULL_CFG_PU_300K : 159 + ADP5585_Rx_PULL_CFG_DISABLE); 160 + 161 + case PIN_CONFIG_DRIVE_OPEN_DRAIN: 162 + case PIN_CONFIG_DRIVE_PUSH_PULL: 163 + return adp5585_gpio_set_drive(adp5585_gpio, off, param); 164 + 165 + case PIN_CONFIG_INPUT_DEBOUNCE: 166 + return adp5585_gpio_set_debounce(adp5585_gpio, off, arg); 167 + 168 + default: 169 + return -ENOTSUPP; 170 + }; 171 + } 172 + 173 + static int adp5585_gpio_probe(struct platform_device *pdev) 174 + { 175 + struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); 176 + struct adp5585_gpio_dev *adp5585_gpio; 177 + struct device *dev = &pdev->dev; 178 + struct gpio_chip *gc; 179 + int ret; 180 + 181 + adp5585_gpio = devm_kzalloc(dev, sizeof(*adp5585_gpio), GFP_KERNEL); 182 + if (!adp5585_gpio) 183 + return -ENOMEM; 184 + 185 + adp5585_gpio->regmap = adp5585->regmap; 186 + 187 + device_set_of_node_from_dev(dev, dev->parent); 188 + 189 + gc = &adp5585_gpio->gpio_chip; 190 + gc->parent = dev; 191 + gc->get_direction = adp5585_gpio_get_direction; 192 + gc->direction_input = adp5585_gpio_direction_input; 193 + gc->direction_output = adp5585_gpio_direction_output; 194 + gc->get = adp5585_gpio_get_value; 195 + gc->set = adp5585_gpio_set_value; 196 + gc->set_config = adp5585_gpio_set_config; 197 + gc->can_sleep = true; 198 + 199 + gc->base = -1; 200 + gc->ngpio = ADP5585_GPIO_MAX; 201 + gc->label = pdev->name; 202 + gc->owner = THIS_MODULE; 203 + 204 + ret = devm_gpiochip_add_data(dev, &adp5585_gpio->gpio_chip, 205 + adp5585_gpio); 206 + if (ret) 207 + return dev_err_probe(dev, ret, "failed to add GPIO chip\n"); 208 + 209 + return 0; 210 + } 211 + 212 + static const struct platform_device_id adp5585_gpio_id_table[] = { 213 + { "adp5585-gpio" }, 214 + { /* Sentinel */ } 215 + }; 216 + MODULE_DEVICE_TABLE(platform, adp5585_gpio_id_table); 217 + 218 + static struct platform_driver adp5585_gpio_driver = { 219 + .driver = { 220 + .name = "adp5585-gpio", 221 + }, 222 + .probe = adp5585_gpio_probe, 223 + .id_table = adp5585_gpio_id_table, 224 + }; 225 + module_platform_driver(adp5585_gpio_driver); 226 + 227 + MODULE_AUTHOR("Haibo Chen <haibo.chen@nxp.com>"); 228 + MODULE_DESCRIPTION("GPIO ADP5585 Driver"); 229 + MODULE_LICENSE("GPL");
+12
drivers/mfd/Kconfig
··· 20 20 This is the core driver for CS5535/CS5536 MFD functions. This is 21 21 necessary for using the board's GPIO and MFGPT functionality. 22 22 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 + 23 35 config MFD_ALTERA_A10SR 24 36 bool "Altera Arria10 DevKit System Resource chip" 25 37 depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF
+1
drivers/mfd/Makefile
··· 193 193 obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o 194 194 obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 195 195 obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 196 + obj-$(CONFIG_MFD_ADP5585) += adp5585.o 196 197 obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o 197 198 obj-$(CONFIG_MFD_INTEL_QUARK_I2C_GPIO) += intel_quark_i2c_gpio.o 198 199 obj-$(CONFIG_LPC_SCH) += lpc_sch.o
+205
drivers/mfd/adp5585.c
··· 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 <haibo.chen@nxp.com>"); 205 + MODULE_LICENSE("GPL");
+7
drivers/pwm/Kconfig
··· 47 47 To compile this driver as a module, choose M here: the module 48 48 will be called pwm-ab8500. 49 49 50 + config PWM_ADP5585 51 + tristate "ADP5585 PWM support" 52 + depends on MFD_ADP5585 53 + help 54 + This option enables support for the PWM function found in the Analog 55 + Devices ADP5585. 56 + 50 57 config PWM_APPLE 51 58 tristate "Apple SoC PWM support" 52 59 depends on ARCH_APPLE || COMPILE_TEST
+1
drivers/pwm/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_PWM) += core.o 3 3 obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o 4 + obj-$(CONFIG_PWM_ADP5585) += pwm-adp5585.o 4 5 obj-$(CONFIG_PWM_APPLE) += pwm-apple.o 5 6 obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o 6 7 obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o
+184
drivers/pwm/pwm-adp5585.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Analog Devices ADP5585 PWM driver 4 + * 5 + * Copyright 2022 NXP 6 + * Copyright 2024 Ideas on Board Oy 7 + * 8 + * Limitations: 9 + * - The .apply() operation executes atomically, but may not wait for the 10 + * period to complete (this is not documented and would need to be tested). 11 + * - Disabling the PWM drives the output pin to a low level immediately. 12 + * - The hardware can only generate normal polarity output. 13 + */ 14 + 15 + #include <asm/byteorder.h> 16 + 17 + #include <linux/device.h> 18 + #include <linux/err.h> 19 + #include <linux/math64.h> 20 + #include <linux/mfd/adp5585.h> 21 + #include <linux/minmax.h> 22 + #include <linux/module.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/pwm.h> 25 + #include <linux/regmap.h> 26 + #include <linux/time.h> 27 + #include <linux/types.h> 28 + 29 + #define ADP5585_PWM_CHAN_NUM 1 30 + 31 + #define ADP5585_PWM_OSC_FREQ_HZ 1000000U 32 + #define ADP5585_PWM_MIN_PERIOD_NS (2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) 33 + #define ADP5585_PWM_MAX_PERIOD_NS (2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) 34 + 35 + static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm) 36 + { 37 + struct regmap *regmap = pwmchip_get_drvdata(chip); 38 + 39 + /* Configure the R3 pin as PWM output. */ 40 + return regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C, 41 + ADP5585_R3_EXTEND_CFG_MASK, 42 + ADP5585_R3_EXTEND_CFG_PWM_OUT); 43 + } 44 + 45 + static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm) 46 + { 47 + struct regmap *regmap = pwmchip_get_drvdata(chip); 48 + 49 + regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C, 50 + ADP5585_R3_EXTEND_CFG_MASK, 51 + ADP5585_R3_EXTEND_CFG_GPIO4); 52 + } 53 + 54 + static int pwm_adp5585_apply(struct pwm_chip *chip, 55 + struct pwm_device *pwm, 56 + const struct pwm_state *state) 57 + { 58 + struct regmap *regmap = pwmchip_get_drvdata(chip); 59 + u64 period, duty_cycle; 60 + u32 on, off; 61 + __le16 val; 62 + int ret; 63 + 64 + if (!state->enabled) { 65 + regmap_clear_bits(regmap, ADP5585_GENERAL_CFG, ADP5585_OSC_EN); 66 + regmap_clear_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN); 67 + return 0; 68 + } 69 + 70 + if (state->polarity != PWM_POLARITY_NORMAL) 71 + return -EINVAL; 72 + 73 + if (state->period < ADP5585_PWM_MIN_PERIOD_NS) 74 + return -EINVAL; 75 + 76 + period = min(state->period, ADP5585_PWM_MAX_PERIOD_NS); 77 + duty_cycle = min(state->duty_cycle, period); 78 + 79 + /* 80 + * Compute the on and off time. As the internal oscillator frequency is 81 + * 1MHz, the calculation can be simplified without loss of precision. 82 + */ 83 + on = div_u64(duty_cycle, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); 84 + off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on; 85 + 86 + val = cpu_to_le16(off); 87 + ret = regmap_bulk_write(regmap, ADP5585_PWM_OFFT_LOW, &val, 2); 88 + if (ret) 89 + return ret; 90 + 91 + val = cpu_to_le16(on); 92 + ret = regmap_bulk_write(regmap, ADP5585_PWM_ONT_LOW, &val, 2); 93 + if (ret) 94 + return ret; 95 + 96 + /* Enable PWM in continuous mode and no external AND'ing. */ 97 + ret = regmap_update_bits(regmap, ADP5585_PWM_CFG, 98 + ADP5585_PWM_IN_AND | ADP5585_PWM_MODE | 99 + ADP5585_PWM_EN, ADP5585_PWM_EN); 100 + if (ret) 101 + return ret; 102 + 103 + return regmap_set_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN); 104 + } 105 + 106 + static int pwm_adp5585_get_state(struct pwm_chip *chip, 107 + struct pwm_device *pwm, 108 + struct pwm_state *state) 109 + { 110 + struct regmap *regmap = pwmchip_get_drvdata(chip); 111 + unsigned int on, off; 112 + unsigned int val; 113 + __le16 on_off; 114 + int ret; 115 + 116 + ret = regmap_bulk_read(regmap, ADP5585_PWM_OFFT_LOW, &on_off, 2); 117 + if (ret) 118 + return ret; 119 + off = le16_to_cpu(on_off); 120 + 121 + ret = regmap_bulk_read(regmap, ADP5585_PWM_ONT_LOW, &on_off, 2); 122 + if (ret) 123 + return ret; 124 + on = le16_to_cpu(on_off); 125 + 126 + state->duty_cycle = on * (NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); 127 + state->period = (on + off) * (NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); 128 + 129 + state->polarity = PWM_POLARITY_NORMAL; 130 + 131 + regmap_read(regmap, ADP5585_PWM_CFG, &val); 132 + state->enabled = !!(val & ADP5585_PWM_EN); 133 + 134 + return 0; 135 + } 136 + 137 + static const struct pwm_ops adp5585_pwm_ops = { 138 + .request = pwm_adp5585_request, 139 + .free = pwm_adp5585_free, 140 + .apply = pwm_adp5585_apply, 141 + .get_state = pwm_adp5585_get_state, 142 + }; 143 + 144 + static int adp5585_pwm_probe(struct platform_device *pdev) 145 + { 146 + struct device *dev = &pdev->dev; 147 + struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent); 148 + struct pwm_chip *chip; 149 + int ret; 150 + 151 + chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM, 0); 152 + if (IS_ERR(chip)) 153 + return PTR_ERR(chip); 154 + 155 + device_set_of_node_from_dev(dev, dev->parent); 156 + 157 + pwmchip_set_drvdata(chip, adp5585->regmap); 158 + chip->ops = &adp5585_pwm_ops; 159 + 160 + ret = devm_pwmchip_add(dev, chip); 161 + if (ret) 162 + return dev_err_probe(dev, ret, "failed to add PWM chip\n"); 163 + 164 + return 0; 165 + } 166 + 167 + static const struct platform_device_id adp5585_pwm_id_table[] = { 168 + { "adp5585-pwm" }, 169 + { /* Sentinel */ } 170 + }; 171 + MODULE_DEVICE_TABLE(platform, adp5585_pwm_id_table); 172 + 173 + static struct platform_driver adp5585_pwm_driver = { 174 + .driver = { 175 + .name = "adp5585-pwm", 176 + }, 177 + .probe = adp5585_pwm_probe, 178 + .id_table = adp5585_pwm_id_table, 179 + }; 180 + module_platform_driver(adp5585_pwm_driver); 181 + 182 + MODULE_AUTHOR("Xiaoning Wang <xiaoning.wang@nxp.com>"); 183 + MODULE_DESCRIPTION("ADP5585 PWM Driver"); 184 + MODULE_LICENSE("GPL");
+126
include/linux/mfd/adp5585.h
··· 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