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