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

pinctrl: amd: isp411: Add amdisp GPIO pinctrl

Add pinctrl driver support for AMD SoC with isp41 hw ip block.

Signed-off-by: Pratap Nirujogi <pratap.nirujogi@amd.com>
Link: https://lore.kernel.org/20250304232051.2936557-1-pratap.nirujogi@amd.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Pratap Nirujogi and committed by
Linus Walleij
e97435ab 7f7a793d

+340
+13
drivers/pinctrl/Kconfig
··· 49 49 Requires ACPI/FDT device enumeration code to set up a platform 50 50 device. 51 51 52 + config PINCTRL_AMDISP 53 + tristate "AMDISP GPIO pin control" 54 + depends on HAS_IOMEM 55 + select GPIOLIB 56 + select PINCONF 57 + select GENERIC_PINCONF 58 + help 59 + The driver for memory mapped GPIO functionality on AMD platforms 60 + with ISP support. All the pins are output controlled only 61 + 62 + Requires AMDGPU to MFD add device for enumeration to set up as 63 + platform device. 64 + 52 65 config PINCTRL_APPLE_GPIO 53 66 tristate "Apple SoC GPIO pin controller driver" 54 67 depends on ARCH_APPLE
+1
drivers/pinctrl/Makefile
··· 10 10 obj-$(CONFIG_OF) += devicetree.o 11 11 12 12 obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o 13 + obj-$(CONFIG_PINCTRL_AMDISP) += pinctrl-amdisp.o 13 14 obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o 14 15 obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o 15 16 obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o
+231
drivers/pinctrl/pinctrl-amdisp.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * AMD ISP Pinctrl Driver 4 + * 5 + * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. 6 + * 7 + */ 8 + 9 + #include <linux/gpio/driver.h> 10 + #include <linux/module.h> 11 + #include <linux/platform_device.h> 12 + 13 + #include "pinctrl-amdisp.h" 14 + 15 + #define DRV_NAME "amdisp-pinctrl" 16 + #define GPIO_CONTROL_PIN 4 17 + #define GPIO_OFFSET_0 0x0 18 + #define GPIO_OFFSET_1 0x4 19 + #define GPIO_OFFSET_2 0x50 20 + 21 + static const u32 gpio_offset[] = { 22 + GPIO_OFFSET_0, 23 + GPIO_OFFSET_1, 24 + GPIO_OFFSET_2 25 + }; 26 + 27 + struct amdisp_pinctrl_data { 28 + const struct pinctrl_pin_desc *pins; 29 + unsigned int npins; 30 + const struct amdisp_function *functions; 31 + unsigned int nfunctions; 32 + const struct amdisp_pingroup *groups; 33 + unsigned int ngroups; 34 + }; 35 + 36 + static const struct amdisp_pinctrl_data amdisp_pinctrl_data = { 37 + .pins = amdisp_pins, 38 + .npins = ARRAY_SIZE(amdisp_pins), 39 + .functions = amdisp_functions, 40 + .nfunctions = ARRAY_SIZE(amdisp_functions), 41 + .groups = amdisp_groups, 42 + .ngroups = ARRAY_SIZE(amdisp_groups), 43 + }; 44 + 45 + struct amdisp_pinctrl { 46 + struct device *dev; 47 + struct pinctrl_dev *pctrl; 48 + struct pinctrl_desc desc; 49 + struct pinctrl_gpio_range gpio_range; 50 + struct gpio_chip gc; 51 + const struct amdisp_pinctrl_data *data; 52 + void __iomem *gpiobase; 53 + raw_spinlock_t lock; 54 + }; 55 + 56 + static int amdisp_get_groups_count(struct pinctrl_dev *pctldev) 57 + { 58 + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 59 + 60 + return pctrl->data->ngroups; 61 + } 62 + 63 + static const char *amdisp_get_group_name(struct pinctrl_dev *pctldev, 64 + unsigned int group) 65 + { 66 + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 67 + 68 + return pctrl->data->groups[group].name; 69 + } 70 + 71 + static int amdisp_get_group_pins(struct pinctrl_dev *pctldev, 72 + unsigned int group, 73 + const unsigned int **pins, 74 + unsigned int *num_pins) 75 + { 76 + struct amdisp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 77 + 78 + *pins = pctrl->data->groups[group].pins; 79 + *num_pins = pctrl->data->groups[group].npins; 80 + return 0; 81 + } 82 + 83 + const struct pinctrl_ops amdisp_pinctrl_ops = { 84 + .get_groups_count = amdisp_get_groups_count, 85 + .get_group_name = amdisp_get_group_name, 86 + .get_group_pins = amdisp_get_group_pins, 87 + }; 88 + 89 + static int amdisp_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) 90 + { 91 + /* amdisp gpio only has output mode */ 92 + return GPIO_LINE_DIRECTION_OUT; 93 + } 94 + 95 + static int amdisp_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) 96 + { 97 + return -EOPNOTSUPP; 98 + } 99 + 100 + static int amdisp_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, 101 + int value) 102 + { 103 + /* Nothing to do, amdisp gpio only has output mode */ 104 + return 0; 105 + } 106 + 107 + static int amdisp_gpio_get(struct gpio_chip *gc, unsigned int gpio) 108 + { 109 + unsigned long flags; 110 + u32 pin_reg; 111 + struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc); 112 + 113 + raw_spin_lock_irqsave(&pctrl->lock, flags); 114 + pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]); 115 + raw_spin_unlock_irqrestore(&pctrl->lock, flags); 116 + 117 + return !!(pin_reg & BIT(GPIO_CONTROL_PIN)); 118 + } 119 + 120 + static void amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) 121 + { 122 + unsigned long flags; 123 + u32 pin_reg; 124 + struct amdisp_pinctrl *pctrl = gpiochip_get_data(gc); 125 + 126 + raw_spin_lock_irqsave(&pctrl->lock, flags); 127 + pin_reg = readl(pctrl->gpiobase + gpio_offset[gpio]); 128 + if (value) 129 + pin_reg |= BIT(GPIO_CONTROL_PIN); 130 + else 131 + pin_reg &= ~BIT(GPIO_CONTROL_PIN); 132 + writel(pin_reg, pctrl->gpiobase + gpio_offset[gpio]); 133 + raw_spin_unlock_irqrestore(&pctrl->lock, flags); 134 + } 135 + 136 + static int amdisp_gpiochip_add(struct platform_device *pdev, 137 + struct amdisp_pinctrl *pctrl) 138 + { 139 + struct gpio_chip *gc = &pctrl->gc; 140 + struct pinctrl_gpio_range *grange = &pctrl->gpio_range; 141 + int ret; 142 + 143 + gc->label = dev_name(pctrl->dev); 144 + gc->parent = &pdev->dev; 145 + gc->names = amdisp_range_pins_name; 146 + gc->request = gpiochip_generic_request; 147 + gc->free = gpiochip_generic_free; 148 + gc->get_direction = amdisp_gpio_get_direction; 149 + gc->direction_input = amdisp_gpio_direction_input; 150 + gc->direction_output = amdisp_gpio_direction_output; 151 + gc->get = amdisp_gpio_get; 152 + gc->set = amdisp_gpio_set; 153 + gc->base = -1; 154 + gc->ngpio = ARRAY_SIZE(amdisp_range_pins); 155 + 156 + grange->id = 0; 157 + grange->pin_base = 0; 158 + grange->base = 0; 159 + grange->pins = amdisp_range_pins; 160 + grange->npins = ARRAY_SIZE(amdisp_range_pins); 161 + grange->name = gc->label; 162 + grange->gc = gc; 163 + 164 + ret = devm_gpiochip_add_data(&pdev->dev, gc, pctrl); 165 + if (ret) 166 + return ret; 167 + 168 + pinctrl_add_gpio_range(pctrl->pctrl, grange); 169 + 170 + return 0; 171 + } 172 + 173 + static int amdisp_pinctrl_probe(struct platform_device *pdev) 174 + { 175 + struct amdisp_pinctrl *pctrl; 176 + struct resource *res; 177 + int ret; 178 + 179 + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); 180 + if (!pctrl) 181 + return -ENOMEM; 182 + 183 + pdev->dev.init_name = DRV_NAME; 184 + 185 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 186 + if (IS_ERR(res)) 187 + return PTR_ERR(res); 188 + 189 + pctrl->gpiobase = devm_ioremap_resource(&pdev->dev, res); 190 + if (IS_ERR(pctrl->gpiobase)) 191 + return PTR_ERR(pctrl->gpiobase); 192 + 193 + platform_set_drvdata(pdev, pctrl); 194 + 195 + pctrl->dev = &pdev->dev; 196 + pctrl->data = &amdisp_pinctrl_data; 197 + pctrl->desc.owner = THIS_MODULE; 198 + pctrl->desc.pctlops = &amdisp_pinctrl_ops; 199 + pctrl->desc.pmxops = NULL; 200 + pctrl->desc.name = dev_name(&pdev->dev); 201 + pctrl->desc.pins = pctrl->data->pins; 202 + pctrl->desc.npins = pctrl->data->npins; 203 + ret = devm_pinctrl_register_and_init(&pdev->dev, &pctrl->desc, 204 + pctrl, &pctrl->pctrl); 205 + if (ret) 206 + return ret; 207 + 208 + ret = pinctrl_enable(pctrl->pctrl); 209 + if (ret) 210 + return ret; 211 + 212 + ret = amdisp_gpiochip_add(pdev, pctrl); 213 + if (ret) 214 + return ret; 215 + 216 + return 0; 217 + } 218 + 219 + static struct platform_driver amdisp_pinctrl_driver = { 220 + .driver = { 221 + .name = DRV_NAME, 222 + }, 223 + .probe = amdisp_pinctrl_probe, 224 + }; 225 + module_platform_driver(amdisp_pinctrl_driver); 226 + 227 + MODULE_AUTHOR("Benjamin Chan <benjamin.chan@amd.com>"); 228 + MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); 229 + MODULE_DESCRIPTION("AMDISP pinctrl driver"); 230 + MODULE_LICENSE("GPL v2"); 231 + MODULE_ALIAS("platform:" DRV_NAME);
+95
drivers/pinctrl/pinctrl-amdisp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * AMD ISP Pinctrl Driver 4 + * 5 + * Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. 6 + * 7 + */ 8 + 9 + static const struct pinctrl_pin_desc amdisp_pins[] = { 10 + PINCTRL_PIN(0, "GPIO_0"), /* sensor0 control */ 11 + PINCTRL_PIN(1, "GPIO_1"), /* sensor1 control */ 12 + PINCTRL_PIN(2, "GPIO_2"), /* sensor2 control */ 13 + }; 14 + 15 + #define AMDISP_GPIO_PINS(pin) \ 16 + static const unsigned int gpio##pin##_pins[] = { pin } 17 + AMDISP_GPIO_PINS(0); 18 + AMDISP_GPIO_PINS(1); 19 + AMDISP_GPIO_PINS(2); 20 + 21 + static const unsigned int amdisp_range_pins[] = { 22 + 0, 1, 2 23 + }; 24 + 25 + static const char * const amdisp_range_pins_name[] = { 26 + "gpio0", "gpio1", "gpio2" 27 + }; 28 + 29 + enum amdisp_functions { 30 + mux_gpio, 31 + mux_NA 32 + }; 33 + 34 + static const char * const gpio_groups[] = { 35 + "gpio0", "gpio1", "gpio2" 36 + }; 37 + 38 + /** 39 + * struct amdisp_function - a pinmux function 40 + * @name: Name of the pinmux function. 41 + * @groups: List of pingroups for this function. 42 + * @ngroups: Number of entries in @groups. 43 + */ 44 + struct amdisp_function { 45 + const char *name; 46 + const char * const *groups; 47 + unsigned int ngroups; 48 + }; 49 + 50 + #define FUNCTION(fname) \ 51 + [mux_##fname] = { \ 52 + .name = #fname, \ 53 + .groups = fname##_groups, \ 54 + .ngroups = ARRAY_SIZE(fname##_groups), \ 55 + } 56 + 57 + static const struct amdisp_function amdisp_functions[] = { 58 + FUNCTION(gpio), 59 + }; 60 + 61 + /** 62 + * struct amdisp_pingroup - a pinmux group 63 + * @name: Name of the pinmux group. 64 + * @pins: List of pins for this group. 65 + * @npins: Number of entries in @pins. 66 + * @funcs: List of functions belongs to this group. 67 + * @nfuncs: Number of entries in @funcs. 68 + * @offset: Group offset in amdisp pinmux groups. 69 + */ 70 + struct amdisp_pingroup { 71 + const char *name; 72 + const unsigned int *pins; 73 + unsigned int npins; 74 + unsigned int *funcs; 75 + unsigned int nfuncs; 76 + unsigned int offset; 77 + }; 78 + 79 + #define PINGROUP(id, f0) \ 80 + { \ 81 + .name = "gpio" #id, \ 82 + .pins = gpio##id##_pins, \ 83 + .npins = ARRAY_SIZE(gpio##id##_pins), \ 84 + .funcs = (int[]){ \ 85 + mux_##f0, \ 86 + }, \ 87 + .nfuncs = 1, \ 88 + .offset = id, \ 89 + } 90 + 91 + static const struct amdisp_pingroup amdisp_groups[] = { 92 + PINGROUP(0, gpio), 93 + PINGROUP(1, gpio), 94 + PINGROUP(2, gpio), 95 + };