sh_keysc.c 8.2 KB
Newer Older
M
Magnus Damm 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * SuperH KEYSC Keypad Driver
 *
 * Copyright (C) 2008 Magnus Damm
 *
 * Based on gpio_keys.c, Copyright 2005 Phil Blundell
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
M
Magnus Damm 已提交
21
#include <linux/input/sh_keysc.h>
22
#include <linux/bitmap.h>
23
#include <linux/pm_runtime.h>
M
Magnus Damm 已提交
24
#include <linux/io.h>
25
#include <linux/slab.h>
M
Magnus Damm 已提交
26 27 28 29 30 31 32

static const struct {
	unsigned char kymd, keyout, keyin;
} sh_keysc_mode[] = {
	[SH_KEYSC_MODE_1] = { 0, 6, 5 },
	[SH_KEYSC_MODE_2] = { 1, 5, 6 },
	[SH_KEYSC_MODE_3] = { 2, 4, 7 },
33 34
	[SH_KEYSC_MODE_4] = { 3, 6, 6 },
	[SH_KEYSC_MODE_5] = { 4, 6, 7 },
M
Magnus Damm 已提交
35
	[SH_KEYSC_MODE_6] = { 5, 8, 8 },
M
Magnus Damm 已提交
36 37 38 39
};

struct sh_keysc_priv {
	void __iomem *iomem_base;
40
	DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
M
Magnus Damm 已提交
41 42 43 44
	struct input_dev *input;
	struct sh_keysc_info pdata;
};

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#define KYCR1 0
#define KYCR2 1
#define KYINDR 2
#define KYOUTDR 3

#define KYCR2_IRQ_LEVEL    0x10
#define KYCR2_IRQ_DISABLED 0x00

static unsigned long sh_keysc_read(struct sh_keysc_priv *p, int reg_nr)
{
	return ioread16(p->iomem_base + (reg_nr << 2));
}

static void sh_keysc_write(struct sh_keysc_priv *p, int reg_nr,
			   unsigned long value)
{
	iowrite16(value, p->iomem_base + (reg_nr << 2));
}

static void sh_keysc_level_mode(struct sh_keysc_priv *p,
				unsigned long keys_set)
{
	struct sh_keysc_info *pdata = &p->pdata;

	sh_keysc_write(p, KYOUTDR, 0);
	sh_keysc_write(p, KYCR2, KYCR2_IRQ_LEVEL | (keys_set << 8));

	if (pdata->kycr2_delay)
		udelay(pdata->kycr2_delay);
}

76 77 78 79 80 81 82 83 84
static void sh_keysc_map_dbg(struct device *dev, unsigned long *map,
			     const char *str)
{
	int k;

	for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++)
		dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]);
}

M
Magnus Damm 已提交
85 86 87 88 89
static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
{
	struct platform_device *pdev = dev_id;
	struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
	struct sh_keysc_info *pdata = &priv->pdata;
90 91 92 93 94
	int keyout_nr = sh_keysc_mode[pdata->mode].keyout;
	int keyin_nr = sh_keysc_mode[pdata->mode].keyin;
	DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS);
	DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS);
	DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS);
M
Magnus Damm 已提交
95
	unsigned char keyin_set, tmp;
96
	int i, k, n;
M
Magnus Damm 已提交
97 98 99

	dev_dbg(&pdev->dev, "isr!\n");

100 101
	bitmap_fill(keys1, SH_KEYSC_MAXKEYS);
	bitmap_zero(keys0, SH_KEYSC_MAXKEYS);
