gpio-stmpe.c 11.0 KB
Newer Older
R
Rabin Vincent 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Copyright (C) ST-Ericsson SA 2010
 *
 * License Terms: GNU General Public License, version 2
 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
14
#include <linux/irqdomain.h>
R
Rabin Vincent 已提交
15
#include <linux/interrupt.h>
16
#include <linux/of.h>
R
Rabin Vincent 已提交
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include <linux/mfd/stmpe.h>

/*
 * These registers are modified under the irq bus lock and cached to avoid
 * unnecessary writes in bus_sync_unlock.
 */
enum { REG_RE, REG_FE, REG_IE };

#define CACHE_NR_REGS	3
#define CACHE_NR_BANKS	(STMPE_NR_GPIOS / 8)

struct stmpe_gpio {
	struct gpio_chip chip;
	struct stmpe *stmpe;
	struct device *dev;
	struct mutex irq_lock;
33
	struct irq_domain *domain;
R
Rabin Vincent 已提交
34 35

	int irq_base;
36
	unsigned norequest_mask;
R
Rabin Vincent 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

	/* Caches of interrupt control registers for bus_lock */
	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
	u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};

static inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
{
	return container_of(chip, struct stmpe_gpio, chip);
}

static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
{
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
	u8 mask = 1 << (offset % 8);
	int ret;

	ret = stmpe_reg_read(stmpe, reg);
	if (ret < 0)
		return ret;

60
	return !!(ret & mask);
R
Rabin Vincent 已提交
61 62 63 64 65 66 67 68 69 70
}

static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
	u8 reg = stmpe->regs[which] - (offset / 8);
	u8 mask = 1 << (offset % 8);

71 72 73 74 75 76 77 78
	/*
	 * Some variants have single register for gpio set/clear functionality.
	 * For them we need to write 0 to clear and 1 to set.
	 */
	if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB])
		stmpe_set_bits(stmpe, reg, mask, val ? mask : 0);
	else
		stmpe_reg_write(stmpe, reg, mask);
R
Rabin Vincent 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
}

static int stmpe_gpio_direction_output(struct gpio_chip *chip,
					 unsigned offset, int val)
{
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
	u8 mask = 1 << (offset % 8);

	stmpe_gpio_set(chip, offset, val);

	return stmpe_set_bits(stmpe, reg, mask, mask);
}

static int stmpe_gpio_direction_input(struct gpio_chip *chip,
					unsigned offset)
{
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
	u8 mask = 1 << (offset % 8);

	return stmpe_set_bits(stmpe, reg, mask, 0);
}

static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);

109
	return irq_create_mapping(stmpe_gpio->domain, offset);
R
Rabin Vincent 已提交
110 111 112 113 114 115 116
}

static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
{
	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
	struct stmpe *stmpe = stmpe_gpio->stmpe;

117 118 119
	if (stmpe_gpio->norequest_mask & (1 << offset))
		return -EINVAL;

R
Rabin Vincent 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
	return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
}

static struct gpio_chip template_chip = {
	.label			= "stmpe",
	.owner			= THIS_MODULE,
	.direction_input	= stmpe_gpio_direction_input,
	.get			= stmpe_gpio_get,
	.direction_output	= stmpe_gpio_direction_output,
	.set			= stmpe_gpio_set,
	.to_irq			= stmpe_gpio_to_irq,
	.request		= stmpe_gpio_request,
	.can_sleep		= 1,
};

135
static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
R
Rabin Vincent 已提交
136
{
137
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
138
	int offset = d->hwirq;
R
Rabin Vincent 已提交
139 140 141 142 143 144
	int regoffset = offset / 8;
	int mask = 1 << (offset % 8);

	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
		return -EINVAL;

145 146 147 148
	/* STMPE801 doesn't have RE and FE registers */
	if (stmpe_gpio->stmpe->partnum == STMPE801)
		return 0;

R
Rabin Vincent 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161
	if (type == IRQ_TYPE_EDGE_RISING)
		stmpe_gpio->regs[REG_RE][regoffset] |= mask;
	else
		stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;

	if (type == IRQ_TYPE_EDGE_FALLING)
		stmpe_gpio->regs[REG_FE][regoffset] |= mask;
	else
		stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;

	return 0;
}

162
static void stmpe_gpio_irq_lock(struct irq_data *d)
R
Rabin Vincent 已提交
163
{
164
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
R
Rabin Vincent 已提交
165 166 167 168

	mutex_lock(&stmpe_gpio->irq_lock);
}

