1/* 2 * Support for viafb GPIO ports. 3 * 4 * Copyright 2009 Jonathan Corbet <corbet@lwn.net> 5 * Distributable under version 2 of the GNU General Public License. 6 */ 7 8#include <linux/spinlock.h> 9#include <linux/gpio.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 20struct 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 27static 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 73struct 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 */ 83static void via_gpio_set(struct gpio_chip *chip, unsigned int nr, 84 int value) 85{ 86 struct viafb_gpio_cfg *cfg = container_of(chip, 87 struct viafb_gpio_cfg, 88 gpio_chip); 89 u8 reg; 90 struct viafb_gpio *gpio; 91 unsigned long flags; 92 93 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 94 gpio = cfg->active_gpios[nr]; 95 reg = via_read_reg(VIASR, gpio->vg_port_index); 96 reg |= 0x40 << gpio->vg_mask_shift; /* output enable */ 97 if (value) 98 reg |= 0x10 << gpio->vg_mask_shift; 99 else 100 reg &= ~(0x10 << gpio->vg_mask_shift); 101 via_write_reg(VIASR, gpio->vg_port_index, reg); 102 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 103} 104 105static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr, 106 int value) 107{ 108 via_gpio_set(chip, nr, value); 109 return 0; 110} 111 112/* 113 * Set the input direction. I'm not sure this is right; we should 114 * be able to do input without disabling output. 115 */ 116static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr) 117{ 118 struct viafb_gpio_cfg *cfg = container_of(chip, 119 struct viafb_gpio_cfg, 120 gpio_chip); 121 struct viafb_gpio *gpio; 122 unsigned long flags; 123 124 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 125 gpio = cfg->active_gpios[nr]; 126 via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 127 0x40 << gpio->vg_mask_shift); 128 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 129 return 0; 130} 131 132static int via_gpio_get(struct gpio_chip *chip, unsigned int nr) 133{ 134 struct viafb_gpio_cfg *cfg = container_of(chip, 135 struct viafb_gpio_cfg, 136 gpio_chip); 137 u8 reg; 138 struct viafb_gpio *gpio; 139 unsigned long flags; 140 141 spin_lock_irqsave(&cfg->vdev->reg_lock, flags); 142 gpio = cfg->active_gpios[nr]; 143 reg = via_read_reg(VIASR, gpio->vg_port_index); 144 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); 145 return reg & (0x04 << gpio->vg_mask_shift); 146} 147 148 149static struct viafb_gpio_cfg viafb_gpio_config = { 150 .gpio_chip = { 151 .label = "VIAFB onboard GPIO", 152 .owner = THIS_MODULE, 153 .direction_output = via_gpio_dir_out, 154 .set = via_gpio_set, 155 .direction_input = via_gpio_dir_input, 156 .get = via_gpio_get, 157 .base = -1, 158 .ngpio = 0, 159 .can_sleep = 0 160 } 161}; 162 163/* 164 * Manage the software enable bit. 165 */ 166static void viafb_gpio_enable(struct viafb_gpio *gpio) 167{ 168 via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02); 169} 170 171static void viafb_gpio_disable(struct viafb_gpio *gpio) 172{ 173 via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); 174} 175 176#ifdef CONFIG_PM 177 178static int viafb_gpio_suspend(void *private) 179{ 180 return 0; 181} 182 183static int viafb_gpio_resume(void *private) 184{ 185 int i; 186 187 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) 188 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); 189 return 0; 190} 191 192static struct viafb_pm_hooks viafb_gpio_pm_hooks = { 193 .suspend = viafb_gpio_suspend, 194 .resume = viafb_gpio_resume 195}; 196#endif /* CONFIG_PM */ 197 198/* 199 * Look up a specific gpio and return the number it was assigned. 200 */ 201int viafb_gpio_lookup(const char *name) 202{ 203 int i; 204 205 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++) 206 if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name)) 207 return viafb_gpio_config.gpio_chip.base + i; 208 return -1; 209} 210EXPORT_SYMBOL_GPL(viafb_gpio_lookup); 211 212/* 213 * Platform device stuff. 214 */ 215static int viafb_gpio_probe(struct platform_device *platdev) 216{ 217 struct viafb_dev *vdev = platdev->dev.platform_data; 218 struct via_port_cfg *port_cfg = vdev->port_cfg; 219 int i, ngpio = 0, ret; 220 struct viafb_gpio *gpio; 221 unsigned long flags; 222 223 /* 224 * Set up entries for all GPIOs which have been configured to 225 * operate as such (as opposed to as i2c ports). 226 */ 227 for (i = 0; i < VIAFB_NUM_PORTS; i++) { 228 if (port_cfg[i].mode != VIA_MODE_GPIO) 229 continue; 230 for (gpio = viafb_all_gpios; 231 gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++) 232 if (gpio->vg_port_index == port_cfg[i].ioport_index) { 233 viafb_gpio_config.active_gpios[ngpio] = gpio; 234 viafb_gpio_config.gpio_names[ngpio] = 235 gpio->vg_name; 236 ngpio++; 237 } 238 } 239 viafb_gpio_config.gpio_chip.ngpio = ngpio; 240 viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names; 241 viafb_gpio_config.vdev = vdev; 242 if (ngpio == 0) { 243 printk(KERN_INFO "viafb: no GPIOs configured\n"); 244 return 0; 245 } 246 /* 247 * Enable the ports. They come in pairs, with a single 248 * enable bit for both. 249 */ 250 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); 251 for (i = 0; i < ngpio; i += 2) 252 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]); 253 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); 254 /* 255 * Get registered. 256 */ 257 viafb_gpio_config.gpio_chip.base = -1; /* Dynamic */ 258 ret = gpiochip_add(&viafb_gpio_config.gpio_chip); 259 if (ret) { 260 printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); 261 viafb_gpio_config.gpio_chip.ngpio = 0; 262 } 263#ifdef CONFIG_PM 264 viafb_pm_register(&viafb_gpio_pm_hooks); 265#endif 266 return ret; 267} 268 269 270static int viafb_gpio_remove(struct platform_device *platdev) 271{ 272 unsigned long flags; 273 int i; 274 275#ifdef CONFIG_PM 276 viafb_pm_unregister(&viafb_gpio_pm_hooks); 277#endif 278 279 /* 280 * Get unregistered. 281 */ 282 if (viafb_gpio_config.gpio_chip.ngpio > 0) { 283 gpiochip_remove(&viafb_gpio_config.gpio_chip); 284 } 285 /* 286 * Disable the ports. 287 */ 288 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags); 289 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2) 290 viafb_gpio_disable(viafb_gpio_config.active_gpios[i]); 291 viafb_gpio_config.gpio_chip.ngpio = 0; 292 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags); 293 return 0; 294} 295 296static struct platform_driver via_gpio_driver = { 297 .driver = { 298 .name = "viafb-gpio", 299 }, 300 .probe = viafb_gpio_probe, 301 .remove = viafb_gpio_remove, 302}; 303 304int viafb_gpio_init(void) 305{ 306 return platform_driver_register(&via_gpio_driver); 307} 308 309void viafb_gpio_exit(void) 310{ 311 platform_driver_unregister(&via_gpio_driver); 312} 313