M
Magnus Damm 已提交
102 103

	do {
104
		bitmap_zero(keys, SH_KEYSC_MAXKEYS);
M
Magnus Damm 已提交
105 106
		keyin_set = 0;

107
		sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
M
Magnus Damm 已提交
108

109 110 111 112
		for (i = 0; i < keyout_nr; i++) {
			n = keyin_nr * i;

			/* drive one KEYOUT pin low, read KEYIN pins */
113
			sh_keysc_write(priv, KYOUTDR, 0xffff ^ (3 << (i * 2)));
M
Magnus Damm 已提交
114
			udelay(pdata->delay);
115 116
			tmp = sh_keysc_read(priv, KYINDR);

117 118 119 120 121 122 123 124
			/* set bit if key press has been detected */
			for (k = 0; k < keyin_nr; k++) {
				if (tmp & (1 << k))
					__set_bit(n + k, keys);
			}

			/* keep track of which KEYIN bits that have been set */
			keyin_set |= tmp ^ ((1 << keyin_nr) - 1);
M
Magnus Damm 已提交
125 126
		}

127
		sh_keysc_level_mode(priv, keyin_set);
128

129 130 131
		bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS);
		bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS);
		bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS);
M
Magnus Damm 已提交
132

133
		sh_keysc_map_dbg(&pdev->dev, keys, "keys");
M
Magnus Damm 已提交
134

135
	} while (sh_keysc_read(priv, KYCR2) & 0x01);
M
Magnus Damm 已提交
136

137 138 139
	sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys");
	sh_keysc_map_dbg(&pdev->dev, keys0, "keys0");
	sh_keysc_map_dbg(&pdev->dev, keys1, "keys1");
M
Magnus Damm 已提交
140 141 142 143 144 145

	for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
		k = pdata->keycodes[i];
		if (!k)
			continue;

146
		if (test_bit(i, keys0) == test_bit(i, priv->last_keys))
M
Magnus Damm 已提交
147 148
			continue;

149
		if (test_bit(i, keys1) || test_bit(i, keys0)) {
M
Magnus Damm 已提交
150
			input_event(priv->input, EV_KEY, k, 1);
151
			__set_bit(i, priv->last_keys);
M
Magnus Damm 已提交
152 153
		}

154
		if (!test_bit(i, keys1)) {
M
Magnus Damm 已提交
155
			input_event(priv->input, EV_KEY, k, 0);
156
			__clear_bit(i, priv->last_keys);
M
Magnus Damm 已提交
157 158 159 160 161 162 163 164 165 166 167 168 169 170
		}

	}
	input_sync(priv->input);

	return IRQ_HANDLED;
}

static int __devinit sh_keysc_probe(struct platform_device *pdev)
{
	struct sh_keysc_priv *priv;
	struct sh_keysc_info *pdata;
	struct resource *res;
	struct input_dev *input;
171
	int i;
M
Magnus Damm 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	int irq, error;

	if (!pdev->dev.platform_data) {
		dev_err(&pdev->dev, "no platform data defined\n");
		error = -EINVAL;
		goto err0;
	}

	error = -ENXIO;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		dev_err(&pdev->dev, "failed to get I/O memory\n");
		goto err0;
	}

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(&pdev->dev, "failed to get irq\n");
		goto err0;
	}

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (priv == NULL) {
		dev_err(&pdev->dev, "failed to allocate driver data\n");
		error = -ENOMEM;
		goto err0;
	}

	platform_set_drvdata(pdev, priv);
	memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
	pdata = &priv->pdata;

204
	priv->iomem_base = ioremap_nocache(res->start, resource_size(res));
M
Magnus Damm 已提交
205 206 207
	if (priv->iomem_base == NULL) {
		dev_err(&pdev->dev, "failed to remap I/O memory\n");
		error = -ENXIO;
208
		goto err1;
M
Magnus Damm 已提交
209 210 211 212 213 214
	}

	priv->input = input_allocate_device();
	if (!priv->input) {
		dev_err(&pdev->dev, "failed to allocate input device\n");
		error = -ENOMEM;
215
		goto err2;
M
Magnus Damm 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229
	}

	input = priv->input;
	input->evbit[0] = BIT_MASK(EV_KEY);

	input->name = pdev->name;
	input->phys = "sh-keysc-keys/input0";
	input->dev.parent = &pdev->dev;

	input->id.bustype = BUS_HOST;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;

230 231 232 233
	input->keycode = pdata->keycodes;
	input->keycodesize = sizeof(pdata->keycodes[0]);
	input->keycodemax = ARRAY_SIZE(pdata->keycodes);

