* [PATCH v1 00/49] USB: prepare for enabling irq in complete()
From: Ming Lei @ 2013-08-17 16:24 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Oliver Neukum, Alan Stern, linux-input,
linux-bluetooth, netdev, linux-wireless, linux-media, alsa-devel
Hi,
As we are going to run URB->complete() in tasklet context[1][2], and
hard interrupt may be enabled when running URB completion handler[3],
so we might need to disable interrupt when acquiring one lock in
the completion handler for the below reasons:
- URB->complete() holds a subsystem wide lock which may be acquired
in another hard irq context, and the subsystem wide lock is acquired
by spin_lock()/read_lock()/write_lock() in complete()
- URB->complete() holds a private lock with spin_lock()/read_lock()/write_lock()
but driver may export APIs to make other drivers acquire the same private
lock in its interrupt handler.
For the sake of safety and making the change simple, this patch set
converts all spin_lock()/read_lock()/write_lock() in completion handler
path into their irqsave version mechanically.
But if you are sure the above two cases do not happen in your driver,
please let me know and I can drop the unnecessary change.
Also if you find some conversions are missed, also please let me know so
that I can add it in the next round.
[1], USB: URB documentation: claim complete() will be run with IRQs enabled
https://git.kernel.org/cgit/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=85721d45261c4be684730c7509a59daa6cda30d8
[2], USB: HCD: support giveback of URB in tasklet context
https://git.kernel.org/cgit/linux/kernel/git/gregkh/usb.git/commit/?h=usb-next&id=94dfd7edfd5c9b605caf7b562de7a813d216e011
[3], http://marc.info/?l=linux-usb&m=137286330626363&w=2
V1:
- rename patchset title
- add missed changes on 'usb_skeleon and usb sg lib'
- remove several sound usb drivers which have been done via sound tree
- some patch style fix
- replace snd_pcm_stream_lock with snd_pcm_stream_lock_irqsave for related
a/v drivers
Cc: linux-input@vger.kernel.org
Cc: linux-bluetooth@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-wireless@vger.kernel.org
Cc: linux-media@vger.kernel.org
Cc: alsa-devel@alsa-project.org
drivers/bluetooth/bfusb.c | 12 ++++----
drivers/bluetooth/btusb.c | 5 ++--
drivers/hid/usbhid/hid-core.c | 5 ++--
drivers/input/misc/cm109.c | 10 ++++---
drivers/isdn/hardware/mISDN/hfcsusb.c | 36 ++++++++++++-----------
drivers/media/dvb-core/dvb_demux.c | 17 +++++++----
drivers/media/usb/cx231xx/cx231xx-audio.c | 10 ++++---
drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++---
drivers/media/usb/cx231xx/cx231xx-vbi.c | 5 ++--
drivers/media/usb/em28xx/em28xx-audio.c | 5 ++--
drivers/media/usb/em28xx/em28xx-core.c | 5 ++--
drivers/media/usb/sn9c102/sn9c102_core.c | 7 +++--
drivers/media/usb/tlg2300/pd-alsa.c | 5 ++--
drivers/media/usb/tlg2300/pd-video.c | 5 ++--
drivers/media/usb/tm6000/tm6000-video.c | 5 ++--
drivers/net/usb/cdc-phonet.c | 5 ++--
drivers/net/usb/hso.c | 38 ++++++++++++++-----------
drivers/net/usb/kaweth.c | 7 +++--
drivers/net/usb/rtl8150.c | 5 ++--
drivers/net/wireless/ath/ath9k/hif_usb.c | 29 ++++++++++---------
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 9 +++---
drivers/net/wireless/ath/ath9k/wmi.c | 11 +++----
drivers/net/wireless/ath/carl9170/rx.c | 5 ++--
drivers/net/wireless/libertas/if_usb.c | 5 ++--
drivers/net/wireless/libertas_tf/if_usb.c | 6 ++--
drivers/net/wireless/zd1211rw/zd_usb.c | 21 ++++++++------
drivers/staging/bcm/InterfaceRx.c | 5 ++--
drivers/staging/btmtk_usb/btmtk_usb.c | 5 ++--
drivers/staging/ced1401/usb1401.c | 35 ++++++++++++-----------
drivers/staging/vt6656/usbpipe.c | 9 +++---
drivers/usb/class/cdc-wdm.c | 16 +++++++----
drivers/usb/class/usblp.c | 10 ++++---
drivers/usb/core/devio.c | 5 ++--
drivers/usb/core/message.c | 5 ++--
drivers/usb/misc/adutux.c | 10 ++++---
drivers/usb/misc/iowarrior.c | 5 ++--
drivers/usb/misc/ldusb.c | 7 +++--
drivers/usb/misc/legousbtower.c | 6 ++--
drivers/usb/misc/usbtest.c | 10 ++++---
drivers/usb/misc/uss720.c | 7 ++++-
drivers/usb/serial/cyberjack.c | 15 ++++++----
drivers/usb/serial/digi_acceleport.c | 23 ++++++++-------
drivers/usb/serial/io_edgeport.c | 14 +++++----
drivers/usb/serial/io_ti.c | 5 ++--
drivers/usb/serial/mos7720.c | 5 ++--
drivers/usb/serial/mos7840.c | 5 ++--
drivers/usb/serial/quatech2.c | 5 ++--
drivers/usb/serial/sierra.c | 9 +++---
drivers/usb/serial/symbolserial.c | 5 ++--
drivers/usb/serial/ti_usb_3410_5052.c | 9 +++---
drivers/usb/serial/usb_wwan.c | 5 ++--
drivers/usb/usb-skeleton.c | 11 ++++---
sound/usb/caiaq/audio.c | 5 ++--
sound/usb/midi.c | 5 ++--
54 files changed, 318 insertions(+), 221 deletions(-)
Thanks,
--
Ming Lei
^ permalink raw reply
* Re: [PATCH v3 RESEND 3/3] input: mc13783: Add DT probe support
From: Tomasz Figa @ 2013-08-17 11:52 UTC (permalink / raw)
To: Alexander Shiyan
Cc: linux-input, Dmitry Torokhov, Sascha Hauer, devicetree,
Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
Ian Campbell, Grant Likely
In-Reply-To: <1376718340-16885-1-git-send-email-shc_work@mail.ru>
Hi Alexander,
Please see my comments inline.
On Saturday 17 of August 2013 09:45:40 Alexander Shiyan wrote:
> Patch adds DT support for MC13783/MC13892 PMICs.
>
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
> ---
> Documentation/devicetree/bindings/mfd/mc13xxx.txt | 13 +++++
> drivers/input/misc/mc13783-pwrbutton.c | 61
> +++++++++++++++++------ 2 files changed, 60 insertions(+), 14
> deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt
> b/Documentation/devicetree/bindings/mfd/mc13xxx.txt index
> abd9e3c..cf8b61c 100644
> --- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt
> +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
> @@ -10,6 +10,12 @@ Optional properties:
> - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being
> used
>
> Sub-nodes:
> +- buttons : Contain power button nodes. Each button should be declared
> as + "button@<num>" and contain code in "linux,code" property.
You should not really be enforcing such strict node naming. If you have
the "buttons" node, which aggregates all the buttons, all you need is just
parsing all the child nodes of it, regardless of their names.
As a side note, the @unit-address suffix is used only when you have the
reg property present in the node and must be equal to the address value
set in this property.
If you need the button index (which is true, looking at the code), you
should use the reg property instead, with appropriate #address-cells
(probably 1 for your use case) and #size-cells (0, as size doesn't make
sense in your use case) in "buttons" node.
> + Optional properties:
The properties below should be rather prefixed with "fsl," string to
indicate that they are specific to this particular device.
> + active-high : Change active button level from 0 to 1.
It is a boolean property, isn't it? If yes, this should be noted. Also the
"from 0 to 1" statement is a bit unfortunate.
What about:
active-high : A boolean property present if the button is active
high. Otherwise the button is assumed to be active low.
> + enable-reset: Performs hadware reset through PMIC.
Could you elaborate on meaning of this property a bit more, please?
> + debounce : Debounce value which will be taken from PMIC
> datasheet. - regulators : Contain the regulator nodes. The regulators
> are bound using their names as listed below with their registers and
> bits for enabling.
>
> @@ -89,6 +95,13 @@ ecspi@70010000 { /* ECSPI1 */
> interrupt-parent = <&gpio0>;
> interrupts = <8>;
>
> + buttons {
> + button@1 {
> + linux,code = <0x1f>;
> + debounce = <1>;
> + };
> + };
> +
So basically this example after addressing my comments would look like:
buttons {
#address-cells = <1>;
#size-cells = <0>;
irrelevant-name@1 {
reg = <1>;
linux,code = <0x1f>;
fsl,debounce = <1>;
};
};
> regulators {
> sw1_reg: mc13892__sw1 {
> regulator-min-microvolt = <600000>;
> diff --git a/drivers/input/misc/mc13783-pwrbutton.c
> b/drivers/input/misc/mc13783-pwrbutton.c index 2e21f19..3f9cfd1 100644
> --- a/drivers/input/misc/mc13783-pwrbutton.c
> +++ b/drivers/input/misc/mc13783-pwrbutton.c
> @@ -24,6 +24,7 @@
> #include <linux/kernel.h>
> #include <linux/errno.h>
> #include <linux/input.h>
> +#include <linux/of.h>
> #include <linux/platform_device.h>
> #include <linux/mfd/mc13783.h>
> #include <linux/mfd/mc13892.h>
> @@ -77,21 +78,28 @@ static int __init mc13xxx_pwrbutton_probe(struct
> platform_device *pdev) struct mc13xxx *mc13xxx =
> dev_get_drvdata(pdev->dev.parent); struct mc13xxx_pwrb_devtype *devtype
> =
> (struct mc13xxx_pwrb_devtype *)pdev->id_entry-
>driver_data;
> + struct device_node *parent, *child;
> struct mc13xxx_pwrb *priv;
> int i, reg = 0, ret = -EINVAL;
>
> - if (!pdata) {
> + of_node_get(pdev->dev.parent->of_node);
> + parent = of_find_node_by_name(pdev->dev.parent->of_node,
"buttons");
The of_find_node_by_name() function does not search for node with given
name inside the node you specify, but rather starting from this node and
going over all the rest of device tree.
of_get_child_by_name() seems to be what you need here.
> + if (!pdata && !parent) {
> dev_err(&pdev->dev, "Missing platform data\n");
> return -ENODEV;
> }
>
> priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> - if (!priv)
> - return -ENOMEM;
> + if (!priv) {
> + ret = -ENOMEM;
> + goto out_node_put;
> + }
>
> priv->input = devm_input_allocate_device(&pdev->dev);
> - if (!priv->input)
> - return -ENOMEM;
> + if (!priv->input) {
> + ret = -ENOMEM;
> + goto out_node_put;
> + }
>
> priv->mc13xxx = mc13xxx;
> priv->devtype = devtype;
> @@ -99,15 +107,36 @@ static int __init mc13xxx_pwrbutton_probe(struct
> platform_device *pdev)
>
> for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
> u16 code, invert, reset, debounce;
> -
> - if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
> - continue;
> - code = pdata->buttons[i].keycode;
> - invert = !!(pdata->buttons[i].flags &
> - MC13XXX_BUTTON_POL_INVERT);
> - reset = !!(pdata->buttons[i].flags &
> - MC13XXX_BUTTON_RESET_EN);
> - debounce = pdata->buttons[i].flags;
> + const __be32 *prop;
> + char childname[5];
> +
> + if (parent) {
> + sprintf(childname, "button@%i", i + 1);
Hmm, this can lead to stack corruption. The line above will print 9
(including terminating zero) characters to the childname array, which can
hold only 5 of them.
> + child = of_get_child_by_name(parent, childname);
> + if (!child)
> + continue;
> + prop = of_get_property(child, "linux,code", NULL);
> + if (prop)
> + code = be32_to_cpu(*prop) & 0xffff;
What about using of_property_read_u32() here? See include/linux/of.h for a
whole lot of useful DT parsing functions and their descriptions in
drivers/of/base.c (kernel-doc comments).
> + else {
> + dev_err(&pdev->dev,
> + "Button %i: Missing key code\n", i
+ 1);
> + continue;
> + }
> + invert = of_property_read_bool(child, "active-
high");
> + reset = of_property_read_bool(child, "enable-
reset");
> + prop = of_get_property(child, "debounce", NULL);
> + debounce = prop ? be32_to_cpu(*prop) : 0;
Again, of_property_read_u32() would simplify the code. As a side note,
there is also a be32_to_cpup() helper, which dereferences a __be32 pointer
for you and returns a value in CPU endianess.
> + } else {
> + if (!(pdata->buttons[i].flags &
MC13XXX_BUTTON_ENABLE))
> + continue;
> + code = pdata->buttons[i].keycode;
> + invert = !!(pdata->buttons[i].flags &
> + MC13XXX_BUTTON_POL_INVERT);
> + reset = !!(pdata->buttons[i].flags &
> + MC13XXX_BUTTON_RESET_EN);
> + debounce = pdata->buttons[i].flags;
> + }
Anyway, based on my comments wrt the bindings, I would rather separate the
DT parsing code from this loop and, in DT case, parse the buttons in a
for_each_child_of_node() loop, reading the reg property and using it as an
index to the buttons array (after checking if the index isn't out of
bounds, of course).
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v3 RESEND 1/3] input: mc13783: Prepare driver to support MC13892 and OF
From: Sascha Hauer @ 2013-08-17 9:23 UTC (permalink / raw)
To: Alexander Shiyan
Cc: Michael Grzeschik, linux-input, Dmitry Torokhov, Sascha Hauer
In-Reply-To: <20130817105305.5201c078d4f2cf52ffb172f8@mail.ru>
On Sat, Aug 17, 2013 at 10:53:05AM +0400, Alexander Shiyan wrote:
> On Sat, 17 Aug 2013 08:20:12 +0200
> Michael Grzeschik <mgr@pengutronix.de> wrote:
>
> > On Sat, Aug 17, 2013 at 09:46:20AM +0400, Alexander Shiyan wrote:
> > > This patch is a preparation mc13xxx powerbutton driver to support
> > > MC13892 and support the probe through the DT.
> >
> > As this patch already mention by itself, it's doing to much at once.
> > And by looking at it, it realy does more than it tells here.
> >
> > Can you rework that into seperate readable tasks. In this patch you
> > nearly rewrite the whole file. That runs the review impossible.
>
> All changes in this patch are addicted to each other, can not be divided.
I find this hard to believe. Here are some changes that can be separated
easily:
- Rename defines from MC13XXX_BUTTON_ to MC13783_BUTTON_
- convert module_platform_driver to module_platform_driver_probe, why do
you change this anyway?
- convert from kzalloc to devm_kzalloc
- rewrite error message from "missing platform data" to "Missing
platform data"
Drop these changes or make them separate patches and your original patch
would be smaller already.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Zubair Lutfullah : @ 2013-08-17 8:58 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Zubair Lutfullah, jic23-KWPb1pKIrIJaa/9Udqfwiw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
bigeasy-hfZtesqFncYOwBW4kG4KsQ,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, Russ.Dill-l0cyMroinI0
In-Reply-To: <520CBEC6.8010400-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On Thu, Aug 15, 2013 at 12:43:02PM +0100, Jonathan Cameron wrote:
> Note I'd also like a much more detailed description in the patch header.
>
> I would also expect an option for the trigger to be supplied from the
> chip itself based on fifo watershead interrupts. Thus the adc could be
> operated at full rate without losing data. As you described in a previous
> email this is much more similar to a one shot osciloscope trigger where it
> grabs the next set of readings. Now this is an interesting option, but
> it isn't the standard one for IIO. I'd be interested to see a proposal
> for adding this functionality to the core in a more general fashion.
When I read trigger, this functionality is what comes to my mind.
Not the single scan current implementation in IIO. My background I guess.
Adding this feature to the core feels a bit above my level at the moment.
I'd like to get this driver sorted first.
>
> For now I'd be much happier if this driver conformed to more or less the
> standard form with the one exception being that the 'trigger' is based on
> the fifo threshold and so it might appear to grab multiple scans of the
> enabled channels for each trigger (which is fine). Even if we provide the
> functionality sketched out above, it would still be as core functionality, not
> in the driver as you have done here.
>
> Jonathan
Will that affect the way generic_buffer.c will read from the driver?
Rest comments below.
> > diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
> > + /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */
> > + if (status & IRQENB_FIFO1OVRRUN) {
> > + config = tiadc_readl(adc_dev, REG_CTRL);
> > + config &= ~(CNTRLREG_TSCSSENB);
> > + tiadc_writel(adc_dev, REG_CTRL, config);
> > + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN |
> > + IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
> > + tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
> > + } else if (status & IRQENB_FIFO1THRES) {
>
> I'd normally expect this interrupt to drive a trigger that in turn results in
> the data being dumped into the software buffers.
>
The work handler is sort of providing similar functionality..
But, I guess using the trigger ABI is more efficient.
> > +
> > + tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES |
> > + IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
> > + tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES
> > + | IRQENB_FIFO1OVRRUN);
> > +
> > + iio_trigger_notify_done(indio_dev->trig);
> Are you actually done? What happens if another trigger turns up in the
> meantime? I'd expect this to occur only after the results of the trigger
> have been handled.
Indeed Done is passed immediately while ADC is still sampling.
Because of the way the trigger was used and structure of the driver.
> > +static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
> > +{
> Don't have pointless wrappers like this.
Noted
> > + return iio_sw_buffer_preenable(indio_dev);
> > +}
> > +
> > +static void tiadc_adc_work(struct work_struct *work_s)
> > +{
> > + struct tiadc_device *adc_dev =
> > + container_of(work_s, struct tiadc_device, poll_work);
> > + struct iio_dev *indio_dev = iio_priv_to_dev(adc_dev);
> > + struct iio_buffer *buffer = indio_dev->buffer;
> > + int i, j, k, fifo1count, read;
> > + unsigned int config;
> So normally we'd just fill with one sample hence for this case
> I'd expect to push out whatever samples are in the fifo right now
> then return. The next trigger would grab the next lot etc.
>
Again. If I understand correctly,
I restructure the driver so that
enabling the buffer via userspace starts sampling the ADC channels.
Preenable/postenable do all that hard work.
I need to use iio_trigger_register to create an IIO trigger inside the
driver.
The IRQ handler for FIFO Threshold causes a trigger event.
The trigger handler pushes the entire fifo to userspace.
I'd like a small ACK before I get to work.
Just to make sure I got things correctly.
Thanks for the input
Zubair
^ permalink raw reply
* Re: [PATCH v3 RESEND 1/3] input: mc13783: Prepare driver to support MC13892 and OF
From: Alexander Shiyan @ 2013-08-17 6:53 UTC (permalink / raw)
To: Michael Grzeschik; +Cc: linux-input, Dmitry Torokhov, Sascha Hauer
In-Reply-To: <20130817062012.GA26693@pengutronix.de>
On Sat, 17 Aug 2013 08:20:12 +0200
Michael Grzeschik <mgr@pengutronix.de> wrote:
> On Sat, Aug 17, 2013 at 09:46:20AM +0400, Alexander Shiyan wrote:
> > This patch is a preparation mc13xxx powerbutton driver to support
> > MC13892 and support the probe through the DT.
>
> As this patch already mention by itself, it's doing to much at once.
> And by looking at it, it realy does more than it tells here.
>
> Can you rework that into seperate readable tasks. In this patch you
> nearly rewrite the whole file. That runs the review impossible.
All changes in this patch are addicted to each other, can not be divided.
As an alternative, I can do all as a new driver.
Thanks.
--
Alexander Shiyan <shc_work@mail.ru>
^ permalink raw reply
* Re: [PATCH v3 RESEND 1/3] input: mc13783: Prepare driver to support MC13892 and OF
From: Michael Grzeschik @ 2013-08-17 6:20 UTC (permalink / raw)
To: Alexander Shiyan; +Cc: linux-input, Dmitry Torokhov, Sascha Hauer
In-Reply-To: <1376718381-16924-1-git-send-email-shc_work@mail.ru>
Hi Alexander,
On Sat, Aug 17, 2013 at 09:46:20AM +0400, Alexander Shiyan wrote:
> This patch is a preparation mc13xxx powerbutton driver to support
> MC13892 and support the probe through the DT.
As this patch already mention by itself, it's doing to much at once.
And by looking at it, it realy does more than it tells here.
Can you rework that into seperate readable tasks. In this patch you
nearly rewrite the whole file. That runs the review impossible.
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
> ---
> arch/arm/mach-imx/mach-mx31moboard.c | 9 +-
> drivers/input/misc/mc13783-pwrbutton.c | 332 +++++++++++++--------------------
> include/linux/mfd/mc13xxx.h | 28 +--
> 3 files changed, 151 insertions(+), 218 deletions(-)
>
> diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
> index 6f424ec..2a8aa43 100644
> --- a/arch/arm/mach-imx/mach-mx31moboard.c
> +++ b/arch/arm/mach-imx/mach-mx31moboard.c
> @@ -276,9 +276,12 @@ static struct mc13xxx_leds_platform_data moboard_leds = {
> };
>
> static struct mc13xxx_buttons_platform_data moboard_buttons = {
> - .b1on_flags = MC13783_BUTTON_DBNC_750MS | MC13783_BUTTON_ENABLE |
> - MC13783_BUTTON_POL_INVERT,
> - .b1on_key = KEY_POWER,
> + .buttons[0] = {
> + .keycode = KEY_POWER,
> + .flags = MC13XXX_BUTTON_ENABLE |
> + MC13XXX_BUTTON_DBNC_750MS |
> + MC13XXX_BUTTON_POL_INVERT,
> + },
> };
>
> static struct mc13xxx_codec_platform_data moboard_codec = {
> diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
> index d0277a7..aaaacef 100644
> --- a/drivers/input/misc/mc13783-pwrbutton.c
> +++ b/drivers/input/misc/mc13783-pwrbutton.c
> @@ -24,248 +24,176 @@
> #include <linux/kernel.h>
> #include <linux/errno.h>
> #include <linux/input.h>
> -#include <linux/interrupt.h>
> #include <linux/platform_device.h>
> #include <linux/mfd/mc13783.h>
> -#include <linux/sched.h>
> -#include <linux/slab.h>
> -
> -struct mc13783_pwrb {
> - struct input_dev *pwr;
> - struct mc13xxx *mc13783;
> -#define MC13783_PWRB_B1_POL_INVERT (1 << 0)
> -#define MC13783_PWRB_B2_POL_INVERT (1 << 1)
> -#define MC13783_PWRB_B3_POL_INVERT (1 << 2)
> - int flags;
> - unsigned short keymap[3];
> +
> +struct mc13xxx_button_def {
> + unsigned int irq;
> + unsigned int sense_bit;
> };
>
> -#define MC13783_REG_INTERRUPT_SENSE_1 5
> -#define MC13783_IRQSENSE1_ONOFD1S (1 << 3)
> -#define MC13783_IRQSENSE1_ONOFD2S (1 << 4)
> -#define MC13783_IRQSENSE1_ONOFD3S (1 << 5)
> +struct mc13xxx_pwrb_devtype {
> + struct mc13xxx_button_def btn_def[MAX13XXX_NUM_BUTTONS];
> +};
>
> -#define MC13783_REG_POWER_CONTROL_2 15
> -#define MC13783_POWER_CONTROL_2_ON1BDBNC 4
> -#define MC13783_POWER_CONTROL_2_ON2BDBNC 6
> -#define MC13783_POWER_CONTROL_2_ON3BDBNC 8
> -#define MC13783_POWER_CONTROL_2_ON1BRSTEN (1 << 1)
> -#define MC13783_POWER_CONTROL_2_ON2BRSTEN (1 << 2)
> -#define MC13783_POWER_CONTROL_2_ON3BRSTEN (1 << 3)
> +struct mc13xxx_pwrb {
> + struct mc13xxx_pwrb_devtype *devtype;
> + unsigned int enabled;
> + unsigned int inverted;
> + u16 btn_code[MAX13XXX_NUM_BUTTONS];
> + struct input_dev *input;
> + struct mc13xxx *mc13xxx;
> +};
>
> -static irqreturn_t button_irq(int irq, void *_priv)
> -{
> - struct mc13783_pwrb *priv = _priv;
> - int val;
> -
> - mc13xxx_irq_ack(priv->mc13783, irq);
> - mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val);
> -
> - switch (irq) {
> - case MC13783_IRQ_ONOFD1:
> - val = val & MC13783_IRQSENSE1_ONOFD1S ? 1 : 0;
> - if (priv->flags & MC13783_PWRB_B1_POL_INVERT)
> - val ^= 1;
> - input_report_key(priv->pwr, priv->keymap[0], val);
> - break;
> -
> - case MC13783_IRQ_ONOFD2:
> - val = val & MC13783_IRQSENSE1_ONOFD2S ? 1 : 0;
> - if (priv->flags & MC13783_PWRB_B2_POL_INVERT)
> - val ^= 1;
> - input_report_key(priv->pwr, priv->keymap[1], val);
> - break;
> -
> - case MC13783_IRQ_ONOFD3:
> - val = val & MC13783_IRQSENSE1_ONOFD3S ? 1 : 0;
> - if (priv->flags & MC13783_PWRB_B3_POL_INVERT)
> - val ^= 1;
> - input_report_key(priv->pwr, priv->keymap[2], val);
> - break;
> - }
> +#define MC13XXX_REG_INTERRUPT_SENSE_1 5
> +#define MC13XXX_REG_POWER_CONTROL_2 15
>
> - input_sync(priv->pwr);
> +static irqreturn_t mc13xxx_pwrbutton_irq(int irq, void *data)
> +{
> + struct mc13xxx_pwrb *priv = data;
> + unsigned int i, val;
> +
> + mc13xxx_irq_ack(priv->mc13xxx, irq);
> + mc13xxx_reg_read(priv->mc13xxx, MC13XXX_REG_INTERRUPT_SENSE_1, &val);
> +
> + for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
> + if (irq == priv->devtype->btn_def[i].irq) {
> + val = !!(val & priv->devtype->btn_def[i].sense_bit);
> + if (priv->inverted & BIT(i))
> + val = !val;
> + input_report_key(priv->input, priv->btn_code[i], val);
> + input_sync(priv->input);
> + break;
> + }
>
> return IRQ_HANDLED;
> }
>
> -static int mc13783_pwrbutton_probe(struct platform_device *pdev)
> +static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
> {
> - const struct mc13xxx_buttons_platform_data *pdata;
> - struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
> - struct input_dev *pwr;
> - struct mc13783_pwrb *priv;
> - int err = 0;
> - int reg = 0;
> -
> - pdata = dev_get_platdata(&pdev->dev);
> + struct mc13xxx_buttons_platform_data *pdata =
> + dev_get_platdata(&pdev->dev);
> + struct mc13xxx *mc13xxx = dev_get_drvdata(pdev->dev.parent);
> + struct mc13xxx_pwrb_devtype *devtype =
> + (struct mc13xxx_pwrb_devtype *)pdev->id_entry->driver_data;
> + struct mc13xxx_pwrb *priv;
> + int i, reg = 0, ret = -EINVAL;
> +
> if (!pdata) {
> - dev_err(&pdev->dev, "missing platform data\n");
> + dev_err(&pdev->dev, "Missing platform data\n");
> return -ENODEV;
> }
>
> - pwr = input_allocate_device();
> - if (!pwr) {
> - dev_dbg(&pdev->dev, "Can't allocate power button\n");
> + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> return -ENOMEM;
> - }
> -
> - priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> - if (!priv) {
> - err = -ENOMEM;
> - dev_dbg(&pdev->dev, "Can't allocate power button\n");
> - goto free_input_dev;
> - }
> -
> - reg |= (pdata->b1on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON1BDBNC;
> - reg |= (pdata->b2on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON2BDBNC;
> - reg |= (pdata->b3on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON3BDBNC;
> -
> - priv->pwr = pwr;
> - priv->mc13783 = mc13783;
>
> - mc13xxx_lock(mc13783);
> -
> - if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) {
> - priv->keymap[0] = pdata->b1on_key;
> - if (pdata->b1on_key != KEY_RESERVED)
> - __set_bit(pdata->b1on_key, pwr->keybit);
> -
> - if (pdata->b1on_flags & MC13783_BUTTON_POL_INVERT)
> - priv->flags |= MC13783_PWRB_B1_POL_INVERT;
> + priv->input = devm_input_allocate_device(&pdev->dev);
> + if (!priv->input)
> + return -ENOMEM;
>
> - if (pdata->b1on_flags & MC13783_BUTTON_RESET_EN)
> - reg |= MC13783_POWER_CONTROL_2_ON1BRSTEN;
> + priv->mc13xxx = mc13xxx;
> + priv->devtype = devtype;
> + platform_set_drvdata(pdev, priv);
>
> - err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD1,
> - button_irq, "b1on", priv);
> - if (err) {
> - dev_dbg(&pdev->dev, "Can't request irq\n");
> - goto free_priv;
> - }
> + for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
> + u16 code, invert, reset, debounce;
> +
> + if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
> + continue;
> + code = pdata->buttons[i].keycode;
> + invert = !!(pdata->buttons[i].flags &
> + MC13XXX_BUTTON_POL_INVERT);
> + reset = !!(pdata->buttons[i].flags &
> + MC13XXX_BUTTON_RESET_EN);
> + debounce = pdata->buttons[i].flags;
> +
> + priv->btn_code[i] = code;
> + if (code != KEY_RESERVED)
> + __set_bit(code, priv->input->keybit);
> +
> + priv->enabled |= BIT(i);
> + priv->inverted |= invert << i;
> + reg |= reset << (i + 1);
> + reg |= (debounce & 0x03) << (4 + i * 2);
> }
>
> - if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) {
> - priv->keymap[1] = pdata->b2on_key;
> - if (pdata->b2on_key != KEY_RESERVED)
> - __set_bit(pdata->b2on_key, pwr->keybit);
> -
> - if (pdata->b2on_flags & MC13783_BUTTON_POL_INVERT)
> - priv->flags |= MC13783_PWRB_B2_POL_INVERT;
> -
> - if (pdata->b2on_flags & MC13783_BUTTON_RESET_EN)
> - reg |= MC13783_POWER_CONTROL_2_ON2BRSTEN;
> -
> - err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD2,
> - button_irq, "b2on", priv);
> - if (err) {
> - dev_dbg(&pdev->dev, "Can't request irq\n");
> - goto free_irq_b1;
> + mc13xxx_lock(mc13xxx);
> +
> + mc13xxx_reg_rmw(mc13xxx, MC13XXX_REG_POWER_CONTROL_2, 0x3fe, reg);
> +
> + for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
> + if (priv->enabled & BIT(i)) {
> + ret = mc13xxx_irq_request(mc13xxx,
> + devtype->btn_def[i].irq,
> + mc13xxx_pwrbutton_irq, NULL,
> + priv);
> + if (ret) {
> + dev_err(&pdev->dev, "Can't request IRQ%i: %i\n",
> + devtype->btn_def[i].irq, ret);
> + priv->enabled &= ~BIT(i);
> + }
> }
> - }
>
> - if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) {
> - priv->keymap[2] = pdata->b3on_key;
> - if (pdata->b3on_key != KEY_RESERVED)
> - __set_bit(pdata->b3on_key, pwr->keybit);
> + mc13xxx_unlock(mc13xxx);
>
> - if (pdata->b3on_flags & MC13783_BUTTON_POL_INVERT)
> - priv->flags |= MC13783_PWRB_B3_POL_INVERT;
> + priv->input->name = "mc13xxx_pwrbutton";
> + priv->input->phys = "mc13xxx_pwrbutton/input0";
> + priv->input->id.bustype = BUS_HOST;
> + priv->input->id.vendor = 0x0001;
> + priv->input->id.product = 0x0001;
> + priv->input->id.version = 0x0100;
> + priv->input->keycode = priv->btn_code;
> + priv->input->keycodemax = ARRAY_SIZE(priv->btn_code);
> + priv->input->keycodesize = sizeof(priv->btn_code[0]);
> + __set_bit(EV_KEY, priv->input->evbit);
>
> - if (pdata->b3on_flags & MC13783_BUTTON_RESET_EN)
> - reg |= MC13783_POWER_CONTROL_2_ON3BRSTEN;
> -
> - err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD3,
> - button_irq, "b3on", priv);
> - if (err) {
> - dev_dbg(&pdev->dev, "Can't request irq: %d\n", err);
> - goto free_irq_b2;
> - }
> - }
> + input_set_drvdata(priv->input, priv);
>
> - mc13xxx_reg_rmw(mc13783, MC13783_REG_POWER_CONTROL_2, 0x3FE, reg);
> + ret = input_register_device(priv->input);
> + if (ret)
> + dev_err(&pdev->dev, "Can't register input device: %i\n", ret);
>
> - mc13xxx_unlock(mc13783);
> -
> - pwr->name = "mc13783_pwrbutton";
> - pwr->phys = "mc13783_pwrbutton/input0";
> - pwr->dev.parent = &pdev->dev;
> -
> - pwr->keycode = priv->keymap;
> - pwr->keycodemax = ARRAY_SIZE(priv->keymap);
> - pwr->keycodesize = sizeof(priv->keymap[0]);
> - __set_bit(EV_KEY, pwr->evbit);
> -
> - err = input_register_device(pwr);
> - if (err) {
> - dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
> - goto free_irq;
> - }
> -
> - platform_set_drvdata(pdev, priv);
> -
> - return 0;
> -
> -free_irq:
> - mc13xxx_lock(mc13783);
> -
> - if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
> - mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD3, priv);
> -
> -free_irq_b2:
> - if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
> - mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD2, priv);
> -
> -free_irq_b1:
> - if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
> - mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD1, priv);
> -
> -free_priv:
> - mc13xxx_unlock(mc13783);
> - kfree(priv);
> -
> -free_input_dev:
> - input_free_device(pwr);
> -
> - return err;
> + return ret;
> }
>
> -static int mc13783_pwrbutton_remove(struct platform_device *pdev)
> +static int mc13xxx_pwrbutton_remove(struct platform_device *pdev)
> {
> - struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
> - const struct mc13xxx_buttons_platform_data *pdata;
> -
> - pdata = dev_get_platdata(&pdev->dev);
> -
> - mc13xxx_lock(priv->mc13783);
> -
> - if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
> - mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD3, priv);
> - if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
> - mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD2, priv);
> - if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
> - mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD1, priv);
> + struct mc13xxx_pwrb *priv = platform_get_drvdata(pdev);
> + int i;
>
> - mc13xxx_unlock(priv->mc13783);
> -
> - input_unregister_device(priv->pwr);
> - kfree(priv);
> + mc13xxx_lock(priv->mc13xxx);
> + for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
> + if (priv->enabled & BIT(i))
> + mc13xxx_irq_free(priv->mc13xxx,
> + priv->devtype->btn_def[i].irq, priv);
> + mc13xxx_unlock(priv->mc13xxx);
>
> return 0;
> }
>
> -static struct platform_driver mc13783_pwrbutton_driver = {
> - .probe = mc13783_pwrbutton_probe,
> - .remove = mc13783_pwrbutton_remove,
> - .driver = {
> - .name = "mc13783-pwrbutton",
> +static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
> + .btn_def[0] = { MC13783_IRQ_ONOFD1, BIT(3) },
> + .btn_def[1] = { MC13783_IRQ_ONOFD2, BIT(4) },
> + .btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5) }
> +};
> +
> +static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
> + { "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
> + { }
> +};
> +MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
> +
> +static struct platform_driver mc13xxx_pwrbutton_driver = {
> + .driver = {
> + .name = "mc13xxx-pwrbutton",
> .owner = THIS_MODULE,
> },
> + .remove = mc13xxx_pwrbutton_remove,
> + .id_table = mc13xxx_pwrbutton_id_table,
> };
> +module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
>
> -module_platform_driver(mc13783_pwrbutton_driver);
> -
> -MODULE_ALIAS("platform:mc13783-pwrbutton");
> MODULE_DESCRIPTION("MC13783 Power Button");
> MODULE_LICENSE("GPL v2");
> MODULE_AUTHOR("Philippe Retornaz");
> diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
> index 41ed592..b895538 100644
> --- a/include/linux/mfd/mc13xxx.h
> +++ b/include/linux/mfd/mc13xxx.h
> @@ -142,20 +142,22 @@ struct mc13xxx_leds_platform_data {
> u32 led_control[MAX_LED_CONTROL_REGS];
> };
>
> +#define MAX13XXX_NUM_BUTTONS 3
> +
> +struct mc13xxx_button {
> + u16 keycode;
> + unsigned int flags;
> +#define MC13XXX_BUTTON_DBNC_0MS 0
> +#define MC13XXX_BUTTON_DBNC_30MS 1
> +#define MC13XXX_BUTTON_DBNC_150MS 2
> +#define MC13XXX_BUTTON_DBNC_750MS 3
> +#define MC13XXX_BUTTON_ENABLE (1 << 2)
> +#define MC13XXX_BUTTON_POL_INVERT (1 << 3)
> +#define MC13XXX_BUTTON_RESET_EN (1 << 4)
> +};
> +
> struct mc13xxx_buttons_platform_data {
> -#define MC13783_BUTTON_DBNC_0MS 0
> -#define MC13783_BUTTON_DBNC_30MS 1
> -#define MC13783_BUTTON_DBNC_150MS 2
> -#define MC13783_BUTTON_DBNC_750MS 3
> -#define MC13783_BUTTON_ENABLE (1 << 2)
> -#define MC13783_BUTTON_POL_INVERT (1 << 3)
> -#define MC13783_BUTTON_RESET_EN (1 << 4)
> - int b1on_flags;
> - unsigned short b1on_key;
> - int b2on_flags;
> - unsigned short b2on_key;
> - int b3on_flags;
> - unsigned short b3on_key;
> + struct mc13xxx_button buttons[MAX13XXX_NUM_BUTTONS];
> };
>
> struct mc13xxx_ts_platform_data {
> --
> 1.8.1.5
>
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH v3 RESEND 2/3] input: mc13783: Add MC13892 support
From: Alexander Shiyan @ 2013-08-17 5:46 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov, Sascha Hauer, Alexander Shiyan
In-Reply-To: <1376718381-16924-1-git-send-email-shc_work@mail.ru>
This patch adds support for MC13892 PMIC in mc13783-pwrbutton driver.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/input/misc/Kconfig | 6 +++---
drivers/input/misc/mc13783-pwrbutton.c | 10 +++++++++-
include/linux/mfd/mc13892.h | 4 ++++
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0b541cd..0d83653 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -167,10 +167,10 @@ config INPUT_MAX8997_HAPTIC
module will be called max8997-haptic.
config INPUT_MC13783_PWRBUTTON
- tristate "MC13783 ON buttons"
- depends on MFD_MC13783
+ tristate "MC13783/MC13892 ON buttons"
+ depends on MFD_MC13XXX
help
- Support the ON buttons of MC13783 PMIC as an input device
+ Support the ON buttons of MC13783/MC13892 PMIC as an input device
reporting power button status.
To compile this driver as a module, choose M here: the module
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index aaaacef..2e21f19 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -26,6 +26,7 @@
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
+#include <linux/mfd/mc13892.h>
struct mc13xxx_button_def {
unsigned int irq;
@@ -178,8 +179,15 @@ static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
.btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5) }
};
+static const struct mc13xxx_pwrb_devtype mc13892_pwrb_devtype = {
+ .btn_def[0] = { MC13892_IRQ_ONOFD1, BIT(3) },
+ .btn_def[1] = { MC13892_IRQ_ONOFD2, BIT(4) },
+ .btn_def[2] = { MC13892_IRQ_ONOFD3, BIT(2) }
+};
+
static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
{ "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
+ { "mc13892-pwrbutton", (kernel_ulong_t)&mc13892_pwrb_devtype },
{ }
};
MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
@@ -194,6 +202,6 @@ static struct platform_driver mc13xxx_pwrbutton_driver = {
};
module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
-MODULE_DESCRIPTION("MC13783 Power Button");
+MODULE_DESCRIPTION("MC13XXX Power Button");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Philippe Retornaz");
diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
index a00f2be..bdc3baf 100644
--- a/include/linux/mfd/mc13892.h
+++ b/include/linux/mfd/mc13892.h
@@ -36,4 +36,8 @@
#define MC13892_PWGT2SPI 22
#define MC13892_VCOINCELL 23
+#define MC13892_IRQ_ONOFD3 26
+#define MC13892_IRQ_ONOFD1 27
+#define MC13892_IRQ_ONOFD2 28
+
#endif
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 RESEND 1/3] input: mc13783: Prepare driver to support MC13892 and OF
From: Alexander Shiyan @ 2013-08-17 5:46 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov, Sascha Hauer, Alexander Shiyan
This patch is a preparation mc13xxx powerbutton driver to support
MC13892 and support the probe through the DT.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
arch/arm/mach-imx/mach-mx31moboard.c | 9 +-
drivers/input/misc/mc13783-pwrbutton.c | 332 +++++++++++++--------------------
include/linux/mfd/mc13xxx.h | 28 +--
3 files changed, 151 insertions(+), 218 deletions(-)
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index 6f424ec..2a8aa43 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -276,9 +276,12 @@ static struct mc13xxx_leds_platform_data moboard_leds = {
};
static struct mc13xxx_buttons_platform_data moboard_buttons = {
- .b1on_flags = MC13783_BUTTON_DBNC_750MS | MC13783_BUTTON_ENABLE |
- MC13783_BUTTON_POL_INVERT,
- .b1on_key = KEY_POWER,
+ .buttons[0] = {
+ .keycode = KEY_POWER,
+ .flags = MC13XXX_BUTTON_ENABLE |
+ MC13XXX_BUTTON_DBNC_750MS |
+ MC13XXX_BUTTON_POL_INVERT,
+ },
};
static struct mc13xxx_codec_platform_data moboard_codec = {
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index d0277a7..aaaacef 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -24,248 +24,176 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/input.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-struct mc13783_pwrb {
- struct input_dev *pwr;
- struct mc13xxx *mc13783;
-#define MC13783_PWRB_B1_POL_INVERT (1 << 0)
-#define MC13783_PWRB_B2_POL_INVERT (1 << 1)
-#define MC13783_PWRB_B3_POL_INVERT (1 << 2)
- int flags;
- unsigned short keymap[3];
+
+struct mc13xxx_button_def {
+ unsigned int irq;
+ unsigned int sense_bit;
};
-#define MC13783_REG_INTERRUPT_SENSE_1 5
-#define MC13783_IRQSENSE1_ONOFD1S (1 << 3)
-#define MC13783_IRQSENSE1_ONOFD2S (1 << 4)
-#define MC13783_IRQSENSE1_ONOFD3S (1 << 5)
+struct mc13xxx_pwrb_devtype {
+ struct mc13xxx_button_def btn_def[MAX13XXX_NUM_BUTTONS];
+};
-#define MC13783_REG_POWER_CONTROL_2 15
-#define MC13783_POWER_CONTROL_2_ON1BDBNC 4
-#define MC13783_POWER_CONTROL_2_ON2BDBNC 6
-#define MC13783_POWER_CONTROL_2_ON3BDBNC 8
-#define MC13783_POWER_CONTROL_2_ON1BRSTEN (1 << 1)
-#define MC13783_POWER_CONTROL_2_ON2BRSTEN (1 << 2)
-#define MC13783_POWER_CONTROL_2_ON3BRSTEN (1 << 3)
+struct mc13xxx_pwrb {
+ struct mc13xxx_pwrb_devtype *devtype;
+ unsigned int enabled;
+ unsigned int inverted;
+ u16 btn_code[MAX13XXX_NUM_BUTTONS];
+ struct input_dev *input;
+ struct mc13xxx *mc13xxx;
+};
-static irqreturn_t button_irq(int irq, void *_priv)
-{
- struct mc13783_pwrb *priv = _priv;
- int val;
-
- mc13xxx_irq_ack(priv->mc13783, irq);
- mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val);
-
- switch (irq) {
- case MC13783_IRQ_ONOFD1:
- val = val & MC13783_IRQSENSE1_ONOFD1S ? 1 : 0;
- if (priv->flags & MC13783_PWRB_B1_POL_INVERT)
- val ^= 1;
- input_report_key(priv->pwr, priv->keymap[0], val);
- break;
-
- case MC13783_IRQ_ONOFD2:
- val = val & MC13783_IRQSENSE1_ONOFD2S ? 1 : 0;
- if (priv->flags & MC13783_PWRB_B2_POL_INVERT)
- val ^= 1;
- input_report_key(priv->pwr, priv->keymap[1], val);
- break;
-
- case MC13783_IRQ_ONOFD3:
- val = val & MC13783_IRQSENSE1_ONOFD3S ? 1 : 0;
- if (priv->flags & MC13783_PWRB_B3_POL_INVERT)
- val ^= 1;
- input_report_key(priv->pwr, priv->keymap[2], val);
- break;
- }
+#define MC13XXX_REG_INTERRUPT_SENSE_1 5
+#define MC13XXX_REG_POWER_CONTROL_2 15
- input_sync(priv->pwr);
+static irqreturn_t mc13xxx_pwrbutton_irq(int irq, void *data)
+{
+ struct mc13xxx_pwrb *priv = data;
+ unsigned int i, val;
+
+ mc13xxx_irq_ack(priv->mc13xxx, irq);
+ mc13xxx_reg_read(priv->mc13xxx, MC13XXX_REG_INTERRUPT_SENSE_1, &val);
+
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+ if (irq == priv->devtype->btn_def[i].irq) {
+ val = !!(val & priv->devtype->btn_def[i].sense_bit);
+ if (priv->inverted & BIT(i))
+ val = !val;
+ input_report_key(priv->input, priv->btn_code[i], val);
+ input_sync(priv->input);
+ break;
+ }
return IRQ_HANDLED;
}
-static int mc13783_pwrbutton_probe(struct platform_device *pdev)
+static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
{
- const struct mc13xxx_buttons_platform_data *pdata;
- struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
- struct input_dev *pwr;
- struct mc13783_pwrb *priv;
- int err = 0;
- int reg = 0;
-
- pdata = dev_get_platdata(&pdev->dev);
+ struct mc13xxx_buttons_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct mc13xxx *mc13xxx = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx_pwrb_devtype *devtype =
+ (struct mc13xxx_pwrb_devtype *)pdev->id_entry->driver_data;
+ struct mc13xxx_pwrb *priv;
+ int i, reg = 0, ret = -EINVAL;
+
if (!pdata) {
- dev_err(&pdev->dev, "missing platform data\n");
+ dev_err(&pdev->dev, "Missing platform data\n");
return -ENODEV;
}
- pwr = input_allocate_device();
- if (!pwr) {
- dev_dbg(&pdev->dev, "Can't allocate power button\n");
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- err = -ENOMEM;
- dev_dbg(&pdev->dev, "Can't allocate power button\n");
- goto free_input_dev;
- }
-
- reg |= (pdata->b1on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON1BDBNC;
- reg |= (pdata->b2on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON2BDBNC;
- reg |= (pdata->b3on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON3BDBNC;
-
- priv->pwr = pwr;
- priv->mc13783 = mc13783;
- mc13xxx_lock(mc13783);
-
- if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) {
- priv->keymap[0] = pdata->b1on_key;
- if (pdata->b1on_key != KEY_RESERVED)
- __set_bit(pdata->b1on_key, pwr->keybit);
-
- if (pdata->b1on_flags & MC13783_BUTTON_POL_INVERT)
- priv->flags |= MC13783_PWRB_B1_POL_INVERT;
+ priv->input = devm_input_allocate_device(&pdev->dev);
+ if (!priv->input)
+ return -ENOMEM;
- if (pdata->b1on_flags & MC13783_BUTTON_RESET_EN)
- reg |= MC13783_POWER_CONTROL_2_ON1BRSTEN;
+ priv->mc13xxx = mc13xxx;
+ priv->devtype = devtype;
+ platform_set_drvdata(pdev, priv);
- err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD1,
- button_irq, "b1on", priv);
- if (err) {
- dev_dbg(&pdev->dev, "Can't request irq\n");
- goto free_priv;
- }
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
+ u16 code, invert, reset, debounce;
+
+ if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
+ continue;
+ code = pdata->buttons[i].keycode;
+ invert = !!(pdata->buttons[i].flags &
+ MC13XXX_BUTTON_POL_INVERT);
+ reset = !!(pdata->buttons[i].flags &
+ MC13XXX_BUTTON_RESET_EN);
+ debounce = pdata->buttons[i].flags;
+
+ priv->btn_code[i] = code;
+ if (code != KEY_RESERVED)
+ __set_bit(code, priv->input->keybit);
+
+ priv->enabled |= BIT(i);
+ priv->inverted |= invert << i;
+ reg |= reset << (i + 1);
+ reg |= (debounce & 0x03) << (4 + i * 2);
}
- if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) {
- priv->keymap[1] = pdata->b2on_key;
- if (pdata->b2on_key != KEY_RESERVED)
- __set_bit(pdata->b2on_key, pwr->keybit);
-
- if (pdata->b2on_flags & MC13783_BUTTON_POL_INVERT)
- priv->flags |= MC13783_PWRB_B2_POL_INVERT;
-
- if (pdata->b2on_flags & MC13783_BUTTON_RESET_EN)
- reg |= MC13783_POWER_CONTROL_2_ON2BRSTEN;
-
- err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD2,
- button_irq, "b2on", priv);
- if (err) {
- dev_dbg(&pdev->dev, "Can't request irq\n");
- goto free_irq_b1;
+ mc13xxx_lock(mc13xxx);
+
+ mc13xxx_reg_rmw(mc13xxx, MC13XXX_REG_POWER_CONTROL_2, 0x3fe, reg);
+
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+ if (priv->enabled & BIT(i)) {
+ ret = mc13xxx_irq_request(mc13xxx,
+ devtype->btn_def[i].irq,
+ mc13xxx_pwrbutton_irq, NULL,
+ priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't request IRQ%i: %i\n",
+ devtype->btn_def[i].irq, ret);
+ priv->enabled &= ~BIT(i);
+ }
}
- }
- if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) {
- priv->keymap[2] = pdata->b3on_key;
- if (pdata->b3on_key != KEY_RESERVED)
- __set_bit(pdata->b3on_key, pwr->keybit);
+ mc13xxx_unlock(mc13xxx);
- if (pdata->b3on_flags & MC13783_BUTTON_POL_INVERT)
- priv->flags |= MC13783_PWRB_B3_POL_INVERT;
+ priv->input->name = "mc13xxx_pwrbutton";
+ priv->input->phys = "mc13xxx_pwrbutton/input0";
+ priv->input->id.bustype = BUS_HOST;
+ priv->input->id.vendor = 0x0001;
+ priv->input->id.product = 0x0001;
+ priv->input->id.version = 0x0100;
+ priv->input->keycode = priv->btn_code;
+ priv->input->keycodemax = ARRAY_SIZE(priv->btn_code);
+ priv->input->keycodesize = sizeof(priv->btn_code[0]);
+ __set_bit(EV_KEY, priv->input->evbit);
- if (pdata->b3on_flags & MC13783_BUTTON_RESET_EN)
- reg |= MC13783_POWER_CONTROL_2_ON3BRSTEN;
-
- err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD3,
- button_irq, "b3on", priv);
- if (err) {
- dev_dbg(&pdev->dev, "Can't request irq: %d\n", err);
- goto free_irq_b2;
- }
- }
+ input_set_drvdata(priv->input, priv);
- mc13xxx_reg_rmw(mc13783, MC13783_REG_POWER_CONTROL_2, 0x3FE, reg);
+ ret = input_register_device(priv->input);
+ if (ret)
+ dev_err(&pdev->dev, "Can't register input device: %i\n", ret);
- mc13xxx_unlock(mc13783);
-
- pwr->name = "mc13783_pwrbutton";
- pwr->phys = "mc13783_pwrbutton/input0";
- pwr->dev.parent = &pdev->dev;
-
- pwr->keycode = priv->keymap;
- pwr->keycodemax = ARRAY_SIZE(priv->keymap);
- pwr->keycodesize = sizeof(priv->keymap[0]);
- __set_bit(EV_KEY, pwr->evbit);
-
- err = input_register_device(pwr);
- if (err) {
- dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
- goto free_irq;
- }
-
- platform_set_drvdata(pdev, priv);
-
- return 0;
-
-free_irq:
- mc13xxx_lock(mc13783);
-
- if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
- mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD3, priv);
-
-free_irq_b2:
- if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
- mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD2, priv);
-
-free_irq_b1:
- if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
- mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD1, priv);
-
-free_priv:
- mc13xxx_unlock(mc13783);
- kfree(priv);
-
-free_input_dev:
- input_free_device(pwr);
-
- return err;
+ return ret;
}
-static int mc13783_pwrbutton_remove(struct platform_device *pdev)
+static int mc13xxx_pwrbutton_remove(struct platform_device *pdev)
{
- struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
- const struct mc13xxx_buttons_platform_data *pdata;
-
- pdata = dev_get_platdata(&pdev->dev);
-
- mc13xxx_lock(priv->mc13783);
-
- if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
- mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD3, priv);
- if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
- mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD2, priv);
- if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
- mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD1, priv);
+ struct mc13xxx_pwrb *priv = platform_get_drvdata(pdev);
+ int i;
- mc13xxx_unlock(priv->mc13783);
-
- input_unregister_device(priv->pwr);
- kfree(priv);
+ mc13xxx_lock(priv->mc13xxx);
+ for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+ if (priv->enabled & BIT(i))
+ mc13xxx_irq_free(priv->mc13xxx,
+ priv->devtype->btn_def[i].irq, priv);
+ mc13xxx_unlock(priv->mc13xxx);
return 0;
}
-static struct platform_driver mc13783_pwrbutton_driver = {
- .probe = mc13783_pwrbutton_probe,
- .remove = mc13783_pwrbutton_remove,
- .driver = {
- .name = "mc13783-pwrbutton",
+static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
+ .btn_def[0] = { MC13783_IRQ_ONOFD1, BIT(3) },
+ .btn_def[1] = { MC13783_IRQ_ONOFD2, BIT(4) },
+ .btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5) }
+};
+
+static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
+ { "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
+
+static struct platform_driver mc13xxx_pwrbutton_driver = {
+ .driver = {
+ .name = "mc13xxx-pwrbutton",
.owner = THIS_MODULE,
},
+ .remove = mc13xxx_pwrbutton_remove,
+ .id_table = mc13xxx_pwrbutton_id_table,
};
+module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
-module_platform_driver(mc13783_pwrbutton_driver);
-
-MODULE_ALIAS("platform:mc13783-pwrbutton");
MODULE_DESCRIPTION("MC13783 Power Button");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Philippe Retornaz");
diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
index 41ed592..b895538 100644
--- a/include/linux/mfd/mc13xxx.h
+++ b/include/linux/mfd/mc13xxx.h
@@ -142,20 +142,22 @@ struct mc13xxx_leds_platform_data {
u32 led_control[MAX_LED_CONTROL_REGS];
};
+#define MAX13XXX_NUM_BUTTONS 3
+
+struct mc13xxx_button {
+ u16 keycode;
+ unsigned int flags;
+#define MC13XXX_BUTTON_DBNC_0MS 0
+#define MC13XXX_BUTTON_DBNC_30MS 1
+#define MC13XXX_BUTTON_DBNC_150MS 2
+#define MC13XXX_BUTTON_DBNC_750MS 3
+#define MC13XXX_BUTTON_ENABLE (1 << 2)
+#define MC13XXX_BUTTON_POL_INVERT (1 << 3)
+#define MC13XXX_BUTTON_RESET_EN (1 << 4)
+};
+
struct mc13xxx_buttons_platform_data {
-#define MC13783_BUTTON_DBNC_0MS 0
-#define MC13783_BUTTON_DBNC_30MS 1
-#define MC13783_BUTTON_DBNC_150MS 2
-#define MC13783_BUTTON_DBNC_750MS 3
-#define MC13783_BUTTON_ENABLE (1 << 2)
-#define MC13783_BUTTON_POL_INVERT (1 << 3)
-#define MC13783_BUTTON_RESET_EN (1 << 4)
- int b1on_flags;
- unsigned short b1on_key;
- int b2on_flags;
- unsigned short b2on_key;
- int b3on_flags;
- unsigned short b3on_key;
+ struct mc13xxx_button buttons[MAX13XXX_NUM_BUTTONS];
};
struct mc13xxx_ts_platform_data {
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 RESEND 3/3] input: mc13783: Add DT probe support
From: Alexander Shiyan @ 2013-08-17 5:45 UTC (permalink / raw)
To: linux-input
Cc: Dmitry Torokhov, Sascha Hauer, devicetree, Rob Herring,
Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
Grant Likely, Alexander Shiyan
Patch adds DT support for MC13783/MC13892 PMICs.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
Documentation/devicetree/bindings/mfd/mc13xxx.txt | 13 +++++
drivers/input/misc/mc13783-pwrbutton.c | 61 +++++++++++++++++------
2 files changed, 60 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
index abd9e3c..cf8b61c 100644
--- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt
+++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
@@ -10,6 +10,12 @@ Optional properties:
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes:
+- buttons : Contain power button nodes. Each button should be declared as
+ "button@<num>" and contain code in "linux,code" property.
+ Optional properties:
+ active-high : Change active button level from 0 to 1.
+ enable-reset: Performs hadware reset through PMIC.
+ debounce : Debounce value which will be taken from PMIC datasheet.
- regulators : Contain the regulator nodes. The regulators are bound using
their names as listed below with their registers and bits for enabling.
@@ -89,6 +95,13 @@ ecspi@70010000 { /* ECSPI1 */
interrupt-parent = <&gpio0>;
interrupts = <8>;
+ buttons {
+ button@1 {
+ linux,code = <0x1f>;
+ debounce = <1>;
+ };
+ };
+
regulators {
sw1_reg: mc13892__sw1 {
regulator-min-microvolt = <600000>;
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index 2e21f19..3f9cfd1 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/input.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
#include <linux/mfd/mc13892.h>
@@ -77,21 +78,28 @@ static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
struct mc13xxx *mc13xxx = dev_get_drvdata(pdev->dev.parent);
struct mc13xxx_pwrb_devtype *devtype =
(struct mc13xxx_pwrb_devtype *)pdev->id_entry->driver_data;
+ struct device_node *parent, *child;
struct mc13xxx_pwrb *priv;
int i, reg = 0, ret = -EINVAL;
- if (!pdata) {
+ of_node_get(pdev->dev.parent->of_node);
+ parent = of_find_node_by_name(pdev->dev.parent->of_node, "buttons");
+ if (!pdata && !parent) {
dev_err(&pdev->dev, "Missing platform data\n");
return -ENODEV;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out_node_put;
+ }
priv->input = devm_input_allocate_device(&pdev->dev);
- if (!priv->input)
- return -ENOMEM;
+ if (!priv->input) {
+ ret = -ENOMEM;
+ goto out_node_put;
+ }
priv->mc13xxx = mc13xxx;
priv->devtype = devtype;
@@ -99,15 +107,36 @@ static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
u16 code, invert, reset, debounce;
-
- if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
- continue;
- code = pdata->buttons[i].keycode;
- invert = !!(pdata->buttons[i].flags &
- MC13XXX_BUTTON_POL_INVERT);
- reset = !!(pdata->buttons[i].flags &
- MC13XXX_BUTTON_RESET_EN);
- debounce = pdata->buttons[i].flags;
+ const __be32 *prop;
+ char childname[5];
+
+ if (parent) {
+ sprintf(childname, "button@%i", i + 1);
+ child = of_get_child_by_name(parent, childname);
+ if (!child)
+ continue;
+ prop = of_get_property(child, "linux,code", NULL);
+ if (prop)
+ code = be32_to_cpu(*prop) & 0xffff;
+ else {
+ dev_err(&pdev->dev,
+ "Button %i: Missing key code\n", i + 1);
+ continue;
+ }
+ invert = of_property_read_bool(child, "active-high");
+ reset = of_property_read_bool(child, "enable-reset");
+ prop = of_get_property(child, "debounce", NULL);
+ debounce = prop ? be32_to_cpu(*prop) : 0;
+ } else {
+ if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
+ continue;
+ code = pdata->buttons[i].keycode;
+ invert = !!(pdata->buttons[i].flags &
+ MC13XXX_BUTTON_POL_INVERT);
+ reset = !!(pdata->buttons[i].flags &
+ MC13XXX_BUTTON_RESET_EN);
+ debounce = pdata->buttons[i].flags;
+ }
priv->btn_code[i] = code;
if (code != KEY_RESERVED)
@@ -155,6 +184,10 @@ static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
if (ret)
dev_err(&pdev->dev, "Can't register input device: %i\n", ret);
+out_node_put:
+ if (parent)
+ of_node_put(parent);
+
return ret;
}
--
1.8.1.5
^ permalink raw reply related
* [Dell Inspiron Inspiron 17R SE 7720] TouchPad detected as Generic Mouse
From: Jason O @ 2013-08-17 5:07 UTC (permalink / raw)
To: linux-input
I have already done regression testing and opened bug reports for this bug. All
information can be found attached to the bug reports. I have tested the newest
mainline kernel and the problem still exists.
Laptop is a Dell Inspiron 17R SE.
Ubuntu: Started as 12.04, currently 13.04
>From Mainline Kernel 3.11-rc4
jason@jason-Inspiron-7720:~$ dmesg | grep Unknown
[ 20.512553] psmouse serio1: alps: Unknown ALPS touchpad: E7=73 03 50, EC=73 02
02
jason@jason-Inspiron-7720:~$ uname -a
Linux jason-Inspiron-7720 3.11.0-031100rc4-generic #201308041735 SMP Sun Aug 4
21:36:46 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Looking at the kernel source really quick, E7 has a match however EC does not
unless I missed something.
Bug reports
Launchpad
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1093237
kernel.org
https://bugzilla.kernel.org/show_bug.cgi?id=60739
^ permalink raw reply
* I Will Be Glad To Know You,
From: Saanasandy Kuku @ 2013-08-16 20:56 UTC (permalink / raw)
I Will Be Glad To Know You,
I am Sandy. Please, I will like to be your friend only if you don't mind,
contact me for my picture
and more about me,
Thanks in advance and remain blessed!
Sandy.
^ permalink raw reply
* Re: [PATCH 3/4] input: ti_tsc: Enable shared IRQ for TSC and add overrun, underflow checks
From: Zubair Lutfullah : @ 2013-08-16 21:31 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Zubair Lutfullah, jic23, dmitry.torokhov, sameo, lee.jones,
linux-iio, linux-input, linux-kernel, gregkh, Russ.Dill
In-Reply-To: <20130816091409.GC26895@linutronix.de>
On Fri, Aug 16, 2013 at 11:14:09AM +0200, Sebastian Andrzej Siewior wrote:
> * Zubair Lutfullah | 2013-08-13 17:48:18 [+0100]:
> >+ if ((status & IRQENB_FIFO0OVRRUN) ||
> >+ (status & IRQENB_FIFO0UNDRFLW)) {
> >+
> >+ config = titsc_readl(ts_dev, REG_CTRL);
> >+ config &= ~(CNTRLREG_TSCSSENB);
> >+ titsc_writel(ts_dev, REG_CTRL, config);
> >+
> >+ if (status & IRQENB_FIFO0UNDRFLW) {
> >+ titsc_writel(ts_dev, REG_IRQSTATUS,
> >+ (status | IRQENB_FIFO0UNDRFLW));
> >+ irqclr |= IRQENB_FIFO0UNDRFLW;
> >+ } else {
> >+ titsc_writel(ts_dev, REG_IRQSTATUS,
> >+ (status | IRQENB_FIFO0OVRRUN));
> >+ irqclr |= IRQENB_FIFO0OVRRUN;
> >+ }
>
> You don't do anything on overflow / underflow. Is this due to the fact
> once enabled for FIFO1 it also triggers for FIFO0?
>
The TSCADC module doesn't recover from these interrupts.
> >+ titsc_writel(ts_dev, REG_CTRL,
> >+ (config | CNTRLREG_TSCSSENB));
The fix is to re-enable the module after disabling
and clearing the interrupts.
That is what the handler is doing.
> >+ } else if (status & IRQENB_FIFO0THRES) {
> > titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
> >
> > if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
> >@@ -317,9 +342,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
> > }
> >
> > if (irqclr) {
> >- titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
> >+ titsc_writel(ts_dev, REG_IRQSTATUS, (status | irqclr));
>
> Shouldn't FIFO1UNDRFLW & OVRRUN be handled by the adc driver? Why do you
> or the unhandled bits as well here?
FIFO1 is only used by TSC. ADC doesn't touch it.
>
> > am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
> >- return IRQ_HANDLED;
> >+ status = titsc_readl(ts_dev, REG_IRQSTATUS);
> >+ if (status == false)
> >+ return IRQ_HANDLED;
>
> And why this? If you something you handled it, if you didn't you return
> NONE. Why does it depend on REG_IRQSTATUS?
These quirks are to handle the situation where both IRQs happen
simultaneously. Which can occur when someone is using the TSC
while continuously sampling using the ADC.
REG_IRQSTATUS has flags for FIFO0 used by ADC as well.
If there are still those IRQs to handle, then IRQ_NONE is returned.
Otherwise, all IRQ flags are clear so IRQ_HANDLED is returned.
Thanks
Zubair
^ permalink raw reply
* Re: [PATCH 0/4] iio: input: ti_am335x_adc: Add continuous sampling support round 5
From: Zubair Lutfullah : @ 2013-08-16 21:23 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Zubair Lutfullah, jic23, dmitry.torokhov, linux-iio, linux-input,
linux-kernel, bigeasy, gregkh, Russ.Dill
In-Reply-To: <520BD308.7030709@kernel.org>
On Wed, Aug 14, 2013 at 07:57:12PM +0100, Jonathan Cameron wrote:
> I'll actually look at these later, but please do put a version number
> in your cover letter patch subject.
> [PATCH V5 0/4] is pretty much the convention to reduce the chance of anyone
> looking at the wrong version.
Noted.
I actually had round 4/5 at the end of the subjects..
Thanks
Zubair
>
> Thanks,
>
> Jonathan
>
> On 08/13/13 21:04, Zubair Lutfullah wrote:
> > Round 5 updates. Fixed the define order in the header as guided by Lee.
> >
> > Round 4 updates below.
> >
> > Note: These apply to the fixes-togreg branch in IIO because of
> > a fix on the adc side in there.
> >
> > The first few are for input which tweak the TSC driver to
> > allow ADC in continuous mode with irqs to work nicely together.
> >
> > The last one is for iio which adds continuous mode to the adc side.
> >
> > Received feedback on previous series.
> > 1. What if IRQs occur together?
> > This is handled now. Even if both assert.
> > They both work.
> >
> > 2. IIO error handling wrong.
> > Fixed now.
> >
> > 3. Headers wierd in IIO.
> > Fixed.
> >
> > Apart from that, found a few bugs in continuous mode
> > here and there. And squashed them into the same patch.
> >
> > Thanks
> > Zubair Lutfullah
> >
> > Zubair Lutfullah (4):
> > input: ti_am335x_tsc: correct step mask update after IRQ
> > input: ti_am335x_tsc: Increase sequencer delay time
> > input: ti_am335x_tsc: Enable shared IRQ for TSC, add overrun and
> > underflow checks
> > iio: ti_am335x_adc: Add continuous sampling and trigger support
> >
> > drivers/iio/adc/ti_am335x_adc.c | 353 ++++++++++++++++++++++++-----
> > drivers/input/touchscreen/ti_am335x_tsc.c | 45 +++-
> > include/linux/mfd/ti_am335x_tscadc.h | 14 ++
> > 3 files changed, 342 insertions(+), 70 deletions(-)
> >
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Zubair Lutfullah : @ 2013-08-16 21:21 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Jonathan Cameron, Zubair Lutfullah, jic23, dmitry.torokhov,
linux-iio, linux-input, linux-kernel, gregkh, Russ.Dill
In-Reply-To: <520E0307.70704@linutronix.de>
On Fri, Aug 16, 2013 at 12:46:31PM +0200, Sebastian Andrzej Siewior wrote:
> On 08/16/2013 01:33 PM, Jonathan Cameron wrote:
> > Ah, fixes-togreg is for this cycle, whereas new stuff like this needs
> > to go on the togreg branch. Hence please rebase on the togreg branch
> > instead.
>
> But he needs "iio: ti_am335x_adc: Fix wrong samples received on 1st
> read" from that branch. How should the rebase be done?
>
> Sebastian
First line of cover letter had a note on this..
Should I send that particular fix along with the patch series
so its applied cleanly in the togreg branch.
And then during the merge window things magically happen to
fix this situation?
Thanks
Zubair
^ permalink raw reply
* Re: [PATCH 1/4] input: ti_am335x_tsc: correct step mask update after IRQ
From: Zubair Lutfullah : @ 2013-08-16 21:42 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Zubair Lutfullah, jic23, dmitry.torokhov, sameo, lee.jones,
linux-iio, linux-input, linux-kernel, gregkh, Russ.Dill
In-Reply-To: <20130816085350.GA26895@linutronix.de>
On Fri, Aug 16, 2013 at 10:53:50AM +0200, Sebastian Andrzej Siewior wrote:
> * Zubair Lutfullah | 2013-08-13 17:48:16 [+0100]:
>
> >@@ -316,7 +318,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
> >
> > if (irqclr) {
> > titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
> >- am335x_tsc_se_update(ts_dev->mfd_tscadc);
> >+ am335x_tsc_se_set(ts_dev->mfd_tscadc, ts_dev->step_mask);
> > return IRQ_HANDLED;
> > }
> > return IRQ_NONE;
>
> titsc_step_config() computes the mask once since it does not change. It
> is then assigned via am335x_tsc_se_set() to ->reg_se_cache() and later
> always udpated via am335x_tsc_se_update(). This should ensure that ADC's
> and TSC's bits are in sync and clear each other out.
> Now you call am335x_tsc_se_set() in every irq which adds the TSC's mask
> to ->reg_se_cache but why? It was never removed.
>
> Sebastian
The problem is when ADC/TSC are used together.
reg_se_cache would get updated with masks in the se_set function in MFD core.
>From TSC driver, the TSC steps would be set in the reg_se_cache variable.
>From ADC driver, the ADC steps would be set in the reg_se_cache variable.
But the ADC masks weren't being cleared from the reg_se_cache variable
anywhere.
After a while of using ADC/TSC together, the reg_se_cache
variable would have FFFF always. Resulting in redundant sampling
and data in ADC FIFO0.
MFD has received fixes to update the reg_se_cache upon
every call to the se_set functions.
Thus, the step_mask must be set every time to ensure
that it is updated correctly every time.
Hope that clears the confusion.
This TSC/ADC sharing can be pretty confusing.
Thanks
Zubair
^ permalink raw reply
* Re: [PATCH v2 1/2] input: document gamepad API and add extra keycodes
From: David Herrmann @ 2013-08-16 21:39 UTC (permalink / raw)
To: Jiri Kosina; +Cc: Dmitry Torokhov, open list:HID CORE LAYER, linux-kernel
In-Reply-To: <alpine.LNX.2.00.1306271147150.3538@pobox.suse.cz>
Hi Jiri
On Thu, Jun 27, 2013 at 11:47 AM, Jiri Kosina <jkosina@suse.cz> wrote:
> On Wed, 26 Jun 2013, Dmitry Torokhov wrote:
>
>> On Sat, Jun 15, 2013 at 03:32:44PM +0200, David Herrmann wrote:
>> > --- a/include/uapi/linux/input.h
>> > +++ b/include/uapi/linux/input.h
>> > @@ -507,10 +507,14 @@ struct input_keymap_entry {
>> >
>> > #define BTN_GAMEPAD 0x130
>> > #define BTN_A 0x130
>> > +#define BTN_SOUTH 0x130
>>
>> Could we do:
>>
>> #define BTN_SOUTH 0x130
>> #define BTN_A BTN_SOUTH
>>
>> so that it is clear that BTN_A, BTN_B, etc are legacy definitions and
>> not an accidental typos that need their own key codes.
>
> Makes sense, will do that modification.
>
>> Otherwise:
>>
>> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>
> Thanks Dmitry. Will be taking it (with the above modification) through my
> tree.
Hm, I just noticed that this got merged without the
Documentation/input/gamepad.txt description. Was this intentional?
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d09bbfd2a8408a995419dff0d2ba906013cf4cc9
Regards
David
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Zubair Lutfullah : @ 2013-08-16 21:18 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Zubair Lutfullah, jic23, dmitry.torokhov, linux-iio, linux-input,
linux-kernel, gregkh, Russ.Dill
In-Reply-To: <20130816125340.GC1263@linutronix.de>
On Fri, Aug 16, 2013 at 02:53:40PM +0200, Sebastian Andrzej Siewior wrote:
> * Zubair Lutfullah | 2013-08-13 21:05:03 [+0100]:
>
> >diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
> >index 3ceac3e..0d7e313 100644
> >--- a/drivers/iio/adc/ti_am335x_adc.c
> >+++ b/drivers/iio/adc/ti_am335x_adc.c
> >@@ -24,16 +24,28 @@
> …
> >+static irqreturn_t tiadc_irq(int irq, void *private)
> >+{
> >+ struct iio_dev *idev = private;
> >+ struct tiadc_device *adc_dev = iio_priv(idev);
> >+ unsigned int status, config;
> >+ status = tiadc_readl(adc_dev, REG_IRQSTATUS);
> >+
> >+ /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */
> >+ if (status & IRQENB_FIFO1OVRRUN) {
> >+ config = tiadc_readl(adc_dev, REG_CTRL);
> >+ config &= ~(CNTRLREG_TSCSSENB);
> >+ tiadc_writel(adc_dev, REG_CTRL, config);
> >+ tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN |
> >+ IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
> >+ tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
>
> I have no idea how other handle this but shouldn't you somehow inform
> *anyone* that you lost some samples due to this overrun?
>
> Sebastian
The ref manual states that TSCADC module doesn't recover
from overrun interrupts. Thats why the disable enable of
the module here to handle the situation.
And of course, clearing interrupt flags.
The data is lost.
Informing someone about lost samples is important indeed.
But a print statement in this area causes more overruns.
I'm open to some input on how to inform userspace of such
a situation.
Thanks
Zubair
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Zubair Lutfullah : @ 2013-08-16 21:13 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Zubair Lutfullah, jic23, dmitry.torokhov, linux-iio, linux-input,
linux-kernel, gregkh, Russ.Dill
In-Reply-To: <20130816132549.GD1263@linutronix.de>
On Fri, Aug 16, 2013 at 03:25:49PM +0200, Sebastian Andrzej Siewior wrote:
> * Zubair Lutfullah | 2013-08-13 21:05:03 [+0100]:
>
> >diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
> >index 3ceac3e..0d7e313 100644
> >--- a/drivers/iio/adc/ti_am335x_adc.c
> >+++ b/drivers/iio/adc/ti_am335x_adc.c
> >@@ -141,58 +350,51 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
> > {
> …
> >+ if (iio_buffer_enabled(indio_dev))
> >+ return -EBUSY;
> >+ else {
>
> You can drop else so you lose one ident level.
>
Noted.
> >+ unsigned long timeout = jiffies + usecs_to_jiffies
> >+ (IDLE_TIMEOUT * adc_dev->channels);
>
> What computing this once? ->channels is assigned at probe time.
>
The timeout depends on number of SW enabled channels.
Hence the calculation. In this read_raw, one channel is to be
read.
However, all channels are sampled. And the one that the
userspace requires is pushed to user.
> >+ /* Wait for ADC sequencer to complete sampling */
> >+ while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
> >+ if (time_after(jiffies, timeout))
> >+ return -EAGAIN;
>
> You should check the condition after the timeout occured once again. It
> is possible that the task performing the read has been pushed away by a
> higher prio task (or preempted incase this sounds like a bully) and
> after it got back on the cpu the timeout occured but the condition is
> valid and no reason for -EAGAIN.
>
> Sebastian
Interesting catch. I'll look into it.
Thanks for pointing it out.
Zubair
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Zubair Lutfullah : @ 2013-08-16 21:10 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Zubair Lutfullah, jic23, dmitry.torokhov, linux-iio, linux-input,
linux-kernel, gregkh, Russ.Dill
In-Reply-To: <20130816145949.GE1263@linutronix.de>
On Fri, Aug 16, 2013 at 04:59:49PM +0200, Sebastian Andrzej Siewior wrote:
> * Zubair Lutfullah | 2013-08-13 21:05:03 [+0100]:
>
> >diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
> >index 3ceac3e..0d7e313 100644
> >--- a/drivers/iio/adc/ti_am335x_adc.c
> >+++ b/drivers/iio/adc/ti_am335x_adc.c
> …
>
> >+static int tiadc_buffer_postdisable(struct iio_dev *indio_dev)
> >+{
> >+ struct tiadc_device *adc_dev = iio_priv(indio_dev);
> >+ int config;
> >+
> >+ tiadc_step_config(indio_dev);
> >+ if (adc_dev->mfd_tscadc->tsc_cell == -1) {
> >+ config = tiadc_readl(adc_dev, REG_CTRL);
> >+ tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
> >+ }
>
> This kind of check is bad. The tsc cell may have been created but the
> driver not enabled or loaded. Further you should document why you need
> to enable / disable the ADC in this places and only if the TSC part is
> not active.
>
> Sebastian
Noted. I'll look into it.
Thanks for pointing it out.
Zubair
^ permalink raw reply
* [PATCH 2/2] input: misc: New USB eBeam input driver
From: Yann Cantin @ 2013-08-16 20:25 UTC (permalink / raw)
To: linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, jkosina-AlSwsSmVLrQ,
rob-VoJi6FS/r0vR7s880joybQ,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, Yann Cantin
In-Reply-To: <1376684743-25047-1-git-send-email-yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>
Signed-off-by: Yann Cantin <yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>
---
Documentation/ABI/testing/sysfs-driver-ebeam | 53 ++
drivers/input/misc/Kconfig | 22 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/ebeam.c | 763 +++++++++++++++++++++++++++
4 files changed, 839 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-ebeam
create mode 100644 drivers/input/misc/ebeam.c
diff --git a/Documentation/ABI/testing/sysfs-driver-ebeam b/Documentation/ABI/testing/sysfs-driver-ebeam
new file mode 100644
index 0000000..552a428
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-ebeam
@@ -0,0 +1,53 @@
+What: /sys/class/input/inputXX/device/min_x
+ /sys/class/input/inputXX/device/min_y
+ /sys/class/input/inputXX/device/max_x
+ /sys/class/input/inputXX/device/max_y
+Date: Jul 2013
+Kernel Version: 3.11
+Contact: yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org
+ linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+ Reading from these files return the actually used range values of
+ the reported coordinates.
+ Writing to these files preset these range values.
+ See below for the calibration procedure.
+
+What: /sys/class/input/inputXX/device/h[1..9]
+Date: Jul 2013
+Kernel Version: 3.11
+Contact: yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org
+ linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+ Reading from these files return the 3x3 transformation matrix elements
+ actually used, in row-major.
+ Writing to these files preset these elements values.
+ See below for the calibration procedure.
+
+What: /sys/class/input/inputXX/device/calibrated
+Date: Jul 2013
+Kernel Version: 3.11
+Contact: yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org
+ linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+ Reading from this file :
+ - Return 0 if the driver is in "un-calibrated" mode : it actually send
+ raw coordinates in the device's internal coordinates system.
+ - Return 1 if the driver is in "calibrated" mode : it send computed coordinates
+ that (hopefully) matches the screen's coordinates system.
+ Writing 1 to this file enable the "calibrated" mode, 0 reset the driver in
+ "un-calibrated" mode.
+
+Calibration procedure :
+
+When loaded, the driver is in "un-calibrated" mode : it send device's raw coordinates
+in the [0..65535]x[0..65535] range, the transformation matrix is the identity.
+
+A calibration program have to compute a homography transformation matrix that convert
+the device's raw coordinates to the matching screen's ones.
+It then write to the appropriate sysfs files the computed values, pre-setting the
+driver's parameters : xy range, and the matrix's elements.
+When all values are passed, it write 1 to the calibrated sysfs file to enable the "calibrated" mode.
+
+Warning : The parameters aren't used until 1 is writen to the calibrated sysfs file.
+
+Writing 0 to the calibrated sysfs file reset the driver in "un-calibrated" mode.
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0b541cd..454df2d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -93,6 +93,28 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_EBEAM_USB
+ tristate "USB eBeam driver"
+ depends on USB_ARCH_HAS_HCD
+ select USB
+ help
+ Say Y here if you have a USB eBeam pointing device and want to
+ use it without any proprietary user space tools.
+
+ Have a look at <http://sourceforge.net/projects/ebeam/> for
+ a usage description and the required user-space tools.
+
+ Supported devices :
+ - Luidia eBeam Classic Projection and eBeam Edge Projection
+ - Nec NP01Wi1 & NP01Wi2 interactive solution
+
+ Supposed working devices, need test, may lack functionnality :
+ - Luidia eBeam Edge Whiteboard and eBeam Engage
+ - Hitachi Starboard FX-63, FX-77, FX-82, FX-77GII
+
+ To compile this driver as a module, choose M here: the
+ module will be called ebeam.
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 829de43..dd2fe33 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
+obj-$(CONFIG_INPUT_EBEAM_USB) += ebeam.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
diff --git a/drivers/input/misc/ebeam.c b/drivers/input/misc/ebeam.c
new file mode 100644
index 0000000..cf551ab
--- /dev/null
+++ b/drivers/input/misc/ebeam.c
@@ -0,0 +1,763 @@
+/******************************************************************************
+ *
+ * eBeam driver
+ *
+ * Copyright (C) 2012 Yann Cantin (yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * based on
+ *
+ * usbtouchscreen.c by Daniel Ritz <daniel.ritz-OI3hZJvNYWs@public.gmane.org>
+ * aiptek.c (sysfs/settings) by Chris Atenasio <chris-v4AJ0sPprEc@public.gmane.org>
+ * Bryan W. Headley <bwheadley-ihVZJaRskl1bRRN4PJnoQQ@public.gmane.org>
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/math64.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_AUTHOR "Yann Cantin <yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>"
+#define DRIVER_DESC "USB eBeam Driver"
+
+/* Common values for eBeam devices */
+#define REPT_SIZE 8 /* packet size */
+#define MIN_RAW_X 0 /* raw coordinates ranges */
+#define MAX_RAW_X 0xFFFF
+#define MIN_RAW_Y 0
+#define MAX_RAW_Y 0xFFFF
+
+
+#define USB_VENDOR_ID_EFI 0x2650 /* Electronics For Imaging, Inc */
+#define USB_DEVICE_ID_EFI_EBEAM 0x1311 /* eBeam hardware : */
+ /* Luidia Classic and Edge */
+ /* Nec NP01Wi1 & NP01Wi2 */
+
+#define EBEAM_BTN_TIP 0x1 /* tip */
+#define EBEAM_BTN_LIT 0x2 /* little */
+#define EBEAM_BTN_BIG 0x4 /* big */
+
+/* ebeam settings */
+struct ebeam_settings {
+ int min_x; /* computed coordinates ranges for the input layer */
+ int max_x;
+ int min_y;
+ int max_y;
+
+ /* H matrix */
+ s64 h1;
+ s64 h2;
+ s64 h3;
+ s64 h4;
+ s64 h5;
+ s64 h6;
+ s64 h7;
+ s64 h8;
+ s64 h9;
+};
+
+/* ebeam device */
+struct ebeam_device {
+ unsigned char *data;
+ dma_addr_t data_dma;
+ unsigned char *buffer;
+ int buf_len;
+ struct urb *irq;
+ struct usb_interface *interface;
+ struct input_dev *input;
+ char name[128];
+ char phys[64];
+ void *priv;
+
+ struct ebeam_settings cursetting; /* device's current settings */
+ struct ebeam_settings newsetting; /* ... and new ones */
+
+ bool calibrated; /* false : send raw */
+ /* true : send computed */
+
+ u16 raw_x, raw_y; /* raw coordinates */
+ int x, y; /* computed coordinates */
+ int btn_map; /* internal buttons map */
+};
+
+/* device types */
+enum {
+ DEVTYPE_EBEAM,
+};
+
+static const struct usb_device_id ebeam_devices[] = {
+ {USB_DEVICE(USB_VENDOR_ID_EFI, USB_DEVICE_ID_EFI_EBEAM),
+ .driver_info = DEVTYPE_EBEAM},
+ {}
+};
+
+static void ebeam_init_settings(struct ebeam_device *ebeam)
+{
+ ebeam->calibrated = false;
+
+ /* Init (x,y) min/max to raw ones */
+ ebeam->cursetting.min_x = ebeam->newsetting.min_x = MIN_RAW_X;
+ ebeam->cursetting.max_x = ebeam->newsetting.max_x = MAX_RAW_X;
+ ebeam->cursetting.min_y = ebeam->newsetting.min_y = MIN_RAW_Y;
+ ebeam->cursetting.max_y = ebeam->newsetting.max_y = MAX_RAW_Y;
+
+ /* Safe values for the H matrix (Identity) */
+ ebeam->cursetting.h1 = ebeam->newsetting.h1 = 1;
+ ebeam->cursetting.h2 = ebeam->newsetting.h2 = 0;
+ ebeam->cursetting.h3 = ebeam->newsetting.h3 = 0;
+
+ ebeam->cursetting.h4 = ebeam->newsetting.h4 = 0;
+ ebeam->cursetting.h5 = ebeam->newsetting.h5 = 1;
+ ebeam->cursetting.h6 = ebeam->newsetting.h6 = 0;
+
+ ebeam->cursetting.h7 = ebeam->newsetting.h7 = 0;
+ ebeam->cursetting.h8 = ebeam->newsetting.h8 = 0;
+ ebeam->cursetting.h9 = ebeam->newsetting.h9 = 1;
+}
+
+static void ebeam_setup_input(struct ebeam_device *ebeam,
+ struct input_dev *input_dev)
+{
+ unsigned long flags;
+
+ /* Take event lock while modifying parameters */
+ spin_lock_irqsave(&input_dev->event_lock, flags);
+
+ /* Properties */
+ set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+ /* Events generated */
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(EV_ABS, input_dev->evbit);
+
+ /* Keys */
+ set_bit(BTN_LEFT, input_dev->keybit);
+ set_bit(BTN_MIDDLE, input_dev->keybit);
+ set_bit(BTN_RIGHT, input_dev->keybit);
+
+ /* Axis */
+ if (!ebeam->calibrated) {
+ ebeam->cursetting.min_x = MIN_RAW_X;
+ ebeam->cursetting.max_x = MAX_RAW_X;
+ ebeam->cursetting.min_y = MIN_RAW_Y;
+ ebeam->cursetting.max_y = MAX_RAW_Y;
+ }
+
+ input_set_abs_params(input_dev, ABS_X,
+ ebeam->cursetting.min_x, ebeam->cursetting.max_x,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ ebeam->cursetting.min_y, ebeam->cursetting.max_y,
+ 0, 0);
+
+ spin_unlock_irqrestore(&input_dev->event_lock, flags);
+}
+
+/*******************************************************************************
+ * sysfs part
+ */
+
+/*
+ * screen min/max and H matrix coefs
+ * _get return *current* value
+ * _set set new value
+ */
+#define DEVICE_MINMAX_ATTR(MM) \
+static ssize_t ebeam_##MM##_get(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ebeam_device *ebeam = dev_get_drvdata(dev); \
+ \
+ return snprintf(buf, PAGE_SIZE, "%d\n", ebeam->cursetting.MM); \
+} \
+static ssize_t ebeam_##MM##_set(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, \
+ size_t count) \
+{ \
+ struct ebeam_device *ebeam = dev_get_drvdata(dev); \
+ int err, MM; \
+ \
+ err = kstrtoint(buf, 10, &MM); \
+ if (err) \
+ return err; \
+ \
+ ebeam->newsetting.MM = MM; \
+ return count; \
+} \
+static DEVICE_ATTR(MM, S_IRUGO | S_IWUGO, \
+ ebeam_##MM##_get, \
+ ebeam_##MM##_set)
+
+DEVICE_MINMAX_ATTR(min_x);
+DEVICE_MINMAX_ATTR(max_x);
+DEVICE_MINMAX_ATTR(min_y);
+DEVICE_MINMAX_ATTR(max_y);
+
+#define DEVICE_H_ATTR(SET_ID) \
+static ssize_t ebeam_h##SET_ID##_get(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ebeam_device *ebeam = dev_get_drvdata(dev); \
+ \
+ return snprintf(buf, PAGE_SIZE, "%lld\n", ebeam->cursetting.h##SET_ID);\
+} \
+static ssize_t ebeam_h##SET_ID##_set(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, \
+ size_t count) \
+{ \
+ struct ebeam_device *ebeam = dev_get_drvdata(dev); \
+ int err; \
+ u64 h; \
+ \
+ err = kstrtoll(buf, 10, &h); \
+ if (err) \
+ return err; \
+ \
+ ebeam->newsetting.h##SET_ID = h; \
+ return count; \
+} \
+static DEVICE_ATTR(h##SET_ID, S_IRUGO | S_IWUGO, \
+ ebeam_h##SET_ID##_get, \
+ ebeam_h##SET_ID##_set)
+
+DEVICE_H_ATTR(1);
+DEVICE_H_ATTR(2);
+DEVICE_H_ATTR(3);
+DEVICE_H_ATTR(4);
+DEVICE_H_ATTR(5);
+DEVICE_H_ATTR(6);
+DEVICE_H_ATTR(7);
+DEVICE_H_ATTR(8);
+DEVICE_H_ATTR(9);
+
+/*
+ * sysfs calibrated
+ * Once H matrix coefs are set, writing 1 to this file triggers
+ * coordinates mapping.
+ * Anything else reset the device to un-calibrated mode,
+ * storing cursetting in newsetting.
+*/
+static ssize_t ebeam_calibrated_get(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ebeam_device *ebeam = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ebeam->calibrated);
+}
+
+static ssize_t ebeam_calibrated_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct ebeam_device *ebeam = dev_get_drvdata(dev);
+ int err, c;
+
+ err = kstrtoint(buf, 10, &c);
+ if (err)
+ return err;
+
+ if (c == 1) {
+ memcpy(&ebeam->cursetting, &ebeam->newsetting,
+ sizeof(struct ebeam_settings));
+ ebeam->calibrated = true;
+ ebeam_setup_input(ebeam, ebeam->input);
+ } else {
+ memcpy(&ebeam->newsetting, &ebeam->cursetting,
+ sizeof(struct ebeam_settings));
+ ebeam->calibrated = false;
+ ebeam_setup_input(ebeam, ebeam->input);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(calibrated, S_IRUGO | S_IWUGO,
+ ebeam_calibrated_get, ebeam_calibrated_set);
+
+static struct attribute *ebeam_attrs[] = {
+ &dev_attr_min_x.attr,
+ &dev_attr_min_y.attr,
+ &dev_attr_max_x.attr,
+ &dev_attr_max_y.attr,
+ &dev_attr_h1.attr,
+ &dev_attr_h2.attr,
+ &dev_attr_h3.attr,
+ &dev_attr_h4.attr,
+ &dev_attr_h5.attr,
+ &dev_attr_h6.attr,
+ &dev_attr_h7.attr,
+ &dev_attr_h8.attr,
+ &dev_attr_h9.attr,
+ &dev_attr_calibrated.attr,
+ NULL
+};
+
+static const struct attribute_group ebeam_attr_group = {
+ .attrs = ebeam_attrs,
+};
+
+/* IRQ */
+static int ebeam_read_data(struct ebeam_device *ebeam, unsigned char *pkt)
+{
+
+/*
+ * Packet description : 8 bytes
+ *
+ * nop packet : FF FF FF FF FF FF FF FF
+ *
+ * pkt[0] : Sensors
+ * bit 1 : ultrasound signal (guessed)
+ * bit 2 : IR signal (tested with a remote...) ;
+ * readings OK : 0x03 (anything else is a show-stopper)
+ *
+ * pkt[1] : raw_x low
+ * pkt[2] : raw_x high
+ *
+ * pkt[3] : raw_y low
+ * pkt[4] : raw_y high
+ *
+ * pkt[5] : fiability ?
+ * often 0xC0
+ * > 0x80 : OK
+ *
+ * pkt[6] :
+ * buttons state (low 4 bits)
+ * 0x1 = no buttons
+ * bit 0 : tip (WARNING inversed : 0=pressed)
+ * bit 1 : ? (always 0 during tests)
+ * bit 2 : little (1=pressed)
+ * bit 3 : big (1=pressed)
+ *
+ * pointer ID : (high 4 bits)
+ * Tested : 0x6=wand ;
+ * Guessed : 0x1=red ; 0x2=blue ; 0x3=green ; 0x4=black ;
+ * 0x5=eraser
+ * bit 4 : pointer ID
+ * bit 5 : pointer ID
+ * bit 6 : pointer ID
+ * bit 7 : pointer ID
+ *
+ *
+ * pkt[7] : fiability ?
+ * often 0xFF
+ *
+ */
+
+ /* Filtering bad/nop packet */
+ if (pkt[0] != 0x03)
+ return 0;
+
+ ebeam->raw_x = (pkt[2] << 8) | pkt[1];
+ ebeam->raw_y = (pkt[4] << 8) | pkt[3];
+
+ ebeam->btn_map = (!(pkt[6] & 0x1)) |
+ ((pkt[6] & 0x4) >> 1) |
+ ((pkt[6] & 0x8) >> 1);
+
+ return 1;
+}
+
+/*
+ * IRQ
+ * compute screen coordinates from raw
+ * Overflow and negative values are ignored
+ */
+static bool ebeam_calculate_xy(struct ebeam_device *ebeam)
+{
+ /* 64-bits divisions handled by div64_s64 */
+
+ s64 scale;
+
+ if (!ebeam->calibrated) {
+ ebeam->x = ebeam->raw_x;
+ ebeam->y = ebeam->raw_y;
+ } else {
+ scale = ebeam->cursetting.h7 * ebeam->raw_x +
+ ebeam->cursetting.h8 * ebeam->raw_y +
+ ebeam->cursetting.h9;
+
+ /* Who want a division by zero in kernel ? */
+ if (scale == 0) {
+ dev_err(&(ebeam->interface)->dev,
+ "%s - Division by zero, wrong calibration.\n",
+ __func__);
+ dev_err(&(ebeam->interface)->dev,
+ "%s - Resetting to un-calibrated mode.\n",
+ __func__);
+ ebeam->calibrated = false;
+ return 0;
+ }
+
+ /*
+ * We *must* round the result, but can't do (int) (v1/v2 + 0.5)
+ *
+ * (int) (v1/v2 + 0.5) <=> (int) ( (2*v1 + v2)/(2*v2) )
+ */
+ ebeam->x =
+ (int) div64_s64((((ebeam->cursetting.h1 * ebeam->raw_x +
+ ebeam->cursetting.h2 * ebeam->raw_y +
+ ebeam->cursetting.h3) << 1) + scale),
+ (scale << 1));
+ ebeam->y =
+ (int) div64_s64((((ebeam->cursetting.h4 * ebeam->raw_x +
+ ebeam->cursetting.h5 * ebeam->raw_y +
+ ebeam->cursetting.h6) << 1) + scale),
+ (scale << 1));
+
+ /* check range */
+ if ((ebeam->x < ebeam->cursetting.min_x) ||
+ (ebeam->x > ebeam->cursetting.max_x) ||
+ (ebeam->y < ebeam->cursetting.min_y) ||
+ (ebeam->y > ebeam->cursetting.max_y))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* IRQ */
+static void ebeam_report_input(struct ebeam_device *ebeam)
+{
+ input_report_key(ebeam->input, BTN_LEFT,
+ (ebeam->btn_map & EBEAM_BTN_TIP));
+ input_report_key(ebeam->input, BTN_MIDDLE,
+ (ebeam->btn_map & EBEAM_BTN_LIT));
+ input_report_key(ebeam->input, BTN_RIGHT,
+ (ebeam->btn_map & EBEAM_BTN_BIG));
+
+ input_report_abs(ebeam->input, ABS_X, ebeam->x);
+ input_report_abs(ebeam->input, ABS_Y, ebeam->y);
+
+ input_sync(ebeam->input);
+}
+
+/* IRQ */
+static void ebeam_process_pkt(struct ebeam_device *ebeam,
+ unsigned char *pkt, int len)
+{
+ if (!ebeam_read_data(ebeam, pkt))
+ return;
+
+ if (!ebeam_calculate_xy(ebeam))
+ return;
+
+ ebeam_report_input(ebeam);
+}
+
+/* IRQ
+ * handler */
+static void ebeam_irq(struct urb *urb)
+{
+ struct ebeam_device *ebeam = urb->context;
+ struct device *dev = &ebeam->interface->dev;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ETIME:
+ /* this urb is timing out */
+ dev_dbg(dev,
+ "%s - urb timed out - was the device unplugged?\n",
+ __func__);
+ return;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EPIPE:
+ /* this urb is terminated, clean up */
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
+ return;
+ default:
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
+ goto exit;
+ }
+
+ ebeam_process_pkt(ebeam, ebeam->data, urb->actual_length);
+
+exit:
+ usb_mark_last_busy(interface_to_usbdev(ebeam->interface));
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
+}
+
+static int ebeam_open(struct input_dev *input)
+{
+ struct ebeam_device *ebeam = input_get_drvdata(input);
+ int r;
+
+ ebeam->irq->dev = interface_to_usbdev(ebeam->interface);
+
+ r = usb_autopm_get_interface(ebeam->interface) ? -EIO : 0;
+ if (r < 0)
+ goto out;
+
+ if (usb_submit_urb(ebeam->irq, GFP_KERNEL)) {
+ r = -EIO;
+ goto out_put;
+ }
+
+ ebeam->interface->needs_remote_wakeup = 1;
+out_put:
+ usb_autopm_put_interface(ebeam->interface);
+out:
+ return r;
+}
+
+static void ebeam_close(struct input_dev *input)
+{
+ struct ebeam_device *ebeam = input_get_drvdata(input);
+ int r;
+
+ usb_kill_urb(ebeam->irq);
+
+ r = usb_autopm_get_interface(ebeam->interface);
+ ebeam->interface->needs_remote_wakeup = 0;
+
+ if (!r)
+ usb_autopm_put_interface(ebeam->interface);
+}
+
+static int ebeam_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ebeam_device *ebeam = usb_get_intfdata(intf);
+
+ usb_kill_urb(ebeam->irq);
+
+ return 0;
+}
+
+static int ebeam_resume(struct usb_interface *intf)
+{
+ struct ebeam_device *ebeam = usb_get_intfdata(intf);
+ struct input_dev *input = ebeam->input;
+ int result = 0;
+
+ mutex_lock(&input->mutex);
+ if (input->users)
+ result = usb_submit_urb(ebeam->irq, GFP_NOIO);
+ mutex_unlock(&input->mutex);
+
+ return result;
+}
+
+static int ebeam_reset_resume(struct usb_interface *intf)
+{
+ return ebeam_resume(intf);
+}
+
+static void ebeam_free_buffers(struct usb_device *udev,
+ struct ebeam_device *ebeam)
+{
+ usb_free_coherent(udev, REPT_SIZE,
+ ebeam->data, ebeam->data_dma);
+ kfree(ebeam->buffer);
+}
+
+static struct usb_endpoint_descriptor *
+ebeam_get_input_endpoint(struct usb_host_interface *interface)
+{
+ int i;
+
+ for (i = 0; i < interface->desc.bNumEndpoints; i++)
+ if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
+ return &interface->endpoint[i].desc;
+
+ return NULL;
+}
+
+static int ebeam_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct ebeam_device *ebeam;
+ struct input_dev *input_dev;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int err = -ENOMEM;
+
+ endpoint = ebeam_get_input_endpoint(intf->cur_altsetting);
+ if (!endpoint)
+ return -ENXIO;
+
+ ebeam = kzalloc(sizeof(struct ebeam_device), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ebeam || !input_dev)
+ goto out_free;
+
+ ebeam_init_settings(ebeam);
+
+ ebeam->data = usb_alloc_coherent(udev, REPT_SIZE,
+ GFP_KERNEL, &ebeam->data_dma);
+ if (!ebeam->data)
+ goto out_free;
+
+ ebeam->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ebeam->irq) {
+ dev_dbg(&intf->dev,
+ "%s - usb_alloc_urb failed: ebeam->irq\n", __func__);
+ goto out_free_buffers;
+ }
+
+ ebeam->interface = intf;
+ ebeam->input = input_dev;
+
+ /* setup name */
+ snprintf(ebeam->name, sizeof(ebeam->name),
+ "USB eBeam %04x:%04x",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ if (udev->manufacturer || udev->product) {
+ strlcat(ebeam->name,
+ " (",
+ sizeof(ebeam->name));
+
+ if (udev->manufacturer)
+ strlcat(ebeam->name,
+ udev->manufacturer,
+ sizeof(ebeam->name));
+
+ if (udev->product) {
+ if (udev->manufacturer)
+ strlcat(ebeam->name,
+ " ",
+ sizeof(ebeam->name));
+ strlcat(ebeam->name,
+ udev->product,
+ sizeof(ebeam->name));
+ }
+
+ if (strlcat(ebeam->name, ")", sizeof(ebeam->name))
+ >= sizeof(ebeam->name)) {
+ /* overflowed, closing ) anyway */
+ ebeam->name[sizeof(ebeam->name)-2] = ')';
+ }
+ }
+
+ /* usb tree */
+ usb_make_path(udev, ebeam->phys, sizeof(ebeam->phys));
+ strlcat(ebeam->phys, "/input0", sizeof(ebeam->phys));
+
+ /* input setup */
+ input_dev->name = ebeam->name;
+ input_dev->phys = ebeam->phys;
+ usb_to_input_id(udev, &input_dev->id);
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, ebeam);
+
+ input_dev->open = ebeam_open;
+ input_dev->close = ebeam_close;
+
+ /* usb urb setup */
+ if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
+ usb_fill_int_urb(ebeam->irq, udev,
+ usb_rcvintpipe(udev, endpoint->bEndpointAddress),
+ ebeam->data, REPT_SIZE,
+ ebeam_irq, ebeam, endpoint->bInterval);
+ else
+ usb_fill_bulk_urb(ebeam->irq, udev,
+ usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
+ ebeam->data, REPT_SIZE,
+ ebeam_irq, ebeam);
+
+ ebeam->irq->dev = udev;
+ ebeam->irq->transfer_dma = ebeam->data_dma;
+ ebeam->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ /* input final setup */
+ ebeam_setup_input(ebeam, input_dev);
+
+ err = input_register_device(ebeam->input);
+ if (err) {
+ dev_dbg(&intf->dev,
+ "%s - input_register_device failed, err: %d\n",
+ __func__, err);
+ goto out_free_urb;
+ }
+
+ /* usb final setup */
+ usb_set_intfdata(intf, ebeam);
+
+ /* sysfs setup */
+ err = sysfs_create_group(&intf->dev.kobj, &ebeam_attr_group);
+ if (err) {
+ dev_dbg(&intf->dev,
+ "%s - cannot create sysfs group, err: %d\n",
+ __func__, err);
+ goto out_unregister_input;
+ }
+
+ return 0;
+
+out_unregister_input:
+ input_unregister_device(input_dev);
+ input_dev = NULL;
+out_free_urb:
+ usb_free_urb(ebeam->irq);
+out_free_buffers:
+ ebeam_free_buffers(udev, ebeam);
+out_free:
+ input_free_device(input_dev);
+ kfree(ebeam);
+ return err;
+}
+
+static void ebeam_disconnect(struct usb_interface *intf)
+{
+ struct ebeam_device *ebeam = usb_get_intfdata(intf);
+
+ if (!ebeam)
+ return;
+
+ dev_dbg(&intf->dev,
+ "%s - ebeam is initialized, cleaning up\n", __func__);
+
+ usb_set_intfdata(intf, NULL);
+ /* this will stop IO via close */
+ input_unregister_device(ebeam->input);
+ sysfs_remove_group(&intf->dev.kobj, &ebeam_attr_group);
+ usb_free_urb(ebeam->irq);
+ ebeam_free_buffers(interface_to_usbdev(intf), ebeam);
+ kfree(ebeam);
+}
+
+MODULE_DEVICE_TABLE(usb, ebeam_devices);
+
+static struct usb_driver ebeam_driver = {
+ .name = "ebeam",
+ .probe = ebeam_probe,
+ .disconnect = ebeam_disconnect,
+ .suspend = ebeam_suspend,
+ .resume = ebeam_resume,
+ .reset_resume = ebeam_reset_resume,
+ .id_table = ebeam_devices,
+ .supports_autosuspend = 1,
+};
+
+module_usb_driver(ebeam_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
--
1.8.1.5
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 1/2] hid: Blacklist eBeam devices
From: Yann Cantin @ 2013-08-16 20:25 UTC (permalink / raw)
To: linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w, jkosina-AlSwsSmVLrQ,
rob-VoJi6FS/r0vR7s880joybQ,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, Yann Cantin
In-Reply-To: <1376684743-25047-1-git-send-email-yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>
Signed-off-by: Yann Cantin <yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>
---
drivers/hid/hid-core.c | 3 +++
drivers/hid/hid-ids.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 36668d1..da5dfa0 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1985,6 +1985,9 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
+#if defined(CONFIG_INPUT_EBEAM_USB)
+ { HID_USB_DEVICE(USB_VENDOR_ID_EFI, USB_DEVICE_ID_EFI_EBEAM) },
+#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index ffe4c7a..abd1c53 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -288,6 +288,9 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
+#define USB_VENDOR_ID_EFI 0x2650
+#define USB_DEVICE_ID_EFI_EBEAM 0x1311
+
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
--
1.8.1.5
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 0/2] new USB eBeam input driver
From: Yann Cantin @ 2013-08-16 20:25 UTC (permalink / raw)
To: linux-input, linux-usb
Cc: linux-kernel, linux-doc, dmitry.torokhov, jkosina, rob, gregkh
Hi,
New USB input driver for eBeam devices.
Currently supported (tested) :
- Luidia eBeam classic projection and edge projection models
- Nec "interactive solution" NP01Wi1 & NP01Wi2 accessories.
>From basic usb point of view, all these devices are
indistinguishable : they have the same usb ids and (blank) hid
report descriptors. There's other re-branded hardware that need to be
test, but i bet on same ids.
Patch 1 to blacklist the devices for hid generic-usb.
Patch 2 is the actual driver.
Notable stuff :
- use div64_s64 for portable 64/64-bits divisions.
- 13 sysfs custom files : 9 values for the transformation matrix,
4 for xy ranges and a calibration trigger.
The module run fine since 3.3.6 kernel, both x86_32 and 64, actually
run in production on a 3.8.13 and compile without errors on
today's linus tree.
Side note :
- This driver was first submit and discuss last year.
Thanks for your help.
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Sebastian Andrzej Siewior @ 2013-08-16 14:59 UTC (permalink / raw)
To: Zubair Lutfullah
Cc: jic23, dmitry.torokhov, linux-iio, linux-input, linux-kernel,
gregkh, Russ.Dill
In-Reply-To: <1376424303-22740-5-git-send-email-zubair.lutfullah@gmail.com>
* Zubair Lutfullah | 2013-08-13 21:05:03 [+0100]:
>diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
>index 3ceac3e..0d7e313 100644
>--- a/drivers/iio/adc/ti_am335x_adc.c
>+++ b/drivers/iio/adc/ti_am335x_adc.c
…
>+static int tiadc_buffer_postdisable(struct iio_dev *indio_dev)
>+{
>+ struct tiadc_device *adc_dev = iio_priv(indio_dev);
>+ int config;
>+
>+ tiadc_step_config(indio_dev);
>+ if (adc_dev->mfd_tscadc->tsc_cell == -1) {
>+ config = tiadc_readl(adc_dev, REG_CTRL);
>+ tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
>+ }
This kind of check is bad. The tsc cell may have been created but the
driver not enabled or loaded. Further you should document why you need
to enable / disable the ADC in this places and only if the TSC part is
not active.
Sebastian
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Sebastian Andrzej Siewior @ 2013-08-16 13:25 UTC (permalink / raw)
To: Zubair Lutfullah
Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, Russ.Dill-l0cyMroinI0
In-Reply-To: <1376424303-22740-5-git-send-email-zubair.lutfullah-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
* Zubair Lutfullah | 2013-08-13 21:05:03 [+0100]:
>diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
>index 3ceac3e..0d7e313 100644
>--- a/drivers/iio/adc/ti_am335x_adc.c
>+++ b/drivers/iio/adc/ti_am335x_adc.c
>@@ -141,58 +350,51 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
> {
…
>+ if (iio_buffer_enabled(indio_dev))
>+ return -EBUSY;
>+ else {
You can drop else so you lose one ident level.
>+ unsigned long timeout = jiffies + usecs_to_jiffies
>+ (IDLE_TIMEOUT * adc_dev->channels);
What computing this once? ->channels is assigned at probe time.
>+ step_en = get_adc_step_mask(adc_dev);
>+ am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
>+
>+ /* Wait for ADC sequencer to complete sampling */
>+ while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
>+ if (time_after(jiffies, timeout))
>+ return -EAGAIN;
You should check the condition after the timeout occured once again. It
is possible that the task performing the read has been pushed away by a
higher prio task (or preempted incase this sounds like a bully) and
after it got back on the cpu the timeout occured but the condition is
valid and no reason for -EAGAIN.
>+ }
and the bracket needs to left by one tab.
Sebastian
^ permalink raw reply
* Re: [PATCH 4/4] iio: ti_am335x_adc: Add continuous sampling and trigger support
From: Sebastian Andrzej Siewior @ 2013-08-16 12:53 UTC (permalink / raw)
To: Zubair Lutfullah
Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, Russ.Dill-l0cyMroinI0
In-Reply-To: <1376424303-22740-5-git-send-email-zubair.lutfullah-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
* Zubair Lutfullah | 2013-08-13 21:05:03 [+0100]:
>diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
>index 3ceac3e..0d7e313 100644
>--- a/drivers/iio/adc/ti_am335x_adc.c
>+++ b/drivers/iio/adc/ti_am335x_adc.c
>@@ -24,16 +24,28 @@
…
>+static irqreturn_t tiadc_irq(int irq, void *private)
>+{
>+ struct iio_dev *idev = private;
>+ struct tiadc_device *adc_dev = iio_priv(idev);
>+ unsigned int status, config;
>+ status = tiadc_readl(adc_dev, REG_IRQSTATUS);
>+
>+ /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */
>+ if (status & IRQENB_FIFO1OVRRUN) {
>+ config = tiadc_readl(adc_dev, REG_CTRL);
>+ config &= ~(CNTRLREG_TSCSSENB);
>+ tiadc_writel(adc_dev, REG_CTRL, config);
>+ tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN |
>+ IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
>+ tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
I have no idea how other handle this but shouldn't you somehow inform
*anyone* that you lost some samples due to this overrun?
>+ } else if (status & IRQENB_FIFO1THRES) {
>+ /* Wake adc_work that pushes FIFO data to iio buffer */
>+ tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES);
>+ adc_dev->data_avail = 1;
>+ wake_up_interruptible(&adc_dev->wq_data_avail);
>+ } else
>+ return IRQ_NONE;
Sebastian
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox