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