Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * Driver for the enhanced rotary controller on pxa930 and pxa935
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License version 2 as
  6 * published by the Free Software Foundation.
  7 */
  8
  9#include <linux/kernel.h>
 10#include <linux/module.h>
 11#include <linux/init.h>
 12#include <linux/interrupt.h>
 13#include <linux/input.h>
 14#include <linux/platform_device.h>
 15#include <linux/io.h>
 16#include <linux/slab.h>
 17
 18#include <mach/pxa930_rotary.h>
 19
 20#define SBCR	(0x04)
 21#define ERCR	(0x0c)
 22
 23#define SBCR_ERSB	(1 << 5)
 24
 25struct pxa930_rotary {
 26	struct input_dev	*input_dev;
 27	void __iomem		*mmio_base;
 28	int			last_ercr;
 29
 30	struct pxa930_rotary_platform_data *pdata;
 31};
 32
 33static void clear_sbcr(struct pxa930_rotary *r)
 34{
 35	uint32_t sbcr = __raw_readl(r->mmio_base + SBCR);
 36
 37	__raw_writel(sbcr | SBCR_ERSB, r->mmio_base + SBCR);
 38	__raw_writel(sbcr & ~SBCR_ERSB, r->mmio_base + SBCR);
 39}
 40
 41static irqreturn_t rotary_irq(int irq, void *dev_id)
 42{
 43	struct pxa930_rotary *r = dev_id;
 44	struct pxa930_rotary_platform_data *pdata = r->pdata;
 45	int ercr, delta, key;
 46
 47	ercr = __raw_readl(r->mmio_base + ERCR) & 0xf;
 48	clear_sbcr(r);
 49
 50	delta = ercr - r->last_ercr;
 51	if (delta == 0)
 52		return IRQ_HANDLED;
 53
 54	r->last_ercr = ercr;
 55
 56	if (pdata->up_key && pdata->down_key) {
 57		key = (delta > 0) ? pdata->up_key : pdata->down_key;
 58		input_report_key(r->input_dev, key, 1);
 59		input_sync(r->input_dev);
 60		input_report_key(r->input_dev, key, 0);
 61	} else
 62		input_report_rel(r->input_dev, pdata->rel_code, delta);
 63
 64	input_sync(r->input_dev);
 65
 66	return IRQ_HANDLED;
 67}
 68
 69static int pxa930_rotary_open(struct input_dev *dev)
 70{
 71	struct pxa930_rotary *r = input_get_drvdata(dev);
 72
 73	clear_sbcr(r);
 74
 75	return 0;
 76}
 77
 78static void pxa930_rotary_close(struct input_dev *dev)
 79{
 80	struct pxa930_rotary *r = input_get_drvdata(dev);
 81
 82	clear_sbcr(r);
 83}
 84
 85static int __devinit pxa930_rotary_probe(struct platform_device *pdev)
 86{
 87	struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data;
 
 88	struct pxa930_rotary *r;
 89	struct input_dev *input_dev;
 90	struct resource *res;
 91	int irq;
 92	int err;
 93
 94	irq = platform_get_irq(pdev, 0);
 95	if (irq < 0) {
 96		dev_err(&pdev->dev, "no irq for rotary controller\n");
 97		return -ENXIO;
 98	}
 99
100	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
101	if (!res) {
102		dev_err(&pdev->dev, "no I/O memory defined\n");
103		return -ENXIO;
104	}
105
106	if (!pdata) {
107		dev_err(&pdev->dev, "no platform data defined\n");
108		return -EINVAL;
109	}
110
111	r = kzalloc(sizeof(struct pxa930_rotary), GFP_KERNEL);
112	if (!r)
113		return -ENOMEM;
114
115	r->mmio_base = ioremap_nocache(res->start, resource_size(res));
116	if (r->mmio_base == NULL) {
117		dev_err(&pdev->dev, "failed to remap IO memory\n");
118		err = -ENXIO;
119		goto failed_free;
120	}
121
122	r->pdata = pdata;
123	platform_set_drvdata(pdev, r);
124
125	/* allocate and register the input device */
126	input_dev = input_allocate_device();
127	if (!input_dev) {
128		dev_err(&pdev->dev, "failed to allocate input device\n");
129		err = -ENOMEM;
130		goto failed_free_io;
131	}
132
133	input_dev->name = pdev->name;
134	input_dev->id.bustype = BUS_HOST;
135	input_dev->open = pxa930_rotary_open;
136	input_dev->close = pxa930_rotary_close;
137	input_dev->dev.parent = &pdev->dev;
138
139	if (pdata->up_key && pdata->down_key) {
140		__set_bit(pdata->up_key, input_dev->keybit);
141		__set_bit(pdata->down_key, input_dev->keybit);
142		__set_bit(EV_KEY, input_dev->evbit);
143	} else {
144		__set_bit(pdata->rel_code, input_dev->relbit);
145		__set_bit(EV_REL, input_dev->evbit);
146	}
147
148	r->input_dev = input_dev;
149	input_set_drvdata(input_dev, r);
150
151	err = request_irq(irq, rotary_irq, IRQF_DISABLED,
152			"enhanced rotary", r);
153	if (err) {
154		dev_err(&pdev->dev, "failed to request IRQ\n");
155		goto failed_free_input;
156	}
157
158	err = input_register_device(input_dev);
159	if (err) {
160		dev_err(&pdev->dev, "failed to register input device\n");
161		goto failed_free_irq;
162	}
163
164	return 0;
165
166failed_free_irq:
167	free_irq(irq, r);
168failed_free_input:
169	input_free_device(input_dev);
170failed_free_io:
171	iounmap(r->mmio_base);
172failed_free:
173	kfree(r);
174	return err;
175}
176
177static int __devexit pxa930_rotary_remove(struct platform_device *pdev)
178{
179	struct pxa930_rotary *r = platform_get_drvdata(pdev);
180
181	free_irq(platform_get_irq(pdev, 0), r);
182	input_unregister_device(r->input_dev);
183	iounmap(r->mmio_base);
184	platform_set_drvdata(pdev, NULL);
185	kfree(r);
186
187	return 0;
188}
189
190static struct platform_driver pxa930_rotary_driver = {
191	.driver		= {
192		.name	= "pxa930-rotary",
193		.owner	= THIS_MODULE,
194	},
195	.probe		= pxa930_rotary_probe,
196	.remove		= __devexit_p(pxa930_rotary_remove),
197};
198
199static int __init pxa930_rotary_init(void)
200{
201	return platform_driver_register(&pxa930_rotary_driver);
202}
203module_init(pxa930_rotary_init);
204
205static void __exit pxa930_rotary_exit(void)
206{
207	platform_driver_unregister(&pxa930_rotary_driver);
208}
209module_exit(pxa930_rotary_exit);
210
211MODULE_LICENSE("GPL");
212MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
213MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Driver for the enhanced rotary controller on pxa930 and pxa935
 
 
 
 
  4 */
  5
  6#include <linux/kernel.h>
  7#include <linux/module.h>
 
  8#include <linux/interrupt.h>
  9#include <linux/input.h>
 10#include <linux/platform_device.h>
 11#include <linux/io.h>
 12#include <linux/slab.h>
 13
 14#include <linux/platform_data/keyboard-pxa930_rotary.h>
 15
 16#define SBCR	(0x04)
 17#define ERCR	(0x0c)
 18
 19#define SBCR_ERSB	(1 << 5)
 20
 21struct pxa930_rotary {
 22	struct input_dev	*input_dev;
 23	void __iomem		*mmio_base;
 24	int			last_ercr;
 25
 26	struct pxa930_rotary_platform_data *pdata;
 27};
 28
 29static void clear_sbcr(struct pxa930_rotary *r)
 30{
 31	uint32_t sbcr = __raw_readl(r->mmio_base + SBCR);
 32
 33	__raw_writel(sbcr | SBCR_ERSB, r->mmio_base + SBCR);
 34	__raw_writel(sbcr & ~SBCR_ERSB, r->mmio_base + SBCR);
 35}
 36
 37static irqreturn_t rotary_irq(int irq, void *dev_id)
 38{
 39	struct pxa930_rotary *r = dev_id;
 40	struct pxa930_rotary_platform_data *pdata = r->pdata;
 41	int ercr, delta, key;
 42
 43	ercr = __raw_readl(r->mmio_base + ERCR) & 0xf;
 44	clear_sbcr(r);
 45
 46	delta = ercr - r->last_ercr;
 47	if (delta == 0)
 48		return IRQ_HANDLED;
 49
 50	r->last_ercr = ercr;
 51
 52	if (pdata->up_key && pdata->down_key) {
 53		key = (delta > 0) ? pdata->up_key : pdata->down_key;
 54		input_report_key(r->input_dev, key, 1);
 55		input_sync(r->input_dev);
 56		input_report_key(r->input_dev, key, 0);
 57	} else
 58		input_report_rel(r->input_dev, pdata->rel_code, delta);
 59
 60	input_sync(r->input_dev);
 61
 62	return IRQ_HANDLED;
 63}
 64
 65static int pxa930_rotary_open(struct input_dev *dev)
 66{
 67	struct pxa930_rotary *r = input_get_drvdata(dev);
 68
 69	clear_sbcr(r);
 70
 71	return 0;
 72}
 73
 74static void pxa930_rotary_close(struct input_dev *dev)
 75{
 76	struct pxa930_rotary *r = input_get_drvdata(dev);
 77
 78	clear_sbcr(r);
 79}
 80
 81static int pxa930_rotary_probe(struct platform_device *pdev)
 82{
 83	struct pxa930_rotary_platform_data *pdata =
 84			dev_get_platdata(&pdev->dev);
 85	struct pxa930_rotary *r;
 86	struct input_dev *input_dev;
 87	struct resource *res;
 88	int irq;
 89	int err;
 90
 91	irq = platform_get_irq(pdev, 0);
 92	if (irq < 0)
 
 93		return -ENXIO;
 
 94
 95	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 96	if (!res) {
 97		dev_err(&pdev->dev, "no I/O memory defined\n");
 98		return -ENXIO;
 99	}
100
101	if (!pdata) {
102		dev_err(&pdev->dev, "no platform data defined\n");
103		return -EINVAL;
104	}
105
106	r = kzalloc(sizeof(struct pxa930_rotary), GFP_KERNEL);
107	if (!r)
108		return -ENOMEM;
109
110	r->mmio_base = ioremap(res->start, resource_size(res));
111	if (r->mmio_base == NULL) {
112		dev_err(&pdev->dev, "failed to remap IO memory\n");
113		err = -ENXIO;
114		goto failed_free;
115	}
116
117	r->pdata = pdata;
118	platform_set_drvdata(pdev, r);
119
120	/* allocate and register the input device */
121	input_dev = input_allocate_device();
122	if (!input_dev) {
123		dev_err(&pdev->dev, "failed to allocate input device\n");
124		err = -ENOMEM;
125		goto failed_free_io;
126	}
127
128	input_dev->name = pdev->name;
129	input_dev->id.bustype = BUS_HOST;
130	input_dev->open = pxa930_rotary_open;
131	input_dev->close = pxa930_rotary_close;
132	input_dev->dev.parent = &pdev->dev;
133
134	if (pdata->up_key && pdata->down_key) {
135		__set_bit(pdata->up_key, input_dev->keybit);
136		__set_bit(pdata->down_key, input_dev->keybit);
137		__set_bit(EV_KEY, input_dev->evbit);
138	} else {
139		__set_bit(pdata->rel_code, input_dev->relbit);
140		__set_bit(EV_REL, input_dev->evbit);
141	}
142
143	r->input_dev = input_dev;
144	input_set_drvdata(input_dev, r);
145
146	err = request_irq(irq, rotary_irq, 0,
147			"enhanced rotary", r);
148	if (err) {
149		dev_err(&pdev->dev, "failed to request IRQ\n");
150		goto failed_free_input;
151	}
152
153	err = input_register_device(input_dev);
154	if (err) {
155		dev_err(&pdev->dev, "failed to register input device\n");
156		goto failed_free_irq;
157	}
158
159	return 0;
160
161failed_free_irq:
162	free_irq(irq, r);
163failed_free_input:
164	input_free_device(input_dev);
165failed_free_io:
166	iounmap(r->mmio_base);
167failed_free:
168	kfree(r);
169	return err;
170}
171
172static int pxa930_rotary_remove(struct platform_device *pdev)
173{
174	struct pxa930_rotary *r = platform_get_drvdata(pdev);
175
176	free_irq(platform_get_irq(pdev, 0), r);
177	input_unregister_device(r->input_dev);
178	iounmap(r->mmio_base);
 
179	kfree(r);
180
181	return 0;
182}
183
184static struct platform_driver pxa930_rotary_driver = {
185	.driver		= {
186		.name	= "pxa930-rotary",
 
187	},
188	.probe		= pxa930_rotary_probe,
189	.remove		= pxa930_rotary_remove,
190};
191module_platform_driver(pxa930_rotary_driver);
 
 
 
 
 
 
 
 
 
 
 
192
193MODULE_LICENSE("GPL");
194MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
195MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");