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