gpio-sch.c (4b4193256c8d3bc3a5397b5cd9494c2ad386317d) | gpio-sch.c (7a81638485c1a62a87b4c391ecc9c651a4a9dc19) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * GPIO interface for Intel Poulsbo SCH 4 * 5 * Copyright (c) 2010 CompuLab Ltd 6 * Author: Denis Turischev <denis@compulab.co.il> 7 */ 8 9#include <linux/acpi.h> 10#include <linux/errno.h> 11#include <linux/gpio/driver.h> 12#include <linux/io.h> | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * GPIO interface for Intel Poulsbo SCH 4 * 5 * Copyright (c) 2010 CompuLab Ltd 6 * Author: Denis Turischev <denis@compulab.co.il> 7 */ 8 9#include <linux/acpi.h> 10#include <linux/errno.h> 11#include <linux/gpio/driver.h> 12#include <linux/io.h> |
13#include <linux/irq.h> |
|
13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/pci_ids.h> 16#include <linux/platform_device.h> | 14#include <linux/kernel.h> 15#include <linux/module.h> 16#include <linux/pci_ids.h> 17#include <linux/platform_device.h> |
18#include <linux/types.h> |
|
17 18#define GEN 0x00 19#define GIO 0x04 20#define GLV 0x08 | 19 20#define GEN 0x00 21#define GIO 0x04 22#define GLV 0x08 |
23#define GTPE 0x0c 24#define GTNE 0x10 25#define GGPE 0x14 26#define GSMI 0x18 27#define GTS 0x1c |
|
21 | 28 |
29#define CORE_BANK_OFFSET 0x00 30#define RESUME_BANK_OFFSET 0x20 31 |
|
22struct sch_gpio { 23 struct gpio_chip chip; | 32struct sch_gpio { 33 struct gpio_chip chip; |
34 struct irq_chip irqchip; |
|
24 spinlock_t lock; 25 unsigned short iobase; 26 unsigned short resume_base; 27}; 28 29static unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio, 30 unsigned int reg) 31{ | 35 spinlock_t lock; 36 unsigned short iobase; 37 unsigned short resume_base; 38}; 39 40static unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio, 41 unsigned int reg) 42{ |
32 unsigned int base = 0; | 43 unsigned int base = CORE_BANK_OFFSET; |
33 34 if (gpio >= sch->resume_base) { 35 gpio -= sch->resume_base; | 44 45 if (gpio >= sch->resume_base) { 46 gpio -= sch->resume_base; |
36 base += 0x20; | 47 base = RESUME_BANK_OFFSET; |
37 } 38 39 return base + reg + gpio / 8; 40} 41 42static unsigned int sch_gpio_bit(struct sch_gpio *sch, unsigned int gpio) 43{ 44 if (gpio >= sch->resume_base) --- 29 unchanged lines hidden (view full) --- 74 outb(reg_val | BIT(bit), sch->iobase + offset); 75 else 76 outb((reg_val & ~BIT(bit)), sch->iobase + offset); 77} 78 79static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num) 80{ 81 struct sch_gpio *sch = gpiochip_get_data(gc); | 48 } 49 50 return base + reg + gpio / 8; 51} 52 53static unsigned int sch_gpio_bit(struct sch_gpio *sch, unsigned int gpio) 54{ 55 if (gpio >= sch->resume_base) --- 29 unchanged lines hidden (view full) --- 85 outb(reg_val | BIT(bit), sch->iobase + offset); 86 else 87 outb((reg_val & ~BIT(bit)), sch->iobase + offset); 88} 89 90static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num) 91{ 92 struct sch_gpio *sch = gpiochip_get_data(gc); |
93 unsigned long flags; |
|
82 | 94 |
83 spin_lock(&sch->lock); | 95 spin_lock_irqsave(&sch->lock, flags); |
84 sch_gpio_reg_set(sch, gpio_num, GIO, 1); | 96 sch_gpio_reg_set(sch, gpio_num, GIO, 1); |
85 spin_unlock(&sch->lock); | 97 spin_unlock_irqrestore(&sch->lock, flags); |
86 return 0; 87} 88 89static int sch_gpio_get(struct gpio_chip *gc, unsigned int gpio_num) 90{ 91 struct sch_gpio *sch = gpiochip_get_data(gc); 92 93 return sch_gpio_reg_get(sch, gpio_num, GLV); 94} 95 96static void sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val) 97{ 98 struct sch_gpio *sch = gpiochip_get_data(gc); | 98 return 0; 99} 100 101static int sch_gpio_get(struct gpio_chip *gc, unsigned int gpio_num) 102{ 103 struct sch_gpio *sch = gpiochip_get_data(gc); 104 105 return sch_gpio_reg_get(sch, gpio_num, GLV); 106} 107 108static void sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val) 109{ 110 struct sch_gpio *sch = gpiochip_get_data(gc); |
111 unsigned long flags; |
|
99 | 112 |
100 spin_lock(&sch->lock); | 113 spin_lock_irqsave(&sch->lock, flags); |
101 sch_gpio_reg_set(sch, gpio_num, GLV, val); | 114 sch_gpio_reg_set(sch, gpio_num, GLV, val); |
102 spin_unlock(&sch->lock); | 115 spin_unlock_irqrestore(&sch->lock, flags); |
103} 104 105static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num, 106 int val) 107{ 108 struct sch_gpio *sch = gpiochip_get_data(gc); | 116} 117 118static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num, 119 int val) 120{ 121 struct sch_gpio *sch = gpiochip_get_data(gc); |
122 unsigned long flags; |
|
109 | 123 |
110 spin_lock(&sch->lock); | 124 spin_lock_irqsave(&sch->lock, flags); |
111 sch_gpio_reg_set(sch, gpio_num, GIO, 0); | 125 sch_gpio_reg_set(sch, gpio_num, GIO, 0); |
112 spin_unlock(&sch->lock); | 126 spin_unlock_irqrestore(&sch->lock, flags); |
113 114 /* 115 * according to the datasheet, writing to the level register has no 116 * effect when GPIO is programmed as input. 117 * Actually the the level register is read-only when configured as input. 118 * Thus presetting the output level before switching to output is _NOT_ possible. 119 * Hence we set the level after configuring the GPIO as output. 120 * But we cannot prevent a short low pulse if direction is set to high --- 18 unchanged lines hidden (view full) --- 139 .owner = THIS_MODULE, 140 .direction_input = sch_gpio_direction_in, 141 .get = sch_gpio_get, 142 .direction_output = sch_gpio_direction_out, 143 .set = sch_gpio_set, 144 .get_direction = sch_gpio_get_direction, 145}; 146 | 127 128 /* 129 * according to the datasheet, writing to the level register has no 130 * effect when GPIO is programmed as input. 131 * Actually the the level register is read-only when configured as input. 132 * Thus presetting the output level before switching to output is _NOT_ possible. 133 * Hence we set the level after configuring the GPIO as output. 134 * But we cannot prevent a short low pulse if direction is set to high --- 18 unchanged lines hidden (view full) --- 153 .owner = THIS_MODULE, 154 .direction_input = sch_gpio_direction_in, 155 .get = sch_gpio_get, 156 .direction_output = sch_gpio_direction_out, 157 .set = sch_gpio_set, 158 .get_direction = sch_gpio_get_direction, 159}; 160 |
161static int sch_irq_type(struct irq_data *d, unsigned int type) 162{ 163 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 164 struct sch_gpio *sch = gpiochip_get_data(gc); 165 irq_hw_number_t gpio_num = irqd_to_hwirq(d); 166 unsigned long flags; 167 int rising, falling; 168 169 switch (type & IRQ_TYPE_SENSE_MASK) { 170 case IRQ_TYPE_EDGE_RISING: 171 rising = 1; 172 falling = 0; 173 break; 174 case IRQ_TYPE_EDGE_FALLING: 175 rising = 0; 176 falling = 1; 177 break; 178 case IRQ_TYPE_EDGE_BOTH: 179 rising = 1; 180 falling = 1; 181 break; 182 default: 183 return -EINVAL; 184 } 185 186 spin_lock_irqsave(&sch->lock, flags); 187 188 sch_gpio_reg_set(sch, gpio_num, GTPE, rising); 189 sch_gpio_reg_set(sch, gpio_num, GTNE, falling); 190 191 irq_set_handler_locked(d, handle_edge_irq); 192 193 spin_unlock_irqrestore(&sch->lock, flags); 194 195 return 0; 196} 197 198static void sch_irq_ack(struct irq_data *d) 199{ 200 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 201 struct sch_gpio *sch = gpiochip_get_data(gc); 202 irq_hw_number_t gpio_num = irqd_to_hwirq(d); 203 unsigned long flags; 204 205 spin_lock_irqsave(&sch->lock, flags); 206 sch_gpio_reg_set(sch, gpio_num, GTS, 1); 207 spin_unlock_irqrestore(&sch->lock, flags); 208} 209 210static void sch_irq_mask_unmask(struct irq_data *d, int val) 211{ 212 struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 213 struct sch_gpio *sch = gpiochip_get_data(gc); 214 irq_hw_number_t gpio_num = irqd_to_hwirq(d); 215 unsigned long flags; 216 217 spin_lock_irqsave(&sch->lock, flags); 218 sch_gpio_reg_set(sch, gpio_num, GGPE, val); 219 spin_unlock_irqrestore(&sch->lock, flags); 220} 221 222static void sch_irq_mask(struct irq_data *d) 223{ 224 sch_irq_mask_unmask(d, 0); 225} 226 227static void sch_irq_unmask(struct irq_data *d) 228{ 229 sch_irq_mask_unmask(d, 1); 230} 231 |
|
147static int sch_gpio_probe(struct platform_device *pdev) 148{ | 232static int sch_gpio_probe(struct platform_device *pdev) 233{ |
234 struct gpio_irq_chip *girq; |
|
149 struct sch_gpio *sch; 150 struct resource *res; 151 152 sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); 153 if (!sch) 154 return -ENOMEM; 155 156 res = platform_get_resource(pdev, IORESOURCE_IO, 0); --- 45 unchanged lines hidden (view full) --- 202 break; 203 204 default: 205 return -ENODEV; 206 } 207 208 platform_set_drvdata(pdev, sch); 209 | 235 struct sch_gpio *sch; 236 struct resource *res; 237 238 sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL); 239 if (!sch) 240 return -ENOMEM; 241 242 res = platform_get_resource(pdev, IORESOURCE_IO, 0); --- 45 unchanged lines hidden (view full) --- 288 break; 289 290 default: 291 return -ENODEV; 292 } 293 294 platform_set_drvdata(pdev, sch); 295 |
296 sch->irqchip.name = "sch_gpio"; 297 sch->irqchip.irq_ack = sch_irq_ack; 298 sch->irqchip.irq_mask = sch_irq_mask; 299 sch->irqchip.irq_unmask = sch_irq_unmask; 300 sch->irqchip.irq_set_type = sch_irq_type; 301 302 girq = &sch->chip.irq; 303 girq->chip = &sch->irqchip; 304 girq->num_parents = 0; 305 girq->parents = NULL; 306 girq->parent_handler = NULL; 307 girq->default_type = IRQ_TYPE_NONE; 308 girq->handler = handle_bad_irq; 309 |
|
210 return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch); 211} 212 213static struct platform_driver sch_gpio_driver = { 214 .driver = { 215 .name = "sch_gpio", 216 }, 217 .probe = sch_gpio_probe, 218}; 219 220module_platform_driver(sch_gpio_driver); 221 222MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>"); 223MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH"); 224MODULE_LICENSE("GPL v2"); 225MODULE_ALIAS("platform:sch_gpio"); | 310 return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch); 311} 312 313static struct platform_driver sch_gpio_driver = { 314 .driver = { 315 .name = "sch_gpio", 316 }, 317 .probe = sch_gpio_probe, 318}; 319 320module_platform_driver(sch_gpio_driver); 321 322MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>"); 323MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH"); 324MODULE_LICENSE("GPL v2"); 325MODULE_ALIAS("platform:sch_gpio"); |