1a987b78fSLewis Hanly // SPDX-License-Identifier: (GPL-2.0) 2a987b78fSLewis Hanly /* 3a987b78fSLewis Hanly * Microchip PolarFire SoC (MPFS) GPIO controller driver 4a987b78fSLewis Hanly * 5a987b78fSLewis Hanly * Copyright (c) 2018-2024 Microchip Technology Inc. and its subsidiaries 6a987b78fSLewis Hanly */ 7a987b78fSLewis Hanly 8a987b78fSLewis Hanly #include <linux/clk.h> 9a987b78fSLewis Hanly #include <linux/device.h> 10a987b78fSLewis Hanly #include <linux/errno.h> 11a987b78fSLewis Hanly #include <linux/gpio/driver.h> 12a987b78fSLewis Hanly #include <linux/init.h> 13a987b78fSLewis Hanly #include <linux/mod_devicetable.h> 14a987b78fSLewis Hanly #include <linux/platform_device.h> 15*65e93637SConor Dooley #include <linux/property.h> 16a987b78fSLewis Hanly #include <linux/regmap.h> 17a987b78fSLewis Hanly #include <linux/spinlock.h> 18a987b78fSLewis Hanly 19a987b78fSLewis Hanly #define MPFS_GPIO_CTRL(i) (0x4 * (i)) 20a987b78fSLewis Hanly #define MPFS_MAX_NUM_GPIO 32 21a987b78fSLewis Hanly #define MPFS_GPIO_EN_INT 3 22a987b78fSLewis Hanly #define MPFS_GPIO_EN_OUT_BUF BIT(2) 23a987b78fSLewis Hanly #define MPFS_GPIO_EN_IN BIT(1) 24a987b78fSLewis Hanly #define MPFS_GPIO_EN_OUT BIT(0) 25a987b78fSLewis Hanly #define MPFS_GPIO_DIR_MASK GENMASK(2, 0) 26a987b78fSLewis Hanly 27a987b78fSLewis Hanly #define MPFS_GPIO_TYPE_INT_EDGE_BOTH 0x80 28a987b78fSLewis Hanly #define MPFS_GPIO_TYPE_INT_EDGE_NEG 0x60 29a987b78fSLewis Hanly #define MPFS_GPIO_TYPE_INT_EDGE_POS 0x40 30a987b78fSLewis Hanly #define MPFS_GPIO_TYPE_INT_LEVEL_LOW 0x20 31a987b78fSLewis Hanly #define MPFS_GPIO_TYPE_INT_LEVEL_HIGH 0x00 32a987b78fSLewis Hanly #define MPFS_GPIO_TYPE_INT_MASK GENMASK(7, 5) 33a987b78fSLewis Hanly #define MPFS_IRQ_REG 0x80 34*65e93637SConor Dooley 35a987b78fSLewis Hanly #define MPFS_INP_REG 0x84 36*65e93637SConor Dooley #define COREGPIO_INP_REG 0x90 37a987b78fSLewis Hanly #define MPFS_OUTP_REG 0x88 38*65e93637SConor Dooley #define COREGPIO_OUTP_REG 0xA0 39*65e93637SConor Dooley 40*65e93637SConor Dooley struct mpfs_gpio_reg_offsets { 41*65e93637SConor Dooley u8 inp; 42*65e93637SConor Dooley u8 outp; 43*65e93637SConor Dooley }; 44a987b78fSLewis Hanly 45a987b78fSLewis Hanly struct mpfs_gpio_chip { 46a987b78fSLewis Hanly struct regmap *regs; 47*65e93637SConor Dooley const struct mpfs_gpio_reg_offsets *offsets; 48a987b78fSLewis Hanly struct gpio_chip gc; 49a987b78fSLewis Hanly }; 50a987b78fSLewis Hanly 51a987b78fSLewis Hanly static const struct regmap_config mpfs_gpio_regmap_config = { 52a987b78fSLewis Hanly .reg_bits = 32, 53a987b78fSLewis Hanly .reg_stride = 4, 54a987b78fSLewis Hanly .val_bits = 32, 55a987b78fSLewis Hanly }; 56a987b78fSLewis Hanly 57a987b78fSLewis Hanly static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index) 58a987b78fSLewis Hanly { 59a987b78fSLewis Hanly struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); 60a987b78fSLewis Hanly 61a987b78fSLewis Hanly regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), 62a987b78fSLewis Hanly MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN); 63a987b78fSLewis Hanly 64a987b78fSLewis Hanly return 0; 65a987b78fSLewis Hanly } 66a987b78fSLewis Hanly 67a987b78fSLewis Hanly static int mpfs_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio_index, int value) 68a987b78fSLewis Hanly { 69a987b78fSLewis Hanly struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); 70a987b78fSLewis Hanly 71a987b78fSLewis Hanly regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), 72a987b78fSLewis Hanly MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN); 73*65e93637SConor Dooley regmap_update_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index), 74a987b78fSLewis Hanly value << gpio_index); 75a987b78fSLewis Hanly 76a987b78fSLewis Hanly return 0; 77a987b78fSLewis Hanly } 78a987b78fSLewis Hanly 79a987b78fSLewis Hanly static int mpfs_gpio_get_direction(struct gpio_chip *gc, 80a987b78fSLewis Hanly unsigned int gpio_index) 81a987b78fSLewis Hanly { 82a987b78fSLewis Hanly struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); 83a987b78fSLewis Hanly unsigned int gpio_cfg; 84a987b78fSLewis Hanly 85a987b78fSLewis Hanly regmap_read(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), &gpio_cfg); 86a987b78fSLewis Hanly if (gpio_cfg & MPFS_GPIO_EN_IN) 87a987b78fSLewis Hanly return GPIO_LINE_DIRECTION_IN; 88a987b78fSLewis Hanly 89a987b78fSLewis Hanly return GPIO_LINE_DIRECTION_OUT; 90a987b78fSLewis Hanly } 91a987b78fSLewis Hanly 92a987b78fSLewis Hanly static int mpfs_gpio_get(struct gpio_chip *gc, unsigned int gpio_index) 93a987b78fSLewis Hanly { 94a987b78fSLewis Hanly struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); 95a987b78fSLewis Hanly 96a987b78fSLewis Hanly if (mpfs_gpio_get_direction(gc, gpio_index) == GPIO_LINE_DIRECTION_OUT) 97*65e93637SConor Dooley return regmap_test_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index)); 98a987b78fSLewis Hanly else 99*65e93637SConor Dooley return regmap_test_bits(mpfs_gpio->regs, mpfs_gpio->offsets->inp, BIT(gpio_index)); 100a987b78fSLewis Hanly } 101a987b78fSLewis Hanly 102a987b78fSLewis Hanly static void mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int value) 103a987b78fSLewis Hanly { 104a987b78fSLewis Hanly struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); 105a987b78fSLewis Hanly 106a987b78fSLewis Hanly mpfs_gpio_get(gc, gpio_index); 107a987b78fSLewis Hanly 108*65e93637SConor Dooley regmap_update_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index), 109a987b78fSLewis Hanly value << gpio_index); 110a987b78fSLewis Hanly 111a987b78fSLewis Hanly mpfs_gpio_get(gc, gpio_index); 112a987b78fSLewis Hanly } 113a987b78fSLewis Hanly 114a987b78fSLewis Hanly static int mpfs_gpio_probe(struct platform_device *pdev) 115a987b78fSLewis Hanly { 116a987b78fSLewis Hanly struct device *dev = &pdev->dev; 117a987b78fSLewis Hanly struct mpfs_gpio_chip *mpfs_gpio; 118a987b78fSLewis Hanly struct clk *clk; 119a987b78fSLewis Hanly void __iomem *base; 120a987b78fSLewis Hanly int ngpios; 121a987b78fSLewis Hanly 122a987b78fSLewis Hanly mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL); 123a987b78fSLewis Hanly if (!mpfs_gpio) 124a987b78fSLewis Hanly return -ENOMEM; 125a987b78fSLewis Hanly 126*65e93637SConor Dooley mpfs_gpio->offsets = device_get_match_data(&pdev->dev); 127*65e93637SConor Dooley 128a987b78fSLewis Hanly base = devm_platform_ioremap_resource(pdev, 0); 129a987b78fSLewis Hanly if (IS_ERR(base)) 130a987b78fSLewis Hanly return dev_err_probe(dev, PTR_ERR(base), "failed to ioremap memory resource\n"); 131a987b78fSLewis Hanly 132a987b78fSLewis Hanly mpfs_gpio->regs = devm_regmap_init_mmio(dev, base, &mpfs_gpio_regmap_config); 133a987b78fSLewis Hanly if (IS_ERR(mpfs_gpio->regs)) 134a987b78fSLewis Hanly return dev_err_probe(dev, PTR_ERR(mpfs_gpio->regs), 135a987b78fSLewis Hanly "failed to initialise regmap\n"); 136a987b78fSLewis Hanly 137a987b78fSLewis Hanly clk = devm_clk_get_enabled(dev, NULL); 138a987b78fSLewis Hanly if (IS_ERR(clk)) 139a987b78fSLewis Hanly return dev_err_probe(dev, PTR_ERR(clk), "failed to get and enable clock\n"); 140a987b78fSLewis Hanly 141a987b78fSLewis Hanly ngpios = MPFS_MAX_NUM_GPIO; 142a987b78fSLewis Hanly device_property_read_u32(dev, "ngpios", &ngpios); 143a987b78fSLewis Hanly if (ngpios > MPFS_MAX_NUM_GPIO) 144a987b78fSLewis Hanly ngpios = MPFS_MAX_NUM_GPIO; 145a987b78fSLewis Hanly 146a987b78fSLewis Hanly mpfs_gpio->gc.direction_input = mpfs_gpio_direction_input; 147a987b78fSLewis Hanly mpfs_gpio->gc.direction_output = mpfs_gpio_direction_output; 148a987b78fSLewis Hanly mpfs_gpio->gc.get_direction = mpfs_gpio_get_direction; 149a987b78fSLewis Hanly mpfs_gpio->gc.get = mpfs_gpio_get; 150a987b78fSLewis Hanly mpfs_gpio->gc.set = mpfs_gpio_set; 151a987b78fSLewis Hanly mpfs_gpio->gc.base = -1; 152a987b78fSLewis Hanly mpfs_gpio->gc.ngpio = ngpios; 153a987b78fSLewis Hanly mpfs_gpio->gc.label = dev_name(dev); 154a987b78fSLewis Hanly mpfs_gpio->gc.parent = dev; 155a987b78fSLewis Hanly mpfs_gpio->gc.owner = THIS_MODULE; 156a987b78fSLewis Hanly 157a987b78fSLewis Hanly return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio); 158a987b78fSLewis Hanly } 159a987b78fSLewis Hanly 160*65e93637SConor Dooley static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets = { 161*65e93637SConor Dooley .inp = MPFS_INP_REG, 162*65e93637SConor Dooley .outp = MPFS_OUTP_REG, 163*65e93637SConor Dooley }; 164*65e93637SConor Dooley 165*65e93637SConor Dooley static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = { 166*65e93637SConor Dooley .inp = COREGPIO_INP_REG, 167*65e93637SConor Dooley .outp = COREGPIO_OUTP_REG, 168*65e93637SConor Dooley }; 169*65e93637SConor Dooley 170a987b78fSLewis Hanly static const struct of_device_id mpfs_gpio_of_ids[] = { 171*65e93637SConor Dooley { 172*65e93637SConor Dooley .compatible = "microchip,mpfs-gpio", 173*65e93637SConor Dooley .data = &mpfs_reg_offsets, 174*65e93637SConor Dooley }, { 175*65e93637SConor Dooley .compatible = "microchip,coregpio-rtl-v3", 176*65e93637SConor Dooley .data = &coregpio_reg_offsets, 177*65e93637SConor Dooley }, 178a987b78fSLewis Hanly { /* end of list */ } 179a987b78fSLewis Hanly }; 180a987b78fSLewis Hanly 181a987b78fSLewis Hanly static struct platform_driver mpfs_gpio_driver = { 182a987b78fSLewis Hanly .probe = mpfs_gpio_probe, 183a987b78fSLewis Hanly .driver = { 184a987b78fSLewis Hanly .name = "microchip,mpfs-gpio", 185a987b78fSLewis Hanly .of_match_table = mpfs_gpio_of_ids, 186a987b78fSLewis Hanly }, 187a987b78fSLewis Hanly }; 188a987b78fSLewis Hanly builtin_platform_driver(mpfs_gpio_driver); 189