1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Support for viafb GPIO ports. 4 * 5 * Copyright 2009 Jonathan Corbet <corbet@lwn.net> 6 */ 7 8 #include <linux/spinlock.h> 9 #include <linux/gpio/driver.h> 10 #include <linux/platform_device.h> 11 #include <linux/via-core.h> 12 #include <linux/via-gpio.h> 13 #include <linux/export.h> 14 15 /* 16 * The ports we know about. Note that the port-25 gpios are not 17 * mentioned in the datasheet. 18 */ 19 20 struct viafb_gpio { 21 char *vg_name; /* Data sheet name */ 22 u16 vg_io_port; 23 u8 vg_port_index; 24 int vg_mask_shift; 25 }; 26 27 static struct viafb_gpio viafb_all_gpios[] = { 28 { 29 .vg_name = "VGPIO0", /* Guess - not in datasheet */ 30 .vg_io_port = VIASR, 31 .vg_port_index = 0x25, 32 .vg_mask_shift = 1 33 }, 34 { 35 .vg_name = "VGPIO1", 36 .vg_io_port = VIASR, 37 .vg_port_index = 0x25, 38 .vg_mask_shift = 0 39 }, 40 { 41 .vg_name = "VGPIO2", /* aka DISPCLKI0 */ 42 .vg_io_port = VIASR, 43 .vg_port_index = 0x2c, 44 .vg_mask_shift = 1 45 }, 46 { 47 .vg_name = "VGPIO3", /* aka DISPCLKO0 */ 48 .vg_io_port = VIASR, 49 .vg_port_index = 0x2c, 50 .vg_mask_shift = 0 51 }, 52 { 53 .vg_name = "VGPIO4", /* DISPCLKI1 */ 54 .vg_io_port = VIASR, 55 .vg_port_index = 0x3d, 56 .vg_mask_shift = 1 57 }, 58 { 59 .vg_name = "VGPIO5", /* DISPCLKO1 */ 60 .vg_io_port = VIASR, 61 .vg_port_index = 0x3d, 62 .vg_mask_shift = 0 63 }, 64 }; 65 66 #define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios) 67 68 /* 69 * This structure controls the active GPIOs, which may be a subset 70 * of those which are known. 71 */ 72 73 struct viafb_gpio_cfg { 74 struct gpio_chip gpio_chip; 75 struct viafb_dev *vdev; 76 struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS]; 77 const char *gpio_names[VIAFB_NUM_GPIOS]; 78 }; 79 80 /* 81 * GPIO access functions 82 */ 83 static void via_gpio_set(struct gpio_chip *chip, unsigned int nr, 84 int value) 85 { 86 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip); 87 u8 reg; 88 struct viafb_gpio *gpio; 89 unsigned long flags; 90 91 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 92 gpio = cfg->active_gpios[nr]; 93 reg = via_read_reg(VIASR, gpio->vg_port_index); 94 reg |= 0x40 << gpio->vg_mask_shift; /* output enable */ 95 if (value) 96 reg |= 0x10 << gpio->vg_mask_shift; 97 else 98 reg &= ~(0x10 << gpio->vg_mask_shift); 99 via_write_reg(VIASR, gpio->vg_port_index, reg); 100 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 101 } 102 103 static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr, 104 int value) 105 { 106 via_gpio_set(chip, nr, value); 107 return 0; 108 } 109 110 /* 111 * Set the input direction. I'm not sure this is right; we should 112 * be able to do input without disabling output. 113 */ 114 static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr) 115 { 116 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip); 117 struct viafb_gpio *gpio; 118 unsigned long flags; 119 120 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 121 gpio = cfg->active_gpios[nr]; 122 via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 123 0x40 << gpio->vg_mask_shift); 124 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 125 return 0; 126 } 127 128 static int via_gpio_get(struct gpio_chip *chip, unsigned int nr) 129 { 130 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip); 131 u8 reg; 132 struct viafb_gpio *gpio; 133 unsigned long flags; 134 135 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 136 gpio = cfg->active_gpios[nr]; 137 reg = via_read_reg(VIASR, gpio->vg_port_index); 138 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 139 return !!(reg & (0x04 << gpio->vg_mask_shift)); 140 } 141 142 143 static struct viafb_gpio_cfg viafb_gpio_config = { 144 .gpio_chip = { 145 .label = "VIAFB onboard GPIO", 146 .owner = THIS_MODULE, 147 .direction_output = via_gpio_dir_out, 148 .set = via_gpio_set, 149 .direction_input = via_gpio_dir_input, 150 .get = via_gpio_get, 151 .base = -1, 152 .ngpio = 0, 153 .can_sleep = 0 154 } 155 }; 156 157 /* 158 * Manage the software enable bit. 159 */ 160 static void viafb_gpio_enable(struct viafb_gpio *gpio) 161 { 162 via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02); 163 } 164 165 static void viafb_gpio_disable(struct viafb_gpio *gpio) 166 { 167 via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); 168 } 169 170 #ifdef CONFIG_PM 171 172 static int viafb_gpio_suspend(void *private) 173 { 174 return 0; 175 } 176 177 static int viafb_gpio_resume(void *private) 178 { 179 int i; 180 181 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) 182 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); 183 return 0; 184 } 185 186 static struct viafb_pm_hooks viafb_gpio_pm_hooks = { 187 .suspend = viafb_gpio_suspend, 188 .resume = viafb_gpio_resume 189 }; 190 #endif /* CONFIG_PM */ 191 192 /* 193 * Look up a specific gpio and return the number it was assigned. 194 */ 195 int viafb_gpio_lookup(const char *name) 196 { 197 int i; 198 199 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++) 200 if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name)) 201 return viafb_gpio_config.gpio_chip.base + i; 202 return -1; 203 } 204 EXPORT_SYMBOL_GPL(viafb_gpio_lookup); 205 206 /* 207 * Platform device stuff. 208 */ 209 static int viafb_gpio_probe(struct platform_device *platdev) 210 { 211 struct viafb_dev *vdev = platdev->dev.platform_data; 212 struct via_port_cfg *port_cfg = vdev->port_cfg; 213 int i, ngpio = 0, ret; 214 struct viafb_gpio *gpio; 215 unsigned long flags; 216 217 /* 218 * Set up entries for all GPIOs which have been configured to 219 * operate as such (as opposed to as i2c ports). 220 */ 221 for (i = 0; i < VIAFB_NUM_PORTS; i++) { 222 if (port_cfg[i].mode != VIA_MODE_GPIO) 223 continue; 224 for (gpio = viafb_all_gpios; 225 gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++) 226 if (gpio->vg_port_index == port_cfg[i].ioport_index) { 227 viafb_gpio_config.active_gpios[ngpio] = gpio; 228 viafb_gpio_config.gpio_names[ngpio] = 229 gpio->vg_name; 230 ngpio++; 231 } 232 } 233 viafb_gpio_config.gpio_chip.ngpio = ngpio; 234 viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names; 235 viafb_gpio_config.vdev = vdev; 236 if (ngpio == 0) { 237 printk(KERN_INFO "viafb: no GPIOs configured\n"); 238 return 0; 239 } 240 /* 241 * Enable the ports. They come in pairs, with a single 242 * enable bit for both. 243 */ 244 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); 245 for (i = 0; i < ngpio; i += 2) 246 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); 247 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); 248 /* 249 * Get registered. 250 */ 251 viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */ 252 ret = gpiochip_add_data(&viafb_gpio_config.gpio_chip, 253 &viafb_gpio_config); 254 if (ret) { 255 printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); 256 viafb_gpio_config.gpio_chip.ngpio = 0; 257 } 258 #ifdef CONFIG_PM 259 viafb_pm_register(&viafb_gpio_pm_hooks); 260 #endif 261 return ret; 262 } 263 264 265 static int viafb_gpio_remove(struct platform_device *platdev) 266 { 267 unsigned long flags; 268 int i; 269 270 #ifdef CONFIG_PM 271 viafb_pm_unregister(&viafb_gpio_pm_hooks); 272 #endif 273 274 /* 275 * Get unregistered. 276 */ 277 if (viafb_gpio_config.gpio_chip.ngpio > 0) { 278 gpiochip_remove(&viafb_gpio_config.gpio_chip); 279 } 280 /* 281 * Disable the ports. 282 */ 283 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); 284 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) 285 viafb_gpio_disable(viafb_gpio_config.active_gpios[i]); 286 viafb_gpio_config.gpio_chip.ngpio = 0; 287 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); 288 return 0; 289 } 290 291 static struct platform_driver via_gpio_driver = { 292 .driver = { 293 .name = "viafb-gpio", 294 }, 295 .probe = viafb_gpio_probe, 296 .remove = viafb_gpio_remove, 297 }; 298 299 int viafb_gpio_init(void) 300 { 301 return platform_driver_register(&via_gpio_driver); 302 } 303 304 void viafb_gpio_exit(void) 305 { 306 platform_driver_unregister(&via_gpio_driver); 307 } 308