169
static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
R
Rabin Vincent 已提交
170
{
171
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
R
Rabin Vincent 已提交
172 173 174 175 176 177 178 179 180 181
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
	static const u8 regmap[] = {
		[REG_RE]	= STMPE_IDX_GPRER_LSB,
		[REG_FE]	= STMPE_IDX_GPFER_LSB,
		[REG_IE]	= STMPE_IDX_IEGPIOR_LSB,
	};
	int i, j;

	for (i = 0; i < CACHE_NR_REGS; i++) {
182 183 184 185 186
		/* STMPE801 doesn't have RE and FE registers */
		if ((stmpe->partnum == STMPE801) &&
				(i != REG_IE))
			continue;

R
Rabin Vincent 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
		for (j = 0; j < num_banks; j++) {
			u8 old = stmpe_gpio->oldregs[i][j];
			u8 new = stmpe_gpio->regs[i][j];

			if (new == old)
				continue;

			stmpe_gpio->oldregs[i][j] = new;
			stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
		}
	}

	mutex_unlock(&stmpe_gpio->irq_lock);
}

202
static void stmpe_gpio_irq_mask(struct irq_data *d)
R
Rabin Vincent 已提交
203
{
204
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
205
	int offset = d->hwirq;
R
Rabin Vincent 已提交
206 207 208 209 210 211
	int regoffset = offset / 8;
	int mask = 1 << (offset % 8);

	stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
}

212
static void stmpe_gpio_irq_unmask(struct irq_data *d)
R
Rabin Vincent 已提交
213
{
214
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
215
	int offset = d->hwirq;
R
Rabin Vincent 已提交
216 217 218 219 220 221 222 223
	int regoffset = offset / 8;
	int mask = 1 << (offset % 8);

	stmpe_gpio->regs[REG_IE][regoffset] |= mask;
}

static struct irq_chip stmpe_gpio_irq_chip = {
	.name			= "stmpe-gpio",
224 225 226 227 228
	.irq_bus_lock		= stmpe_gpio_irq_lock,
	.irq_bus_sync_unlock	= stmpe_gpio_irq_sync_unlock,
	.irq_mask		= stmpe_gpio_irq_mask,
	.irq_unmask		= stmpe_gpio_irq_unmask,
	.irq_set_type		= stmpe_gpio_irq_set_type,
R
Rabin Vincent 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
};

static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
{
	struct stmpe_gpio *stmpe_gpio = dev;
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
	u8 status[num_banks];
	int ret;
	int i;

	ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
	if (ret < 0)
		return IRQ_NONE;

	for (i = 0; i < num_banks; i++) {
		int bank = num_banks - i - 1;
		unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
		unsigned int stat = status[i];

		stat &= enabled;
		if (!stat)
			continue;

		while (stat) {
			int bit = __ffs(stat);
			int line = bank * 8 + bit;
257
			int virq = irq_find_mapping(stmpe_gpio->domain, line);
R
Rabin Vincent 已提交
258

259
			handle_nested_irq(virq);
R
Rabin Vincent 已提交
260 261 262 263
			stat &= ~(1 << bit);
		}

		stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
264 265 266 267 268

		/* Edge detect register is not present on 801 */
		if (stmpe->partnum != STMPE801)
			stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
					+ i, status[i]);
R
Rabin Vincent 已提交
269 270 271 272 273
	}

	return IRQ_HANDLED;
}

274 275
int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
		       irq_hw_number_t hwirq)
R
Rabin Vincent 已提交
276
{
277 278 279 280
	struct stmpe_gpio *stmpe_gpio = d->host_data;

	if (!stmpe_gpio)
		return -EINVAL;
R
Rabin Vincent 已提交
281

282 283 284 285
	irq_set_chip_data(hwirq, stmpe_gpio);
	irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip,
				 handle_simple_irq);
	irq_set_nested_thread(hwirq, 1);
R
Rabin Vincent 已提交
286
#ifdef CONFIG_ARM
287
	set_irq_flags(hwirq, IRQF_VALID);
R
Rabin Vincent 已提交
288
#else
289
	irq_set_noprobe(hwirq);
R
Rabin Vincent 已提交
290 291 292 293 294
#endif

	return 0;
}

295
void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
R
Rabin Vincent 已提交
296 297
{
#ifdef CONFIG_ARM
298
	set_irq_flags(virq, 0);
R
Rabin Vincent 已提交
299
#endif
300 301 302 303 304 305 306 307 308 309
	irq_set_chip_and_handler(virq, NULL, NULL);
	irq_set_chip_data(virq, NULL);
}

static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
	.unmap = stmpe_gpio_irq_unmap,
	.map = stmpe_gpio_irq_map,
	.xlate = irq_domain_xlate_twocell,
};

