gpio-clps711x.c (bf61c8840efe60fd8f91446860b63338fb424158) | gpio-clps711x.c (55fe14ab872ab7a60944332c79640d561e93dfe8) |
---|---|
1/* 2 * CLPS711X GPIO driver 3 * | 1/* 2 * CLPS711X GPIO driver 3 * |
4 * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> | 4 * Copyright (C) 2012,2013 Alexander Shiyan <shc_work@mail.ru> |
5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 | 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 |
12#include <linux/io.h> 13#include <linux/slab.h> | 12#include <linux/err.h> |
14#include <linux/gpio.h> 15#include <linux/module.h> | 13#include <linux/gpio.h> 14#include <linux/module.h> |
16#include <linux/spinlock.h> | 15#include <linux/basic_mmio_gpio.h> |
17#include <linux/platform_device.h> 18 | 16#include <linux/platform_device.h> 17 |
19#include <mach/hardware.h> 20 21#define CLPS711X_GPIO_PORTS 5 22#define CLPS711X_GPIO_NAME "gpio-clps711x" 23 24struct clps711x_gpio { 25 struct gpio_chip chip[CLPS711X_GPIO_PORTS]; 26 spinlock_t lock; 27}; 28 29static void __iomem *clps711x_ports[] = { 30 CLPS711X_VIRT_BASE + PADR, 31 CLPS711X_VIRT_BASE + PBDR, 32 CLPS711X_VIRT_BASE + PCDR, 33 CLPS711X_VIRT_BASE + PDDR, 34 CLPS711X_VIRT_BASE + PEDR, 35}; 36 37static void __iomem *clps711x_pdirs[] = { 38 CLPS711X_VIRT_BASE + PADDR, 39 CLPS711X_VIRT_BASE + PBDDR, 40 CLPS711X_VIRT_BASE + PCDDR, 41 CLPS711X_VIRT_BASE + PDDDR, 42 CLPS711X_VIRT_BASE + PEDDR, 43}; 44 45#define clps711x_port(x) clps711x_ports[x->base / 8] 46#define clps711x_pdir(x) clps711x_pdirs[x->base / 8] 47 48static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) | 18static int clps711x_gpio_probe(struct platform_device *pdev) |
49{ | 19{ |
50 return !!(readb(clps711x_port(chip)) & (1 << offset)); 51} | 20 void __iomem *dat, *dir; 21 struct bgpio_chip *bgc; 22 struct resource *res; 23 int err, id = pdev->id; |
52 | 24 |
53static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, 54 int value) 55{ 56 int tmp; 57 unsigned long flags; 58 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 25 if ((id < 0) || (id > 4)) 26 return -ENODEV; |
59 | 27 |
60 spin_lock_irqsave(&gpio->lock, flags); 61 tmp = readb(clps711x_port(chip)) & ~(1 << offset); 62 if (value) 63 tmp |= 1 << offset; 64 writeb(tmp, clps711x_port(chip)); 65 spin_unlock_irqrestore(&gpio->lock, flags); 66} | 28 bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); 29 if (!bgc) 30 return -ENOMEM; |
67 | 31 |
68static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset) 69{ 70 int tmp; 71 unsigned long flags; 72 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 32 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 33 dat = devm_ioremap_resource(&pdev->dev, res); 34 if (IS_ERR(dat)) 35 return PTR_ERR(dat); |
73 | 36 |
74 spin_lock_irqsave(&gpio->lock, flags); 75 tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); 76 writeb(tmp, clps711x_pdir(chip)); 77 spin_unlock_irqrestore(&gpio->lock, flags); | 37 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 38 dir = devm_ioremap_resource(&pdev->dev, res); 39 if (IS_ERR(dir)) 40 return PTR_ERR(dir); |
78 | 41 |
79 return 0; 80} | 42 switch (id) { 43 case 3: 44 /* PORTD is inverted logic for direction register */ 45 err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL, 46 NULL, dir, 0); 47 break; 48 default: 49 err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL, 50 dir, NULL, 0); 51 break; 52 } |
81 | 53 |
82static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, 83 int value) 84{ 85 int tmp; 86 unsigned long flags; 87 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 54 if (err) 55 return err; |
88 | 56 |
89 spin_lock_irqsave(&gpio->lock, flags); 90 tmp = readb(clps711x_pdir(chip)) | (1 << offset); 91 writeb(tmp, clps711x_pdir(chip)); 92 tmp = readb(clps711x_port(chip)) & ~(1 << offset); 93 if (value) 94 tmp |= 1 << offset; 95 writeb(tmp, clps711x_port(chip)); 96 spin_unlock_irqrestore(&gpio->lock, flags); | 57 switch (id) { 58 case 4: 59 /* PORTE is 3 lines only */ 60 bgc->gc.ngpio = 3; 61 break; 62 default: 63 break; 64 } |
97 | 65 |
98 return 0; 99} | 66 bgc->gc.base = id * 8; 67 platform_set_drvdata(pdev, bgc); |
100 | 68 |
101static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) 102{ 103 int tmp; 104 unsigned long flags; 105 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); 106 107 spin_lock_irqsave(&gpio->lock, flags); 108 tmp = readb(clps711x_pdir(chip)) | (1 << offset); 109 writeb(tmp, clps711x_pdir(chip)); 110 spin_unlock_irqrestore(&gpio->lock, flags); 111 112 return 0; | 69 return gpiochip_add(&bgc->gc); |
113} 114 | 70} 71 |
115static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, 116 int value) | 72static int clps711x_gpio_remove(struct platform_device *pdev) |
117{ | 73{ |
118 int tmp; 119 unsigned long flags; 120 struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 74 struct bgpio_chip *bgc = platform_get_drvdata(pdev); |
121 | 75 |
122 spin_lock_irqsave(&gpio->lock, flags); 123 tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); 124 writeb(tmp, clps711x_pdir(chip)); 125 tmp = readb(clps711x_port(chip)) & ~(1 << offset); 126 if (value) 127 tmp |= 1 << offset; 128 writeb(tmp, clps711x_port(chip)); 129 spin_unlock_irqrestore(&gpio->lock, flags); 130 131 return 0; | 76 return bgpio_remove(bgc); |
132} 133 | 77} 78 |
134static struct { 135 char *name; 136 int nr; 137 int inv_dir; 138} clps711x_gpio_ports[] __initconst = { 139 { "PORTA", 8, 0, }, 140 { "PORTB", 8, 0, }, 141 { "PORTC", 8, 0, }, 142 { "PORTD", 8, 1, }, 143 { "PORTE", 3, 0, }, | 79static struct platform_driver clps711x_gpio_driver = { 80 .driver = { 81 .name = "clps711x-gpio", 82 .owner = THIS_MODULE, 83 }, 84 .probe = clps711x_gpio_probe, 85 .remove = clps711x_gpio_remove, |
144}; | 86}; |
87module_platform_driver(clps711x_gpio_driver); |
|
145 | 88 |
146static int __init gpio_clps711x_init(void) 147{ 148 int i; 149 struct platform_device *pdev; 150 struct clps711x_gpio *gpio; 151 152 pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); 153 if (!pdev) { 154 pr_err("Cannot create platform device: %s\n", 155 CLPS711X_GPIO_NAME); 156 return -ENOMEM; 157 } 158 159 platform_device_add(pdev); 160 161 gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), 162 GFP_KERNEL); 163 if (!gpio) { 164 dev_err(&pdev->dev, "GPIO allocating memory error\n"); 165 platform_device_unregister(pdev); 166 return -ENOMEM; 167 } 168 169 platform_set_drvdata(pdev, gpio); 170 171 spin_lock_init(&gpio->lock); 172 173 for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { 174 gpio->chip[i].owner = THIS_MODULE; 175 gpio->chip[i].dev = &pdev->dev; 176 gpio->chip[i].label = clps711x_gpio_ports[i].name; 177 gpio->chip[i].base = i * 8; 178 gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; 179 gpio->chip[i].get = gpio_clps711x_get; 180 gpio->chip[i].set = gpio_clps711x_set; 181 if (!clps711x_gpio_ports[i].inv_dir) { 182 gpio->chip[i].direction_input = gpio_clps711x_dir_in; 183 gpio->chip[i].direction_output = gpio_clps711x_dir_out; 184 } else { 185 gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv; 186 gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv; 187 } 188 WARN_ON(gpiochip_add(&gpio->chip[i])); 189 } 190 191 dev_info(&pdev->dev, "GPIO driver initialized\n"); 192 193 return 0; 194} 195arch_initcall(gpio_clps711x_init); 196 197MODULE_LICENSE("GPL v2"); | 89MODULE_LICENSE("GPL"); |
198MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 199MODULE_DESCRIPTION("CLPS711X GPIO driver"); | 90MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 91MODULE_DESCRIPTION("CLPS711X GPIO driver"); |