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 int 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 return 0; 136 } 137 138 static int amdisp_gpiochip_add(struct platform_device *pdev, 139 struct amdisp_pinctrl *pctrl) 140 { 141 struct gpio_chip *gc = &pctrl->gc; 142 struct pinctrl_gpio_range *grange = &pctrl->gpio_range; 143 int ret; 144 145 gc->label = dev_name(pctrl->dev); 146 gc->parent = &pdev->dev; 147 gc->names = amdisp_range_pins_name; 148 gc->request = gpiochip_generic_request; 149 gc->free = gpiochip_generic_free; 150 gc->get_direction = amdisp_gpio_get_direction; 151 gc->direction_input = amdisp_gpio_direction_input; 152 gc->direction_output = amdisp_gpio_direction_output; 153 gc->get = amdisp_gpio_get; 154 gc->set = amdisp_gpio_set; 155 gc->base = -1; 156 gc->ngpio = ARRAY_SIZE(amdisp_range_pins); 157 158 grange->id = 0; 159 grange->pin_base = 0; 160 grange->base = 0; 161 grange->pins = amdisp_range_pins; 162 grange->npins = ARRAY_SIZE(amdisp_range_pins); 163 grange->name = gc->label; 164 grange->gc = gc; 165 166 ret = devm_gpiochip_add_data(&pdev->dev, gc, pctrl); 167 if (ret) 168 return ret; 169 170 pinctrl_add_gpio_range(pctrl->pctrl, grange); 171 172 return 0; 173 } 174 175 static int amdisp_pinctrl_probe(struct platform_device *pdev) 176 { 177 struct amdisp_pinctrl *pctrl; 178 struct resource *res; 179 int ret; 180 181 pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); 182 if (!pctrl) 183 return -ENOMEM; 184 185 pdev->dev.init_name = DRV_NAME; 186 187 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 188 if (!res) 189 return -EINVAL; 190 191 pctrl->gpiobase = devm_ioremap_resource(&pdev->dev, res); 192 if (IS_ERR(pctrl->gpiobase)) 193 return PTR_ERR(pctrl->gpiobase); 194 195 platform_set_drvdata(pdev, pctrl); 196 197 pctrl->dev = &pdev->dev; 198 pctrl->data = &amdisp_pinctrl_data; 199 pctrl->desc.owner = THIS_MODULE; 200 pctrl->desc.pctlops = &amdisp_pinctrl_ops; 201 pctrl->desc.pmxops = NULL; 202 pctrl->desc.name = dev_name(&pdev->dev); 203 pctrl->desc.pins = pctrl->data->pins; 204 pctrl->desc.npins = pctrl->data->npins; 205 ret = devm_pinctrl_register_and_init(&pdev->dev, &pctrl->desc, 206 pctrl, &pctrl->pctrl); 207 if (ret) 208 return ret; 209 210 ret = pinctrl_enable(pctrl->pctrl); 211 if (ret) 212 return ret; 213 214 ret = amdisp_gpiochip_add(pdev, pctrl); 215 if (ret) 216 return ret; 217 218 return 0; 219 } 220 221 static struct platform_driver amdisp_pinctrl_driver = { 222 .driver = { 223 .name = DRV_NAME, 224 }, 225 .probe = amdisp_pinctrl_probe, 226 }; 227 module_platform_driver(amdisp_pinctrl_driver); 228 229 MODULE_AUTHOR("Benjamin Chan <benjamin.chan@amd.com>"); 230 MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); 231 MODULE_DESCRIPTION("AMDISP pinctrl driver"); 232 MODULE_LICENSE("GPL v2"); 233 MODULE_ALIAS("platform:" DRV_NAME); 234