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 "via-gpio.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 int via_gpio_set(struct gpio_chip *chip, unsigned int nr, int value) 84 { 85 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip); 86 u8 reg; 87 struct viafb_gpio *gpio; 88 unsigned long flags; 89 90 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 91 gpio = cfg->active_gpios[nr]; 92 reg = via_read_reg(VIASR, gpio->vg_port_index); 93 reg |= 0x40 << gpio->vg_mask_shift; /* output enable */ 94 if (value) 95 reg |= 0x10 << gpio->vg_mask_shift; 96 else 97 reg &= ~(0x10 << gpio->vg_mask_shift); 98 via_write_reg(VIASR, gpio->vg_port_index, reg); 99 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 100 101 return 0; 102 } 103 104 static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr, 105 int value) 106 { 107 return via_gpio_set(chip, nr, value); 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 static struct gpiod_lookup_table viafb_gpio_table = { 193 .dev_id = "viafb-camera", 194 .table = { 195 GPIO_LOOKUP("via-gpio", 2, "VGPIO2", GPIO_ACTIVE_LOW), 196 GPIO_LOOKUP("via-gpio", 3, "VGPIO3", GPIO_ACTIVE_HIGH), 197 { } 198 }, 199 }; 200 201 /* 202 * Platform device stuff. 203 */ 204 static int viafb_gpio_probe(struct platform_device *platdev) 205 { 206 struct viafb_dev *vdev = platdev->dev.platform_data; 207 struct via_port_cfg *port_cfg = vdev->port_cfg; 208 int i, ngpio = 0, ret; 209 struct viafb_gpio *gpio; 210 unsigned long flags; 211 212 /* 213 * Set up entries for all GPIOs which have been configured to 214 * operate as such (as opposed to as i2c ports). 215 */ 216 for (i = 0; i < VIAFB_NUM_PORTS; i++) { 217 if (port_cfg[i].mode != VIA_MODE_GPIO) 218 continue; 219 for (gpio = viafb_all_gpios; 220 gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++) 221 if (gpio->vg_port_index == port_cfg[i].ioport_index) { 222 viafb_gpio_config.active_gpios[ngpio] = gpio; 223 viafb_gpio_config.gpio_names[ngpio] = 224 gpio->vg_name; 225 ngpio++; 226 } 227 } 228 viafb_gpio_config.gpio_chip.ngpio = ngpio; 229 viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names; 230 viafb_gpio_config.vdev = vdev; 231 if (ngpio == 0) { 232 printk(KERN_INFO "viafb: no GPIOs configured\n"); 233 return 0; 234 } 235 /* 236 * Enable the ports. They come in pairs, with a single 237 * enable bit for both. 238 */ 239 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); 240 for (i = 0; i < ngpio; i += 2) 241 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); 242 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); 243 /* 244 * Get registered. 245 */ 246 viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */ 247 viafb_gpio_config.gpio_chip.label = "via-gpio"; 248 ret = gpiochip_add_data(&viafb_gpio_config.gpio_chip, 249 &viafb_gpio_config); 250 if (ret) { 251 printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); 252 viafb_gpio_config.gpio_chip.ngpio = 0; 253 } 254 255 gpiod_add_lookup_table(&viafb_gpio_table); 256 257 #ifdef CONFIG_PM 258 viafb_pm_register(&viafb_gpio_pm_hooks); 259 #endif 260 return ret; 261 } 262 263 264 static void viafb_gpio_remove(struct platform_device *platdev) 265 { 266 unsigned long flags; 267 int i; 268 269 #ifdef CONFIG_PM 270 viafb_pm_unregister(&viafb_gpio_pm_hooks); 271 #endif 272 273 /* 274 * Get unregistered. 275 */ 276 if (viafb_gpio_config.gpio_chip.ngpio > 0) { 277 gpiochip_remove(&viafb_gpio_config.gpio_chip); 278 } 279 /* 280 * Disable the ports. 281 */ 282 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); 283 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) 284 viafb_gpio_disable(viafb_gpio_config.active_gpios[i]); 285 viafb_gpio_config.gpio_chip.ngpio = 0; 286 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); 287 } 288 289 static struct platform_driver via_gpio_driver = { 290 .driver = { 291 .name = "viafb-gpio", 292 }, 293 .probe = viafb_gpio_probe, 294 .remove = viafb_gpio_remove, 295 }; 296 297 int viafb_gpio_init(void) 298 { 299 return platform_driver_register(&via_gpio_driver); 300 } 301 302 void viafb_gpio_exit(void) 303 { 304 platform_driver_unregister(&via_gpio_driver); 305 } 306