sh_keysc.c 8.4 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/clk.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 },
35
	[SH_KEYSC_MODE_6] = { 5, 7, 7 },
M
Magnus Damm 已提交
36 37 38 39
};

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

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 76
#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);
}

77 78 79 80 81 82 83 84 85
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 已提交
86 87 88 89 90
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;
91 92 93 94 95
	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 已提交
96
	unsigned char keyin_set, tmp;
97
	int i, k, n;
M
Magnus Damm 已提交
98 99 100

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

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

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

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

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

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

118 119 120 121 122 123 124 125
			/* 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 已提交
126 127
		}

128
		sh_keysc_level_mode(priv, keyin_set);
129

130 131 132
		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 已提交
133

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

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

138 139 140
	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 已提交
141 142 143 144 145 146

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

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

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

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

	}
	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;
172
	char clk_name[8];
173
	int i;
M
Magnus Damm 已提交
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 204 205
	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;

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

213 214 215 216 217 218 219 220
	snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
	priv->clk = clk_get(&pdev->dev, clk_name);
	if (IS_ERR(priv->clk)) {
		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
		error = PTR_ERR(priv->clk);
		goto err2;
	}

M
Magnus Damm 已提交
221 222 223 224
	priv->input = input_allocate_device();
	if (!priv->input) {
		dev_err(&pdev->dev, "failed to allocate input device\n");
		error = -ENOMEM;
225
		goto err3;
M
Magnus Damm 已提交
226 227 228 229 230 231 232 233 234 235 236 237 238 239
	}

	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;

240 241 242 243
	input->keycode = pdata->keycodes;
	input->keycodesize = sizeof(pdata->keycodes[0]);
	input->keycodemax = ARRAY_SIZE(pdata->keycodes);

M
Magnus Damm 已提交
244 245 246
	error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
	if (error) {
		dev_err(&pdev->dev, "failed to request IRQ\n");
247
		goto err4;
M
Magnus Damm 已提交
248 249
	}

250 251 252
	for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
		__set_bit(pdata->keycodes[i], input->keybit);
	__clear_bit(KEY_RESERVED, input->keybit);
M
Magnus Damm 已提交
253 254 255 256

	error = input_register_device(input);
	if (error) {
		dev_err(&pdev->dev, "failed to register input device\n");
257
		goto err5;
M
Magnus Damm 已提交
258 259
	}

260 261
	clk_enable(priv->clk);

262 263 264
	sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
		       pdata->scan_timing);
	sh_keysc_level_mode(priv, 0);
265 266

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

M
Magnus Damm 已提交
268
	return 0;
269

270
 err5:
271
	free_irq(irq, pdev);
272
 err4:
273
	input_free_device(input);
274 275
 err3:
	clk_put(priv->clk);
M
Magnus Damm 已提交
276
 err2:
277
	iounmap(priv->iomem_base);
M
Magnus Damm 已提交
278 279 280 281 282 283 284 285 286 287 288
 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);

289
	sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
M
Magnus Damm 已提交
290 291 292 293 294

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

295 296 297
	clk_disable(priv->clk);
	clk_put(priv->clk);

M
Magnus Damm 已提交
298 299
	platform_set_drvdata(pdev, NULL);
	kfree(priv);
300

M
Magnus Damm 已提交
301 302 303
	return 0;
}

304 305
static int sh_keysc_suspend(struct device *dev)
{
306 307
	struct platform_device *pdev = to_platform_device(dev);
	struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
308
	int irq = platform_get_irq(pdev, 0);
309 310
	unsigned short value;

311
	value = sh_keysc_read(priv, KYCR1);
M
Magnus Damm 已提交
312

313
	if (device_may_wakeup(dev)) {
314
		value |= 0x80;
315
		enable_irq_wake(irq);
316
	} else {
317
		value &= ~0x80;
318
	}
319

320
	sh_keysc_write(priv, KYCR1, value);
321

322 323 324
	return 0;
}

325 326 327 328 329 330 331 332 333 334 335
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);

	return 0;
}

336
static const struct dev_pm_ops sh_keysc_dev_pm_ops = {
337
	.suspend = sh_keysc_suspend,
338
	.resume = sh_keysc_resume,
339
};
M
Magnus Damm 已提交
340 341 342 343 344 345

struct platform_driver sh_keysc_device_driver = {
	.probe		= sh_keysc_probe,
	.remove		= __devexit_p(sh_keysc_remove),
	.driver		= {
		.name	= "sh_keysc",
346
		.pm	= &sh_keysc_dev_pm_ops,
M
Magnus Damm 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	}
};

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