234 235
	error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT,
				     dev_name(&pdev->dev), pdev);
M
Magnus Damm 已提交
236 237
	if (error) {
		dev_err(&pdev->dev, "failed to request IRQ\n");
238
		goto err3;
M
Magnus Damm 已提交
239 240
	}

241 242 243
	for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
		__set_bit(pdata->keycodes[i], input->keybit);
	__clear_bit(KEY_RESERVED, input->keybit);
M
Magnus Damm 已提交
244 245 246 247

	error = input_register_device(input);
	if (error) {
		dev_err(&pdev->dev, "failed to register input device\n");
248
		goto err4;
M
Magnus Damm 已提交
249 250
	}

251 252
	pm_runtime_enable(&pdev->dev);
	pm_runtime_get_sync(&pdev->dev);
253

254 255 256
	sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
		       pdata->scan_timing);
	sh_keysc_level_mode(priv, 0);
257 258

	device_init_wakeup(&pdev->dev, 1);
259

M
Magnus Damm 已提交
260
	return 0;
261

262
 err4:
263
	free_irq(irq, pdev);
264
 err3:
265
	input_free_device(input);
M
Magnus Damm 已提交
266
 err2:
267
	iounmap(priv->iomem_base);
M
Magnus Damm 已提交
268 269 270 271 272 273 274 275 276 277 278
 err1:
	platform_set_drvdata(pdev, NULL);
	kfree(priv);
 err0:
	return error;
}

static int __devexit sh_keysc_remove(struct platform_device *pdev)
{
	struct sh_keysc_priv *priv = platform_get_drvdata(pdev);

279
	sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
M
Magnus Damm 已提交
280 281 282 283 284

	input_unregister_device(priv->input);
	free_irq(platform_get_irq(pdev, 0), pdev);
	iounmap(priv->iomem_base);

285 286
	pm_runtime_put_sync(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
287

M
Magnus Damm 已提交
288 289
	platform_set_drvdata(pdev, NULL);
	kfree(priv);
290

M
Magnus Damm 已提交
291 292 293
	return 0;
}

294
#if CONFIG_PM_SLEEP
295 296
static int sh_keysc_suspend(struct device *dev)
{
297 298
	struct platform_device *pdev = to_platform_device(dev);
	struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
299
	int irq = platform_get_irq(pdev, 0);
300 301
	unsigned short value;

302
	value = sh_keysc_read(priv, KYCR1);
M
Magnus Damm 已提交
303

304
	if (device_may_wakeup(dev)) {
305
		sh_keysc_write(priv, KYCR1, value | 0x80);
306
		enable_irq_wake(irq);
307
	} else {
308 309
		sh_keysc_write(priv, KYCR1, value & ~0x80);
		pm_runtime_put_sync(dev);
310
	}
311 312 313 314

	return 0;
}

315 316 317 318 319 320 321
static int sh_keysc_resume(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	int irq = platform_get_irq(pdev, 0);

	if (device_may_wakeup(dev))
		disable_irq_wake(irq);
322 323
	else
		pm_runtime_get_sync(dev);
324 325 326

	return 0;
}
327
#endif
328

329 330
static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
			 sh_keysc_suspend, sh_keysc_resume);
M
Magnus Damm 已提交
331

332
static struct platform_driver sh_keysc_device_driver = {
M
Magnus Damm 已提交
333 334 335 336
	.probe		= sh_keysc_probe,
	.remove		= __devexit_p(sh_keysc_remove),
	.driver		= {
		.name	= "sh_keysc",
337
		.pm	= &sh_keysc_dev_pm_ops,
M
Magnus Damm 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	}
};

static int __init sh_keysc_init(void)
{
	return platform_driver_register(&sh_keysc_device_driver);
}

static void __exit sh_keysc_exit(void)
{
	platform_driver_unregister(&sh_keysc_device_driver);
}

module_init(sh_keysc_init);
module_exit(sh_keysc_exit);

MODULE_AUTHOR("Magnus Damm");
MODULE_DESCRIPTION("SuperH KEYSC Keypad Driver");
MODULE_LICENSE("GPL");