310
static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
311 312 313 314 315 316 317 318 319
{
	int base = stmpe_gpio->irq_base;

	stmpe_gpio->domain = irq_domain_add_simple(NULL,
				stmpe_gpio->chip.ngpio, base,
				&stmpe_gpio_irq_simple_ops, stmpe_gpio);
	if (!stmpe_gpio->domain) {
		dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
		return -ENOSYS;
R
Rabin Vincent 已提交
320
	}
321 322

	return 0;
R
Rabin Vincent 已提交
323 324
}

B
Bill Pemberton 已提交
325
static int stmpe_gpio_probe(struct platform_device *pdev)
R
Rabin Vincent 已提交
326 327
{
	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
328
	struct device_node *np = pdev->dev.of_node;
R
Rabin Vincent 已提交
329 330 331
	struct stmpe_gpio_platform_data *pdata;
	struct stmpe_gpio *stmpe_gpio;
	int ret;
C
Chris Blair 已提交
332
	int irq = 0;
R
Rabin Vincent 已提交
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350

	pdata = stmpe->pdata->gpio;

	irq = platform_get_irq(pdev, 0);

	stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
	if (!stmpe_gpio)
		return -ENOMEM;

	mutex_init(&stmpe_gpio->irq_lock);

	stmpe_gpio->dev = &pdev->dev;
	stmpe_gpio->stmpe = stmpe;
	stmpe_gpio->chip = template_chip;
	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
	stmpe_gpio->chip.dev = &pdev->dev;
	stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;

351 352 353 354 355 356
	if (pdata)
		stmpe_gpio->norequest_mask = pdata->norequest_mask;
	else if (np)
		of_property_read_u32(np, "st,norequest-mask",
				&stmpe_gpio->norequest_mask);

C
Chris Blair 已提交
357 358 359 360 361 362
	if (irq >= 0)
		stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
	else
		dev_info(&pdev->dev,
			"device configured in no-irq mode; "
			"irqs are not available\n");
R
Rabin Vincent 已提交
363 364 365

	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
	if (ret)
V
Vasiliy Kulikov 已提交
366
		goto out_free;
R
Rabin Vincent 已提交
367

C
Chris Blair 已提交
368 369 370 371
	if (irq >= 0) {
		ret = stmpe_gpio_irq_init(stmpe_gpio);
		if (ret)
			goto out_disable;
R
Rabin Vincent 已提交
372

C
Chris Blair 已提交
373 374 375 376
		ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
				IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
		if (ret) {
			dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
377
			goto out_disable;
C
Chris Blair 已提交
378
		}
R
Rabin Vincent 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	}

	ret = gpiochip_add(&stmpe_gpio->chip);
	if (ret) {
		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
		goto out_freeirq;
	}

	if (pdata && pdata->setup)
		pdata->setup(stmpe, stmpe_gpio->chip.base);

	platform_set_drvdata(pdev, stmpe_gpio);

	return 0;

out_freeirq:
C
Chris Blair 已提交
395 396
	if (irq >= 0)
		free_irq(irq, stmpe_gpio);
V
Vasiliy Kulikov 已提交
397 398
out_disable:
	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
R
Rabin Vincent 已提交
399 400 401 402 403
out_free:
	kfree(stmpe_gpio);
	return ret;
}

B
Bill Pemberton 已提交
404
static int stmpe_gpio_remove(struct platform_device *pdev)
R
Rabin Vincent 已提交
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
{
	struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
	struct stmpe *stmpe = stmpe_gpio->stmpe;
	struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
	int irq = platform_get_irq(pdev, 0);
	int ret;

	if (pdata && pdata->remove)
		pdata->remove(stmpe, stmpe_gpio->chip.base);

	ret = gpiochip_remove(&stmpe_gpio->chip);
	if (ret < 0) {
		dev_err(stmpe_gpio->dev,
			"unable to remove gpiochip: %d\n", ret);
		return ret;
	}

	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);

424
	if (irq >= 0)
C
Chris Blair 已提交
425
		free_irq(irq, stmpe_gpio);
426

R
Rabin Vincent 已提交
427 428 429 430 431 432 433 434 435 436
	platform_set_drvdata(pdev, NULL);
	kfree(stmpe_gpio);

	return 0;
}

static struct platform_driver stmpe_gpio_driver = {
	.driver.name	= "stmpe-gpio",
	.driver.owner	= THIS_MODULE,
	.probe		= stmpe_gpio_probe,
B
Bill Pemberton 已提交
437
	.remove		= stmpe_gpio_remove,
R
Rabin Vincent 已提交
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
};

static int __init stmpe_gpio_init(void)
{
	return platform_driver_register(&stmpe_gpio_driver);
}
subsys_initcall(stmpe_gpio_init);

static void __exit stmpe_gpio_exit(void)
{
	platform_driver_unregister(&stmpe_gpio_driver);
}
module_exit(stmpe_gpio_exit);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPExxxx GPIO driver");
MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");