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
#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
26 27
/* No variant has more than 24 GPIOs */
#define CACHE_NR_BANKS	(24 / 8)
R
Rabin Vincent 已提交
28 29 30 31 32 33

struct stmpe_gpio {
	struct gpio_chip chip;
	struct stmpe *stmpe;
	struct device *dev;
	struct mutex irq_lock;
34
	struct irq_domain *domain;
35
	unsigned norequest_mask;
R
Rabin Vincent 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

	/* 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;

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

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);

70 71 72 73 74 75 76 77
	/*
	 * 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 已提交
78 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
}

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);

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

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;

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

R
Rabin Vincent 已提交
119 120 121 122 123 124 125 126 127 128 129 130
	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,
131
	.can_sleep		= true,
R
Rabin Vincent 已提交
132 133
};

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

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

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

R
Rabin Vincent 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160
	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;
}

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

	mutex_lock(&stmpe_gpio->irq_lock);
}

168
static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
R
Rabin Vincent 已提交
169
{
170
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
R
Rabin Vincent 已提交
171 172 173 174 175 176 177 178 179 180
	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++) {
181 182 183 184 185
		/* STMPE801 doesn't have RE and FE registers */
		if ((stmpe->partnum == STMPE801) &&
				(i != REG_IE))
			continue;

R
Rabin Vincent 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
		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);
}

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

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

211
static void stmpe_gpio_irq_unmask(struct irq_data *d)
R
Rabin Vincent 已提交
212
{
213
	struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
214
	int offset = d->hwirq;
R
Rabin Vincent 已提交
215 216 217 218 219 220 221 222
	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",
223 224 225 226 227
	.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 已提交
228 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
};

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;
256 257
			int child_irq = irq_find_mapping(stmpe_gpio->domain,
							 line);
R
Rabin Vincent 已提交
258

259
			handle_nested_irq(child_irq);
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
static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq,
275
			      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
	irq_set_chip_data(irq, stmpe_gpio);
	irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
284
				 handle_simple_irq);
285
	irq_set_nested_thread(irq, 1);
R
Rabin Vincent 已提交
286
#ifdef CONFIG_ARM
287
	set_irq_flags(irq, IRQF_VALID);
R
Rabin Vincent 已提交
288
#else
289
	irq_set_noprobe(irq);
R
Rabin Vincent 已提交
290 291 292 293 294
#endif

	return 0;
}

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

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 311
static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
		struct device_node *np)
312
{
313
	stmpe_gpio->domain = irq_domain_add_simple(np,
314
				stmpe_gpio->chip.ngpio, 0,
315 316 317 318
				&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 已提交
319
	}
320 321

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

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

	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;
348 349 350
#ifdef CONFIG_OF
	stmpe_gpio->chip.of_node = np;
#endif
351
	stmpe_gpio->chip.base = -1;
R
Rabin Vincent 已提交
352

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

359
	if (irq < 0)
C
Chris Blair 已提交
360 361 362
		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
	if (irq >= 0) {
369
		ret = stmpe_gpio_irq_init(stmpe_gpio, np);
C
Chris Blair 已提交
370 371
		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
	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 已提交
436
	.remove		= stmpe_gpio_remove,
R
Rabin Vincent 已提交
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
};

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>");