linux/drivers/video/fbdev/via/via-gpio.c
<<
>>
Prefs
   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