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 (!res) 187 return -EINVAL; 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); 232