0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/spinlock.h>
0009 #include <linux/gpio/driver.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/via-core.h>
0012 #include <linux/via-gpio.h>
0013 #include <linux/export.h>
0014
0015
0016
0017
0018
0019
0020 struct viafb_gpio {
0021 char *vg_name;
0022 u16 vg_io_port;
0023 u8 vg_port_index;
0024 int vg_mask_shift;
0025 };
0026
0027 static struct viafb_gpio viafb_all_gpios[] = {
0028 {
0029 .vg_name = "VGPIO0",
0030 .vg_io_port = VIASR,
0031 .vg_port_index = 0x25,
0032 .vg_mask_shift = 1
0033 },
0034 {
0035 .vg_name = "VGPIO1",
0036 .vg_io_port = VIASR,
0037 .vg_port_index = 0x25,
0038 .vg_mask_shift = 0
0039 },
0040 {
0041 .vg_name = "VGPIO2",
0042 .vg_io_port = VIASR,
0043 .vg_port_index = 0x2c,
0044 .vg_mask_shift = 1
0045 },
0046 {
0047 .vg_name = "VGPIO3",
0048 .vg_io_port = VIASR,
0049 .vg_port_index = 0x2c,
0050 .vg_mask_shift = 0
0051 },
0052 {
0053 .vg_name = "VGPIO4",
0054 .vg_io_port = VIASR,
0055 .vg_port_index = 0x3d,
0056 .vg_mask_shift = 1
0057 },
0058 {
0059 .vg_name = "VGPIO5",
0060 .vg_io_port = VIASR,
0061 .vg_port_index = 0x3d,
0062 .vg_mask_shift = 0
0063 },
0064 };
0065
0066 #define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
0067
0068
0069
0070
0071
0072
0073 struct viafb_gpio_cfg {
0074 struct gpio_chip gpio_chip;
0075 struct viafb_dev *vdev;
0076 struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
0077 const char *gpio_names[VIAFB_NUM_GPIOS];
0078 };
0079
0080
0081
0082
0083 static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
0084 int value)
0085 {
0086 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
0087 u8 reg;
0088 struct viafb_gpio *gpio;
0089 unsigned long flags;
0090
0091 spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
0092 gpio = cfg->active_gpios[nr];
0093 reg = via_read_reg(VIASR, gpio->vg_port_index);
0094 reg |= 0x40 << gpio->vg_mask_shift;
0095 if (value)
0096 reg |= 0x10 << gpio->vg_mask_shift;
0097 else
0098 reg &= ~(0x10 << gpio->vg_mask_shift);
0099 via_write_reg(VIASR, gpio->vg_port_index, reg);
0100 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
0101 }
0102
0103 static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
0104 int value)
0105 {
0106 via_gpio_set(chip, nr, value);
0107 return 0;
0108 }
0109
0110
0111
0112
0113
0114 static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
0115 {
0116 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
0117 struct viafb_gpio *gpio;
0118 unsigned long flags;
0119
0120 spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
0121 gpio = cfg->active_gpios[nr];
0122 via_write_reg_mask(VIASR, gpio->vg_port_index, 0,
0123 0x40 << gpio->vg_mask_shift);
0124 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
0125 return 0;
0126 }
0127
0128 static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
0129 {
0130 struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
0131 u8 reg;
0132 struct viafb_gpio *gpio;
0133 unsigned long flags;
0134
0135 spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
0136 gpio = cfg->active_gpios[nr];
0137 reg = via_read_reg(VIASR, gpio->vg_port_index);
0138 spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
0139 return !!(reg & (0x04 << gpio->vg_mask_shift));
0140 }
0141
0142
0143 static struct viafb_gpio_cfg viafb_gpio_config = {
0144 .gpio_chip = {
0145 .label = "VIAFB onboard GPIO",
0146 .owner = THIS_MODULE,
0147 .direction_output = via_gpio_dir_out,
0148 .set = via_gpio_set,
0149 .direction_input = via_gpio_dir_input,
0150 .get = via_gpio_get,
0151 .base = -1,
0152 .ngpio = 0,
0153 .can_sleep = 0
0154 }
0155 };
0156
0157
0158
0159
0160 static void viafb_gpio_enable(struct viafb_gpio *gpio)
0161 {
0162 via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02);
0163 }
0164
0165 static void viafb_gpio_disable(struct viafb_gpio *gpio)
0166 {
0167 via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
0168 }
0169
0170 #ifdef CONFIG_PM
0171
0172 static int viafb_gpio_suspend(void *private)
0173 {
0174 return 0;
0175 }
0176
0177 static int viafb_gpio_resume(void *private)
0178 {
0179 int i;
0180
0181 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
0182 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
0183 return 0;
0184 }
0185
0186 static struct viafb_pm_hooks viafb_gpio_pm_hooks = {
0187 .suspend = viafb_gpio_suspend,
0188 .resume = viafb_gpio_resume
0189 };
0190 #endif
0191
0192
0193
0194
0195 int viafb_gpio_lookup(const char *name)
0196 {
0197 int i;
0198
0199 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++)
0200 if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name))
0201 return viafb_gpio_config.gpio_chip.base + i;
0202 return -1;
0203 }
0204 EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
0205
0206
0207
0208
0209 static int viafb_gpio_probe(struct platform_device *platdev)
0210 {
0211 struct viafb_dev *vdev = platdev->dev.platform_data;
0212 struct via_port_cfg *port_cfg = vdev->port_cfg;
0213 int i, ngpio = 0, ret;
0214 struct viafb_gpio *gpio;
0215 unsigned long flags;
0216
0217
0218
0219
0220
0221 for (i = 0; i < VIAFB_NUM_PORTS; i++) {
0222 if (port_cfg[i].mode != VIA_MODE_GPIO)
0223 continue;
0224 for (gpio = viafb_all_gpios;
0225 gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
0226 if (gpio->vg_port_index == port_cfg[i].ioport_index) {
0227 viafb_gpio_config.active_gpios[ngpio] = gpio;
0228 viafb_gpio_config.gpio_names[ngpio] =
0229 gpio->vg_name;
0230 ngpio++;
0231 }
0232 }
0233 viafb_gpio_config.gpio_chip.ngpio = ngpio;
0234 viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names;
0235 viafb_gpio_config.vdev = vdev;
0236 if (ngpio == 0) {
0237 printk(KERN_INFO "viafb: no GPIOs configured\n");
0238 return 0;
0239 }
0240
0241
0242
0243
0244 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
0245 for (i = 0; i < ngpio; i += 2)
0246 viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
0247 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
0248
0249
0250
0251 viafb_gpio_config.gpio_chip.base = -1;
0252 ret = gpiochip_add_data(&viafb_gpio_config.gpio_chip,
0253 &viafb_gpio_config);
0254 if (ret) {
0255 printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
0256 viafb_gpio_config.gpio_chip.ngpio = 0;
0257 }
0258 #ifdef CONFIG_PM
0259 viafb_pm_register(&viafb_gpio_pm_hooks);
0260 #endif
0261 return ret;
0262 }
0263
0264
0265 static int viafb_gpio_remove(struct platform_device *platdev)
0266 {
0267 unsigned long flags;
0268 int i;
0269
0270 #ifdef CONFIG_PM
0271 viafb_pm_unregister(&viafb_gpio_pm_hooks);
0272 #endif
0273
0274
0275
0276
0277 if (viafb_gpio_config.gpio_chip.ngpio > 0) {
0278 gpiochip_remove(&viafb_gpio_config.gpio_chip);
0279 }
0280
0281
0282
0283 spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
0284 for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
0285 viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
0286 viafb_gpio_config.gpio_chip.ngpio = 0;
0287 spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
0288 return 0;
0289 }
0290
0291 static struct platform_driver via_gpio_driver = {
0292 .driver = {
0293 .name = "viafb-gpio",
0294 },
0295 .probe = viafb_gpio_probe,
0296 .remove = viafb_gpio_remove,
0297 };
0298
0299 int viafb_gpio_init(void)
0300 {
0301 return platform_driver_register(&via_gpio_driver);
0302 }
0303
0304 void viafb_gpio_exit(void)
0305 {
0306 platform_driver_unregister(&via_gpio_driver);
0307 }