Merge branch 'next' into for-linus
Prepare input updates for 4.11 merge window.
This commit is contained in:
Коммит
6e11617fcf
|
@ -0,0 +1,27 @@
|
|||
Samsung tm2-touchkey
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "cypress,tm2-touchkey"
|
||||
- reg: I2C address of the chip.
|
||||
- interrupt-parent: a phandle for the interrupt controller (see interrupt
|
||||
binding[0]).
|
||||
- interrupts: interrupt to which the chip is connected (see interrupt
|
||||
binding[0]).
|
||||
- vcc-supply : internal regulator output. 1.8V
|
||||
- vdd-supply : power supply for IC 3.3V
|
||||
|
||||
[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Example:
|
||||
&i2c0 {
|
||||
/* ... */
|
||||
|
||||
touchkey@20 {
|
||||
compatible = "cypress,tm2-touchkey";
|
||||
reg = <0x20>;
|
||||
interrupt-parent = <&gpa3>;
|
||||
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
|
||||
vcc-supply=<&ldo32_reg>;
|
||||
vdd-supply=<&ldo33_reg>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
* Freescale MPR121 Controllor
|
||||
|
||||
Required Properties:
|
||||
- compatible: Should be "fsl,mpr121-touchkey"
|
||||
- reg: The I2C slave address of the device.
|
||||
- interrupts: The interrupt number to the cpu.
|
||||
- vdd-supply: Phandle to the Vdd power supply.
|
||||
- linux,keycodes: Specifies an array of numeric keycode values to
|
||||
be used for reporting button presses. The array can
|
||||
contain up to 12 entries.
|
||||
|
||||
Optional Properties:
|
||||
- wakeup-source: Use any event on keypad as wakeup event.
|
||||
- autorepeat: Enable autorepeat feature.
|
||||
|
||||
Example:
|
||||
|
||||
#include "dt-bindings/input/input.h"
|
||||
|
||||
touchkey: mpr121@5a {
|
||||
compatible = "fsl,mpr121-touchkey";
|
||||
reg = <0x5a>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <28 2>;
|
||||
autorepeat;
|
||||
vdd-supply = <&ldo4_reg>;
|
||||
linux,keycodes = <KEY_0>, <KEY_1>, <KEY_2>, <KEY_3>,
|
||||
<KEY_4> <KEY_5>, <KEY_6>, <KEY_7>,
|
||||
<KEY_8>, <KEY_9>, <KEY_A>, <KEY_B>;
|
||||
};
|
|
@ -5,3 +5,19 @@ Registers a PWM device as beeper.
|
|||
Required properties:
|
||||
- compatible: should be "pwm-beeper"
|
||||
- pwms: phandle to the physical PWM device
|
||||
|
||||
Optional properties:
|
||||
- amp-supply: phandle to a regulator that acts as an amplifier for the beeper
|
||||
|
||||
Example:
|
||||
|
||||
beeper_amp: amplifier {
|
||||
compatible = "fixed-regulator";
|
||||
gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
beeper {
|
||||
compatible = "pwm-beeper";
|
||||
pwms = <&pwm0>;
|
||||
amp-supply = <&beeper_amp>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
Zeitec ZET6223 I2C touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "zeitec,zet6223"
|
||||
- reg : I2C slave address of the chip (0x76)
|
||||
- interrupt-parent : a phandle pointing to the interrupt controller
|
||||
serving the interrupt for this chip
|
||||
- interrupts : interrupt specification for the zet6223 interrupt
|
||||
|
||||
Optional properties:
|
||||
|
||||
- vio-supply : Specification for VIO supply (1.8V or 3.3V,
|
||||
depending on system interface needs).
|
||||
- vcc-supply : Specification for 3.3V VCC supply.
|
||||
- touchscreen-size-x : See touchscreen.txt
|
||||
- touchscreen-size-y : See touchscreen.txt
|
||||
- touchscreen-inverted-x : See touchscreen.txt
|
||||
- touchscreen-inverted-y : See touchscreen.txt
|
||||
- touchscreen-swapped-x-y : See touchscreen.txt
|
||||
|
||||
Example:
|
||||
|
||||
i2c@00000000 {
|
||||
|
||||
zet6223: touchscreen@76 {
|
||||
compatible = "zeitec,zet6223";
|
||||
reg = <0x76>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>
|
||||
};
|
||||
|
||||
};
|
|
@ -329,6 +329,7 @@ xes Extreme Engineering Solutions (X-ES)
|
|||
xillybus Xillybus Ltd.
|
||||
xlnx Xilinx
|
||||
zarlink Zarlink Semiconductor
|
||||
zeitec ZEITEC Semiconductor Co., LTD.
|
||||
zii Zodiac Inflight Innovations
|
||||
zte ZTE Corp.
|
||||
zyxel ZyXEL Communications Corp.
|
||||
|
|
|
@ -94,7 +94,6 @@ comment "Userland interfaces"
|
|||
|
||||
config INPUT_MOUSEDEV
|
||||
tristate "Mouse interface"
|
||||
default y
|
||||
help
|
||||
Say Y here if you want your mouse to be accessible as char devices
|
||||
13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
|
||||
|
@ -109,7 +108,6 @@ config INPUT_MOUSEDEV
|
|||
|
||||
config INPUT_MOUSEDEV_PSAUX
|
||||
bool "Provide legacy /dev/psaux device"
|
||||
default y
|
||||
depends on INPUT_MOUSEDEV
|
||||
help
|
||||
Say Y here if you want your mouse also be accessible as char device
|
||||
|
@ -118,7 +116,6 @@ config INPUT_MOUSEDEV_PSAUX
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
|
||||
config INPUT_MOUSEDEV_SCREEN_X
|
||||
int "Horizontal screen resolution"
|
||||
depends on INPUT_MOUSEDEV
|
||||
|
|
|
@ -1749,7 +1749,7 @@ static const struct dev_pm_ops input_dev_pm_ops = {
|
|||
};
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct device_type input_dev_type = {
|
||||
static const struct device_type input_dev_type = {
|
||||
.groups = input_dev_attr_groups,
|
||||
.release = input_dev_release,
|
||||
.uevent = input_dev_uevent,
|
||||
|
@ -2091,6 +2091,12 @@ int input_register_device(struct input_dev *dev)
|
|||
const char *path;
|
||||
int error;
|
||||
|
||||
if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
|
||||
dev_err(&dev->dev,
|
||||
"Absolute device without dev->absinfo, refusing to register\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dev->devres_managed) {
|
||||
devres = devres_alloc(devm_input_device_unregister,
|
||||
sizeof(struct input_devres), GFP_KERNEL);
|
||||
|
|
|
@ -87,7 +87,7 @@ static int joydev_correct(int value, struct js_corr *corr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
|
||||
return clamp(value, -32767, 32767);
|
||||
}
|
||||
|
||||
static void joydev_pass_event(struct joydev_client *client,
|
||||
|
@ -187,6 +187,17 @@ static void joydev_detach_client(struct joydev *joydev,
|
|||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static void joydev_refresh_state(struct joydev *joydev)
|
||||
{
|
||||
struct input_dev *dev = joydev->handle.dev;
|
||||
int i, val;
|
||||
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
val = input_abs_get_val(dev, joydev->abspam[i]);
|
||||
joydev->abs[i] = joydev_correct(val, &joydev->corr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int joydev_open_device(struct joydev *joydev)
|
||||
{
|
||||
int retval;
|
||||
|
@ -201,6 +212,8 @@ static int joydev_open_device(struct joydev *joydev)
|
|||
retval = input_open_device(&joydev->handle);
|
||||
if (retval)
|
||||
joydev->open--;
|
||||
else
|
||||
joydev_refresh_state(joydev);
|
||||
}
|
||||
|
||||
mutex_unlock(&joydev->mutex);
|
||||
|
@ -872,7 +885,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
j = joydev->abspam[i];
|
||||
if (input_abs_get_max(dev, j) == input_abs_get_min(dev, j)) {
|
||||
joydev->corr[i].type = JS_CORR_NONE;
|
||||
joydev->abs[i] = input_abs_get_val(dev, j);
|
||||
continue;
|
||||
}
|
||||
joydev->corr[i].type = JS_CORR_BROKEN;
|
||||
|
@ -887,10 +899,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
|||
if (t) {
|
||||
joydev->corr[i].coef[2] = (1 << 29) / t;
|
||||
joydev->corr[i].coef[3] = (1 << 29) / t;
|
||||
|
||||
joydev->abs[i] =
|
||||
joydev_correct(input_abs_get_val(dev, j),
|
||||
joydev->corr + i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,6 @@ static int probe_maple_controller(struct device *dev)
|
|||
idev->dev.parent = &mdev->dev;
|
||||
idev->name = mdev->product_name;
|
||||
idev->id.bustype = BUS_HOST;
|
||||
input_set_drvdata(idev, pad);
|
||||
|
||||
error = input_register_device(idev);
|
||||
if (error)
|
||||
|
|
|
@ -320,18 +320,18 @@ static struct usb_device_id xpad_table[] = {
|
|||
XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */
|
||||
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */
|
||||
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
|
||||
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
|
||||
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
||||
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
|
||||
XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
|
||||
XPAD_XBOX360_VENDOR(0x15e4), /* Numark X-Box 360 controllers */
|
||||
XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
|
||||
XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
||||
XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -389,6 +389,7 @@ struct usb_xpad {
|
|||
|
||||
static int xpad_init_input(struct usb_xpad *xpad);
|
||||
static void xpad_deinit_input(struct usb_xpad *xpad);
|
||||
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
|
||||
|
||||
/*
|
||||
* xpad_process_packet
|
||||
|
@ -608,14 +609,36 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
|
|||
}
|
||||
|
||||
/*
|
||||
* xpadone_process_buttons
|
||||
* xpadone_process_packet
|
||||
*
|
||||
* Process a button update packet from an Xbox one controller.
|
||||
* Completes a request by converting the data into events for the
|
||||
* input subsystem. This version is for the Xbox One controller.
|
||||
*
|
||||
* The report format was gleaned from
|
||||
* https://github.com/kylelemons/xbox/blob/master/xbox.go
|
||||
*/
|
||||
static void xpadone_process_buttons(struct usb_xpad *xpad,
|
||||
struct input_dev *dev,
|
||||
unsigned char *data)
|
||||
static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
|
||||
{
|
||||
struct input_dev *dev = xpad->dev;
|
||||
|
||||
/* the xbox button has its own special report */
|
||||
if (data[0] == 0X07) {
|
||||
/*
|
||||
* The Xbox One S controller requires these reports to be
|
||||
* acked otherwise it continues sending them forever and
|
||||
* won't report further mode button events.
|
||||
*/
|
||||
if (data[1] == 0x30)
|
||||
xpadone_ack_mode_report(xpad, data[2]);
|
||||
|
||||
input_report_key(dev, BTN_MODE, data[4] & 0x01);
|
||||
input_sync(dev);
|
||||
return;
|
||||
}
|
||||
/* check invalid packet */
|
||||
else if (data[0] != 0X20)
|
||||
return;
|
||||
|
||||
/* menu/view buttons */
|
||||
input_report_key(dev, BTN_START, data[4] & 0x04);
|
||||
input_report_key(dev, BTN_SELECT, data[4] & 0x08);
|
||||
|
@ -678,34 +701,6 @@ static void xpadone_process_buttons(struct usb_xpad *xpad,
|
|||
input_sync(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* xpadone_process_packet
|
||||
*
|
||||
* Completes a request by converting the data into events for the
|
||||
* input subsystem. This version is for the Xbox One controller.
|
||||
*
|
||||
* The report format was gleaned from
|
||||
* https://github.com/kylelemons/xbox/blob/master/xbox.go
|
||||
*/
|
||||
|
||||
static void xpadone_process_packet(struct usb_xpad *xpad,
|
||||
u16 cmd, unsigned char *data)
|
||||
{
|
||||
struct input_dev *dev = xpad->dev;
|
||||
|
||||
switch (data[0]) {
|
||||
case 0x20:
|
||||
xpadone_process_buttons(xpad, dev, data);
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
/* the xbox button has its own special report */
|
||||
input_report_key(dev, BTN_MODE, data[4] & 0x01);
|
||||
input_sync(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void xpad_irq_in(struct urb *urb)
|
||||
{
|
||||
struct usb_xpad *xpad = urb->context;
|
||||
|
@ -850,10 +845,9 @@ static void xpad_irq_out(struct urb *urb)
|
|||
spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
}
|
||||
|
||||
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad,
|
||||
struct usb_endpoint_descriptor *ep_irq_out)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_irq_out;
|
||||
int ep_irq_out_idx;
|
||||
int error;
|
||||
|
||||
if (xpad->xtype == XTYPE_UNKNOWN)
|
||||
|
@ -863,23 +857,17 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
|||
|
||||
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
GFP_KERNEL, &xpad->odata_dma);
|
||||
if (!xpad->odata) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
if (!xpad->odata)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&xpad->odata_lock);
|
||||
|
||||
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!xpad->irq_out) {
|
||||
error = -ENOMEM;
|
||||
goto fail2;
|
||||
goto err_free_coherent;
|
||||
}
|
||||
|
||||
/* Xbox One controller has in/out endpoints swapped. */
|
||||
ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1;
|
||||
ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc;
|
||||
|
||||
usb_fill_int_urb(xpad->irq_out, xpad->udev,
|
||||
usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
|
||||
xpad->odata, XPAD_PKT_LEN,
|
||||
|
@ -889,8 +877,9 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
|||
|
||||
return 0;
|
||||
|
||||
fail2: usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
||||
fail1: return error;
|
||||
err_free_coherent:
|
||||
usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void xpad_stop_output(struct usb_xpad *xpad)
|
||||
|
@ -974,6 +963,30 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct xpad_output_packet *packet =
|
||||
&xpad->out_packets[XPAD_OUT_CMD_IDX];
|
||||
static const u8 mode_report_ack[] = {
|
||||
0x01, 0x20, 0x00, 0x09, 0x00, 0x07, 0x20, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
|
||||
packet->len = sizeof(mode_report_ack);
|
||||
memcpy(packet->data, mode_report_ack, packet->len);
|
||||
packet->data[2] = seq_num;
|
||||
packet->pending = true;
|
||||
|
||||
/* Reset the sequence so we send out the ack now */
|
||||
xpad->last_out_packet = -1;
|
||||
xpad_try_sending_next_out_packet(xpad);
|
||||
|
||||
spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_XPAD_FF
|
||||
static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
{
|
||||
|
@ -1198,6 +1211,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
|
|||
led_cdev = &led->led_cdev;
|
||||
led_cdev->name = led->name;
|
||||
led_cdev->brightness_set = xpad_led_set;
|
||||
led_cdev->flags = LED_CORE_SUSPENDRESUME;
|
||||
|
||||
error = led_classdev_register(&xpad->udev->dev, led_cdev);
|
||||
if (error)
|
||||
|
@ -1468,8 +1482,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_xpad *xpad;
|
||||
struct usb_endpoint_descriptor *ep_irq_in;
|
||||
int ep_irq_in_idx;
|
||||
struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
|
||||
int i, error;
|
||||
|
||||
if (intf->cur_altsetting->desc.bNumEndpoints != 2)
|
||||
|
@ -1539,14 +1552,27 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
|||
goto err_free_in_urb;
|
||||
}
|
||||
|
||||
error = xpad_init_output(intf, xpad);
|
||||
ep_irq_in = ep_irq_out = NULL;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct usb_endpoint_descriptor *ep =
|
||||
&intf->cur_altsetting->endpoint[i].desc;
|
||||
|
||||
if (usb_endpoint_dir_in(ep))
|
||||
ep_irq_in = ep;
|
||||
else
|
||||
ep_irq_out = ep;
|
||||
}
|
||||
|
||||
if (!ep_irq_in || !ep_irq_out) {
|
||||
error = -ENODEV;
|
||||
goto err_free_in_urb;
|
||||
}
|
||||
|
||||
error = xpad_init_output(intf, xpad, ep_irq_out);
|
||||
if (error)
|
||||
goto err_free_in_urb;
|
||||
|
||||
/* Xbox One controller has in/out endpoints swapped. */
|
||||
ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
|
||||
ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc;
|
||||
|
||||
usb_fill_int_urb(xpad->irq_in, udev,
|
||||
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
|
||||
xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
|
||||
|
@ -1662,8 +1688,16 @@ static int xpad_resume(struct usb_interface *intf)
|
|||
retval = xpad360w_start_input(xpad);
|
||||
} else {
|
||||
mutex_lock(&input->mutex);
|
||||
if (input->users)
|
||||
if (input->users) {
|
||||
retval = xpad_start_input(xpad);
|
||||
} else if (xpad->xtype == XTYPE_XBOXONE) {
|
||||
/*
|
||||
* Even if there are no users, we'll send Xbox One pads
|
||||
* the startup sequence so they don't sit there and
|
||||
* blink until somebody opens the input device again.
|
||||
*/
|
||||
retval = xpad_start_xbox_one(xpad);
|
||||
}
|
||||
mutex_unlock(&input->mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -666,6 +666,17 @@ config KEYBOARD_TC3589X
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called tc3589x-keypad.
|
||||
|
||||
config KEYBOARD_TM2_TOUCHKEY
|
||||
tristate "TM2 touchkey support"
|
||||
depends on I2C
|
||||
depends on LEDS_CLASS
|
||||
help
|
||||
Say Y here to enable device driver for tm2-touchkey with
|
||||
LED control for the Exynos5433 TM2 board.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
module will be called tm2-touchkey.
|
||||
|
||||
config KEYBOARD_TWL4030
|
||||
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
|
||||
depends on TWL4030_CORE
|
||||
|
|
|
@ -61,6 +61,7 @@ obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o
|
|||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
|
||||
obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY) += tm2-touchkey.o
|
||||
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
|
||||
|
|
|
@ -148,8 +148,6 @@ static int adc_keys_probe(struct platform_device *pdev)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
platform_set_drvdata(pdev, st);
|
||||
|
||||
poll_dev = devm_input_allocate_polled_device(dev);
|
||||
if (!poll_dev) {
|
||||
dev_err(dev, "failed to allocate input device\n");
|
||||
|
|
|
@ -107,8 +107,6 @@ static int adp5520_keys_probe(struct platform_device *pdev)
|
|||
input->phys = "adp5520-keys/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input_set_drvdata(input, dev);
|
||||
|
||||
input->id.bustype = BUS_I2C;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x5520;
|
||||
|
|
|
@ -213,7 +213,7 @@ static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp)
|
|||
/* Initialize the KPCR Keypad Configuration Register */
|
||||
kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE;
|
||||
|
||||
error = matrix_keypad_parse_of_params(dev, &kp->n_rows, &kp->n_cols);
|
||||
error = matrix_keypad_parse_properties(dev, &kp->n_rows, &kp->n_cols);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse kp params\n");
|
||||
return error;
|
||||
|
@ -352,8 +352,6 @@ static int bcm_kp_probe(struct platform_device *pdev)
|
|||
|
||||
kp->input_dev = input_dev;
|
||||
|
||||
platform_set_drvdata(pdev, kp);
|
||||
|
||||
error = bcm_kp_matrix_key_parse_dt(kp);
|
||||
if (error)
|
||||
return error;
|
||||
|
|
|
@ -268,8 +268,6 @@ static int bfin_kpad_probe(struct platform_device *pdev)
|
|||
input->phys = "bf54x-keys/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input_set_drvdata(input, bf54x_kpad);
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
|
|
|
@ -392,7 +392,6 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
|
|||
return error;
|
||||
|
||||
dev_info(dev, "CAP11XX detected, revision 0x%02x\n", rev);
|
||||
i2c_set_clientdata(i2c_client, priv);
|
||||
node = dev->of_node;
|
||||
|
||||
if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/*
|
||||
* @rows: Number of rows in the keypad
|
||||
* @cols: Number of columns in the keypad
|
||||
|
@ -43,8 +45,9 @@
|
|||
* @valid_keys: bitmap of existing keys for each matrix column
|
||||
* @old_kb_state: bitmap of keys pressed last scan
|
||||
* @dev: Device pointer
|
||||
* @idev: Input device
|
||||
* @ec: Top level ChromeOS device to use to talk to EC
|
||||
* @idev: The input device for the matrix keys.
|
||||
* @bs_idev: The input device for non-matrix buttons and switches (or NULL).
|
||||
* @notifier: interrupt event notifier for transport devices
|
||||
*/
|
||||
struct cros_ec_keyb {
|
||||
|
@ -57,12 +60,64 @@ struct cros_ec_keyb {
|
|||
uint8_t *old_kb_state;
|
||||
|
||||
struct device *dev;
|
||||
struct input_dev *idev;
|
||||
struct cros_ec_device *ec;
|
||||
|
||||
struct input_dev *idev;
|
||||
struct input_dev *bs_idev;
|
||||
struct notifier_block notifier;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* cros_ec_bs_map - Struct mapping Linux keycodes to EC button/switch bitmap
|
||||
* #defines
|
||||
*
|
||||
* @ev_type: The type of the input event to generate (e.g., EV_KEY).
|
||||
* @code: A linux keycode
|
||||
* @bit: A #define like EC_MKBP_POWER_BUTTON or EC_MKBP_LID_OPEN
|
||||
* @inverted: If the #define and EV_SW have opposite meanings, this is true.
|
||||
* Only applicable to switches.
|
||||
*/
|
||||
struct cros_ec_bs_map {
|
||||
unsigned int ev_type;
|
||||
unsigned int code;
|
||||
u8 bit;
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
/* cros_ec_keyb_bs - Map EC button/switch #defines into kernel ones */
|
||||
static const struct cros_ec_bs_map cros_ec_keyb_bs[] = {
|
||||
/* Buttons */
|
||||
{
|
||||
.ev_type = EV_KEY,
|
||||
.code = KEY_POWER,
|
||||
.bit = EC_MKBP_POWER_BUTTON,
|
||||
},
|
||||
{
|
||||
.ev_type = EV_KEY,
|
||||
.code = KEY_VOLUMEUP,
|
||||
.bit = EC_MKBP_VOL_UP,
|
||||
},
|
||||
{
|
||||
.ev_type = EV_KEY,
|
||||
.code = KEY_VOLUMEDOWN,
|
||||
.bit = EC_MKBP_VOL_DOWN,
|
||||
},
|
||||
|
||||
/* Switches */
|
||||
{
|
||||
.ev_type = EV_SW,
|
||||
.code = SW_LID,
|
||||
.bit = EC_MKBP_LID_OPEN,
|
||||
.inverted = true,
|
||||
},
|
||||
{
|
||||
.ev_type = EV_SW,
|
||||
.code = SW_TABLET_MODE,
|
||||
.bit = EC_MKBP_TABLET_MODE,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns true when there is at least one combination of pressed keys that
|
||||
* results in ghosting.
|
||||
|
@ -149,20 +204,33 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
|
|||
input_sync(ckdev->idev);
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_open(struct input_dev *dev)
|
||||
/**
|
||||
* cros_ec_keyb_report_bs - Report non-matrixed buttons or switches
|
||||
*
|
||||
* This takes a bitmap of buttons or switches from the EC and reports events,
|
||||
* syncing at the end.
|
||||
*
|
||||
* @ckdev: The keyboard device.
|
||||
* @ev_type: The input event type (e.g., EV_KEY).
|
||||
* @mask: A bitmap of buttons from the EC.
|
||||
*/
|
||||
static void cros_ec_keyb_report_bs(struct cros_ec_keyb *ckdev,
|
||||
unsigned int ev_type, u32 mask)
|
||||
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
|
||||
struct input_dev *idev = ckdev->bs_idev;
|
||||
int i;
|
||||
|
||||
return blocking_notifier_chain_register(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(cros_ec_keyb_bs); i++) {
|
||||
const struct cros_ec_bs_map *map = &cros_ec_keyb_bs[i];
|
||||
|
||||
static void cros_ec_keyb_close(struct input_dev *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
|
||||
if (map->ev_type != ev_type)
|
||||
continue;
|
||||
|
||||
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
input_event(idev, ev_type, map->code,
|
||||
!!(mask & BIT(map->bit)) ^ map->inverted);
|
||||
}
|
||||
input_sync(idev);
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_work(struct notifier_block *nb,
|
||||
|
@ -170,22 +238,54 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
|
|||
{
|
||||
struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
|
||||
notifier);
|
||||
u32 val;
|
||||
unsigned int ev_type;
|
||||
|
||||
if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
|
||||
switch (ckdev->ec->event_data.event_type) {
|
||||
case EC_MKBP_EVENT_KEY_MATRIX:
|
||||
/*
|
||||
* If EC is not the wake source, discard key state changes
|
||||
* during suspend.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
|
||||
if (ckdev->ec->event_size != ckdev->cols) {
|
||||
dev_err(ckdev->dev,
|
||||
"Discarded incomplete key matrix event.\n");
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
cros_ec_keyb_process(ckdev,
|
||||
ckdev->ec->event_data.data.key_matrix,
|
||||
ckdev->ec->event_size);
|
||||
break;
|
||||
|
||||
case EC_MKBP_EVENT_BUTTON:
|
||||
case EC_MKBP_EVENT_SWITCH:
|
||||
/*
|
||||
* If EC is not the wake source, discard key state
|
||||
* changes during suspend. Switches will be re-checked in
|
||||
* cros_ec_keyb_resume() to be sure nothing is lost.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
|
||||
if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
|
||||
val = get_unaligned_le32(
|
||||
&ckdev->ec->event_data.data.buttons);
|
||||
ev_type = EV_KEY;
|
||||
} else {
|
||||
val = get_unaligned_le32(
|
||||
&ckdev->ec->event_data.data.switches);
|
||||
ev_type = EV_SW;
|
||||
}
|
||||
cros_ec_keyb_report_bs(ckdev, ev_type, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
/*
|
||||
* If EC is not the wake source, discard key state changes during
|
||||
* suspend.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
if (ckdev->ec->event_size != ckdev->cols) {
|
||||
dev_err(ckdev->dev,
|
||||
"Discarded incomplete key matrix event.\n");
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix,
|
||||
ckdev->ec->event_size);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
@ -213,23 +313,229 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev)
|
|||
}
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_probe(struct platform_device *pdev)
|
||||
/**
|
||||
* cros_ec_keyb_info - Wrap the EC command EC_CMD_MKBP_INFO
|
||||
*
|
||||
* This wraps the EC_CMD_MKBP_INFO, abstracting out all of the marshalling and
|
||||
* unmarshalling and different version nonsense into something simple.
|
||||
*
|
||||
* @ec_dev: The EC device
|
||||
* @info_type: Either EC_MKBP_INFO_SUPPORTED or EC_MKBP_INFO_CURRENT.
|
||||
* @event_type: Either EC_MKBP_EVENT_BUTTON or EC_MKBP_EVENT_SWITCH. Actually
|
||||
* in some cases this could be EC_MKBP_EVENT_KEY_MATRIX or
|
||||
* EC_MKBP_EVENT_HOST_EVENT too but we don't use in this driver.
|
||||
* @result: Where we'll store the result; a union
|
||||
* @result_size: The size of the result. Expected to be the size of one of
|
||||
* the elements in the union.
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_info(struct cros_ec_device *ec_dev,
|
||||
enum ec_mkbp_info_type info_type,
|
||||
enum ec_mkbp_event event_type,
|
||||
union ec_response_get_next_data *result,
|
||||
size_t result_size)
|
||||
{
|
||||
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_keyb *ckdev;
|
||||
struct ec_params_mkbp_info *params;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max_t(size_t, result_size,
|
||||
sizeof(*params)), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->command = EC_CMD_MKBP_INFO;
|
||||
msg->version = 1;
|
||||
msg->outsize = sizeof(*params);
|
||||
msg->insize = result_size;
|
||||
params = (struct ec_params_mkbp_info *)msg->data;
|
||||
params->info_type = info_type;
|
||||
params->event_type = event_type;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
dev_warn(ec_dev->dev, "Transfer error %d/%d: %d\n",
|
||||
(int)info_type, (int)event_type, ret);
|
||||
} else if (msg->result == EC_RES_INVALID_VERSION) {
|
||||
/* With older ECs we just return 0 for everything */
|
||||
memset(result, 0, result_size);
|
||||
ret = 0;
|
||||
} else if (msg->result != EC_RES_SUCCESS) {
|
||||
dev_warn(ec_dev->dev, "Error getting info %d/%d: %d\n",
|
||||
(int)info_type, (int)event_type, msg->result);
|
||||
ret = -EPROTO;
|
||||
} else if (ret != result_size) {
|
||||
dev_warn(ec_dev->dev, "Wrong size %d/%d: %d != %zu\n",
|
||||
(int)info_type, (int)event_type,
|
||||
ret, result_size);
|
||||
ret = -EPROTO;
|
||||
} else {
|
||||
memcpy(result, msg->data, result_size);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
kfree(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_query_switches - Query the state of switches and report
|
||||
*
|
||||
* This will ask the EC about the current state of switches and report to the
|
||||
* kernel. Note that we don't query for buttons because they are more
|
||||
* transitory and we'll get an update on the next release / press.
|
||||
*
|
||||
* @ckdev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_query_switches(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ckdev->ec;
|
||||
union ec_response_get_next_data event_data = {};
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_keyb_info(ec_dev, EC_MKBP_INFO_CURRENT,
|
||||
EC_MKBP_EVENT_SWITCH, &event_data,
|
||||
sizeof(event_data.switches));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cros_ec_keyb_report_bs(ckdev, EV_SW,
|
||||
get_unaligned_le32(&event_data.switches));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_resume - Resume the keyboard
|
||||
*
|
||||
* We use the resume notification as a chance to query the EC for switches.
|
||||
*
|
||||
* @dev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static __maybe_unused int cros_ec_keyb_resume(struct device *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
|
||||
|
||||
if (ckdev->bs_idev)
|
||||
return cros_ec_keyb_query_switches(ckdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_register_bs - Register non-matrix buttons/switches
|
||||
*
|
||||
* Handles all the bits of the keyboard driver related to non-matrix buttons
|
||||
* and switches, including asking the EC about which are present and telling
|
||||
* the kernel to expect them.
|
||||
*
|
||||
* If this device has no support for buttons and switches we'll return no error
|
||||
* but the ckdev->bs_idev will remain NULL when this function exits.
|
||||
*
|
||||
* @ckdev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ckdev->ec;
|
||||
struct device *dev = ckdev->dev;
|
||||
struct input_dev *idev;
|
||||
struct device_node *np;
|
||||
union ec_response_get_next_data event_data = {};
|
||||
const char *phys;
|
||||
u32 buttons;
|
||||
u32 switches;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = cros_ec_keyb_info(ec_dev, EC_MKBP_INFO_SUPPORTED,
|
||||
EC_MKBP_EVENT_BUTTON, &event_data,
|
||||
sizeof(event_data.buttons));
|
||||
if (ret)
|
||||
return ret;
|
||||
buttons = get_unaligned_le32(&event_data.buttons);
|
||||
|
||||
ret = cros_ec_keyb_info(ec_dev, EC_MKBP_INFO_SUPPORTED,
|
||||
EC_MKBP_EVENT_SWITCH, &event_data,
|
||||
sizeof(event_data.switches));
|
||||
if (ret)
|
||||
return ret;
|
||||
switches = get_unaligned_le32(&event_data.switches);
|
||||
|
||||
if (!buttons && !switches)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We call the non-matrix buttons/switches 'input1', if present.
|
||||
* Allocate phys before input dev, to ensure correct tear-down
|
||||
* ordering.
|
||||
*/
|
||||
phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input1", ec_dev->phys_name);
|
||||
if (!phys)
|
||||
return -ENOMEM;
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
idev->name = "cros_ec_buttons";
|
||||
idev->phys = phys;
|
||||
__set_bit(EV_REP, idev->evbit);
|
||||
|
||||
idev->id.bustype = BUS_VIRTUAL;
|
||||
idev->id.version = 1;
|
||||
idev->id.product = 0;
|
||||
idev->dev.parent = dev;
|
||||
|
||||
input_set_drvdata(idev, ckdev);
|
||||
ckdev->bs_idev = idev;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cros_ec_keyb_bs); i++) {
|
||||
const struct cros_ec_bs_map *map = &cros_ec_keyb_bs[i];
|
||||
|
||||
if (buttons & BIT(map->bit))
|
||||
input_set_capability(idev, map->ev_type, map->code);
|
||||
}
|
||||
|
||||
ret = cros_ec_keyb_query_switches(ckdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot query switches\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = input_register_device(ckdev->bs_idev);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot register input device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_register_bs - Register matrix keys
|
||||
*
|
||||
* Handles all the bits of the keyboard driver related to matrix keys.
|
||||
*
|
||||
* @ckdev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ckdev->ec;
|
||||
struct device *dev = ckdev->dev;
|
||||
struct input_dev *idev;
|
||||
const char *phys;
|
||||
int err;
|
||||
|
||||
np = pdev->dev.of_node;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
|
||||
if (!ckdev)
|
||||
return -ENOMEM;
|
||||
err = matrix_keypad_parse_of_params(dev, &ckdev->rows, &ckdev->cols);
|
||||
err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -241,27 +547,28 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
|
|||
if (!ckdev->old_kb_state)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* We call the keyboard matrix 'input0'. Allocate phys before input
|
||||
* dev, to ensure correct tear-down ordering.
|
||||
*/
|
||||
phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", ec_dev->phys_name);
|
||||
if (!phys)
|
||||
return -ENOMEM;
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
ckdev->ec = ec;
|
||||
ckdev->notifier.notifier_call = cros_ec_keyb_work;
|
||||
ckdev->dev = dev;
|
||||
dev_set_drvdata(dev, ckdev);
|
||||
|
||||
idev->name = CROS_EC_DEV_NAME;
|
||||
idev->phys = ec->phys_name;
|
||||
idev->phys = phys;
|
||||
__set_bit(EV_REP, idev->evbit);
|
||||
|
||||
idev->id.bustype = BUS_VIRTUAL;
|
||||
idev->id.version = 1;
|
||||
idev->id.product = 0;
|
||||
idev->dev.parent = dev;
|
||||
idev->open = cros_ec_keyb_open;
|
||||
idev->close = cros_ec_keyb_close;
|
||||
|
||||
ckdev->ghost_filter = of_property_read_bool(np,
|
||||
ckdev->ghost_filter = of_property_read_bool(dev->of_node,
|
||||
"google,needs-ghost-filter");
|
||||
|
||||
err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols,
|
||||
|
@ -287,6 +594,57 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_keyb *ckdev;
|
||||
int err;
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
|
||||
if (!ckdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ckdev->ec = ec;
|
||||
ckdev->dev = dev;
|
||||
dev_set_drvdata(dev, ckdev);
|
||||
|
||||
err = cros_ec_keyb_register_matrix(ckdev);
|
||||
if (err) {
|
||||
dev_err(dev, "cannot register matrix inputs: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = cros_ec_keyb_register_bs(ckdev);
|
||||
if (err) {
|
||||
dev_err(dev, "cannot register non-matrix inputs: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ckdev->notifier.notifier_call = cros_ec_keyb_work;
|
||||
err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
if (err) {
|
||||
dev_err(dev, "cannot register notifier: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cros_ec_keyb_of_match[] = {
|
||||
{ .compatible = "google,cros-ec-keyb" },
|
||||
|
@ -295,11 +653,15 @@ static const struct of_device_id cros_ec_keyb_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, cros_ec_keyb_of_match);
|
||||
#endif
|
||||
|
||||
static const SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
|
||||
|
||||
static struct platform_driver cros_ec_keyb_driver = {
|
||||
.probe = cros_ec_keyb_probe,
|
||||
.remove = cros_ec_keyb_remove,
|
||||
.driver = {
|
||||
.name = "cros-ec-keyb",
|
||||
.of_match_table = of_match_ptr(cros_ec_keyb_of_match),
|
||||
.pm = &cros_ec_keyb_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev)
|
|||
struct input_dev *key_dev;
|
||||
struct resource *res, *mem;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_ks_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct davinci_ks_platform_data *pdata = dev_get_platdata(dev);
|
||||
int error, i;
|
||||
|
||||
if (pdata->device_enable) {
|
||||
|
@ -255,7 +255,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev)
|
|||
|
||||
key_dev->name = "davinci_keyscan";
|
||||
key_dev->phys = "davinci_keyscan/input0";
|
||||
key_dev->dev.parent = &pdev->dev;
|
||||
key_dev->dev.parent = dev;
|
||||
key_dev->id.bustype = BUS_HOST;
|
||||
key_dev->id.vendor = 0x0001;
|
||||
key_dev->id.product = 0x0001;
|
||||
|
|
|
@ -36,6 +36,8 @@ struct gpio_button_data {
|
|||
struct input_dev *input;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
unsigned short *code;
|
||||
|
||||
struct timer_list release_timer;
|
||||
unsigned int release_delay; /* in msecs, for IRQ-only buttons */
|
||||
|
||||
|
@ -52,6 +54,7 @@ struct gpio_keys_drvdata {
|
|||
const struct gpio_keys_platform_data *pdata;
|
||||
struct input_dev *input;
|
||||
struct mutex disable_lock;
|
||||
unsigned short *keymap;
|
||||
struct gpio_button_data data[0];
|
||||
};
|
||||
|
||||
|
@ -203,7 +206,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
|
|||
if (only_disabled && !bdata->disabled)
|
||||
continue;
|
||||
|
||||
__set_bit(bdata->button->code, bits);
|
||||
__set_bit(*bdata->code, bits);
|
||||
}
|
||||
|
||||
ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
|
||||
|
@ -254,7 +257,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
|
|||
if (bdata->button->type != type)
|
||||
continue;
|
||||
|
||||
if (test_bit(bdata->button->code, bits) &&
|
||||
if (test_bit(*bdata->code, bits) &&
|
||||
!bdata->button->can_disable) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
|
@ -269,7 +272,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
|
|||
if (bdata->button->type != type)
|
||||
continue;
|
||||
|
||||
if (test_bit(bdata->button->code, bits))
|
||||
if (test_bit(*bdata->code, bits))
|
||||
gpio_keys_disable_button(bdata);
|
||||
else
|
||||
gpio_keys_enable_button(bdata);
|
||||
|
@ -371,7 +374,7 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
|
|||
if (state)
|
||||
input_event(input, type, button->code, button->value);
|
||||
} else {
|
||||
input_event(input, type, button->code, state);
|
||||
input_event(input, type, *bdata->code, state);
|
||||
}
|
||||
input_sync(input);
|
||||
}
|
||||
|
@ -411,7 +414,7 @@ static void gpio_keys_irq_timer(unsigned long _data)
|
|||
|
||||
spin_lock_irqsave(&bdata->lock, flags);
|
||||
if (bdata->key_pressed) {
|
||||
input_event(input, EV_KEY, bdata->button->code, 0);
|
||||
input_event(input, EV_KEY, *bdata->code, 0);
|
||||
input_sync(input);
|
||||
bdata->key_pressed = false;
|
||||
}
|
||||
|
@ -421,7 +424,6 @@ static void gpio_keys_irq_timer(unsigned long _data)
|
|||
static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct gpio_button_data *bdata = dev_id;
|
||||
const struct gpio_keys_button *button = bdata->button;
|
||||
struct input_dev *input = bdata->input;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -433,11 +435,11 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
|
|||
if (bdata->button->wakeup)
|
||||
pm_wakeup_event(bdata->input->dev.parent, 0);
|
||||
|
||||
input_event(input, EV_KEY, button->code, 1);
|
||||
input_event(input, EV_KEY, *bdata->code, 1);
|
||||
input_sync(input);
|
||||
|
||||
if (!bdata->release_delay) {
|
||||
input_event(input, EV_KEY, button->code, 0);
|
||||
input_event(input, EV_KEY, *bdata->code, 0);
|
||||
input_sync(input);
|
||||
goto out;
|
||||
}
|
||||
|
@ -465,12 +467,14 @@ static void gpio_keys_quiesce_key(void *data)
|
|||
|
||||
static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
struct input_dev *input,
|
||||
struct gpio_button_data *bdata,
|
||||
struct gpio_keys_drvdata *ddata,
|
||||
const struct gpio_keys_button *button,
|
||||
int idx,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
const char *desc = button->desc ? button->desc : "gpio_keys";
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_button_data *bdata = &ddata->data[idx];
|
||||
irq_handler_t isr;
|
||||
unsigned long irqflags;
|
||||
int irq;
|
||||
|
@ -514,8 +518,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
|||
if (button->active_low)
|
||||
flags |= GPIOF_ACTIVE_LOW;
|
||||
|
||||
error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
|
||||
desc);
|
||||
error = devm_gpio_request_one(dev, button->gpio, flags, desc);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Failed to request GPIO %d, error %d\n",
|
||||
button->gpio, error);
|
||||
|
@ -577,16 +580,17 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
|||
irqflags = 0;
|
||||
}
|
||||
|
||||
input_set_capability(input, button->type ?: EV_KEY, button->code);
|
||||
bdata->code = &ddata->keymap[idx];
|
||||
*bdata->code = button->code;
|
||||
input_set_capability(input, button->type ?: EV_KEY, *bdata->code);
|
||||
|
||||
/*
|
||||
* Install custom action to cancel release timer and
|
||||
* workqueue item.
|
||||
*/
|
||||
error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
|
||||
error = devm_add_action(dev, gpio_keys_quiesce_key, bdata);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register quiesce action, error: %d\n",
|
||||
dev_err(dev, "failed to register quiesce action, error: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
@ -598,8 +602,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
|||
if (!button->can_disable)
|
||||
irqflags |= IRQF_SHARED;
|
||||
|
||||
error = devm_request_any_context_irq(&pdev->dev, bdata->irq,
|
||||
isr, irqflags, desc, bdata);
|
||||
error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,
|
||||
desc, bdata);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Unable to claim irq %d; error %d\n",
|
||||
bdata->irq, error);
|
||||
|
@ -750,6 +754,12 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ddata->keymap = devm_kcalloc(dev,
|
||||
pdata->nbuttons, sizeof(ddata->keymap[0]),
|
||||
GFP_KERNEL);
|
||||
if (!ddata->keymap)
|
||||
return -ENOMEM;
|
||||
|
||||
input = devm_input_allocate_device(dev);
|
||||
if (!input) {
|
||||
dev_err(dev, "failed to allocate input device\n");
|
||||
|
@ -765,7 +775,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
|||
|
||||
input->name = pdata->name ? : pdev->name;
|
||||
input->phys = "gpio-keys/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->dev.parent = dev;
|
||||
input->open = gpio_keys_open;
|
||||
input->close = gpio_keys_close;
|
||||
|
||||
|
@ -774,25 +784,29 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
|||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0100;
|
||||
|
||||
input->keycode = ddata->keymap;
|
||||
input->keycodesize = sizeof(ddata->keymap[0]);
|
||||
input->keycodemax = pdata->nbuttons;
|
||||
|
||||
/* Enable auto repeat feature of Linux input subsystem */
|
||||
if (pdata->rep)
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
const struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
struct gpio_button_data *bdata = &ddata->data[i];
|
||||
|
||||
if (!dev_get_platdata(dev)) {
|
||||
child = device_get_next_child_node(&pdev->dev, child);
|
||||
child = device_get_next_child_node(dev, child);
|
||||
if (!child) {
|
||||
dev_err(&pdev->dev,
|
||||
dev_err(dev,
|
||||
"missing child device node for entry %d\n",
|
||||
i);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
error = gpio_keys_setup_key(pdev, input, bdata, button, child);
|
||||
error = gpio_keys_setup_key(pdev, input, ddata,
|
||||
button, i, child);
|
||||
if (error) {
|
||||
fwnode_handle_put(child);
|
||||
return error;
|
||||
|
@ -804,7 +818,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
|||
|
||||
fwnode_handle_put(child);
|
||||
|
||||
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||
error = sysfs_create_group(&dev->kobj, &gpio_keys_attr_group);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to export keys/switches, error: %d\n",
|
||||
error);
|
||||
|
@ -818,12 +832,12 @@ static int gpio_keys_probe(struct platform_device *pdev)
|
|||
goto err_remove_group;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, wakeup);
|
||||
device_init_wakeup(dev, wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_group:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||
sysfs_remove_group(&dev->kobj, &gpio_keys_attr_group);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -831,8 +845,6 @@ static int gpio_keys_remove(struct platform_device *pdev)
|
|||
{
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -252,13 +252,13 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
|||
|
||||
size = sizeof(struct gpio_keys_polled_dev) +
|
||||
pdata->nbuttons * sizeof(struct gpio_keys_button_data);
|
||||
bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
bdev = devm_kzalloc(dev, size, GFP_KERNEL);
|
||||
if (!bdev) {
|
||||
dev_err(dev, "no memory for private data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
|
||||
poll_dev = devm_input_allocate_polled_device(dev);
|
||||
if (!poll_dev) {
|
||||
dev_err(dev, "no memory for polled device\n");
|
||||
return -ENOMEM;
|
||||
|
@ -332,7 +332,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
|||
if (button->active_low)
|
||||
flags |= GPIOF_ACTIVE_LOW;
|
||||
|
||||
error = devm_gpio_request_one(&pdev->dev, button->gpio,
|
||||
error = devm_gpio_request_one(dev, button->gpio,
|
||||
flags, button->desc ? : DRV_NAME);
|
||||
if (error) {
|
||||
dev_err(dev,
|
||||
|
@ -365,7 +365,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
|||
bdev->poll_dev = poll_dev;
|
||||
bdev->dev = dev;
|
||||
bdev->pdata = pdata;
|
||||
platform_set_drvdata(pdev, bdev);
|
||||
|
||||
error = input_register_polled_device(poll_dev);
|
||||
if (error) {
|
||||
|
|
|
@ -197,8 +197,6 @@ static int jornada680kbd_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, jornadakbd);
|
||||
|
||||
jornadakbd->poll_dev = poll_dev;
|
||||
|
||||
memcpy(jornadakbd->keymap, jornada_scancodes,
|
||||
|
|
|
@ -145,7 +145,7 @@ static int lpc32xx_parse_dt(struct device *dev,
|
|||
u32 rows = 0, columns = 0;
|
||||
int err;
|
||||
|
||||
err = matrix_keypad_parse_of_params(dev, &rows, &columns);
|
||||
err = matrix_keypad_parse_properties(dev, &rows, &columns);
|
||||
if (err)
|
||||
return err;
|
||||
if (rows != columns) {
|
||||
|
|
|
@ -196,7 +196,6 @@ static int probe_maple_kbd(struct device *dev)
|
|||
__clear_bit(KEY_RESERVED, idev->keybit);
|
||||
|
||||
input_set_capability(idev, EV_MSC, MSC_SCAN);
|
||||
input_set_drvdata(idev, kbd);
|
||||
|
||||
error = input_register_device(idev);
|
||||
if (error)
|
||||
|
|
|
@ -545,8 +545,6 @@ static int matrix_keypad_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
matrix_keypad_free_gpio(keypad);
|
||||
input_unregister_device(keypad->input_dev);
|
||||
kfree(keypad);
|
||||
|
|
|
@ -241,7 +241,6 @@ static int max7359_probe(struct i2c_client *client,
|
|||
/* Initialize MAX7359 */
|
||||
max7359_initialize(client);
|
||||
|
||||
i2c_set_clientdata(client, keypad);
|
||||
device_init_wakeup(&client->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -12,14 +12,16 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c/mpr121_touchkey.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Register definitions */
|
||||
#define ELE_TOUCH_STATUS_0_ADDR 0x0
|
||||
|
@ -59,10 +61,9 @@
|
|||
struct mpr121_touchkey {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
unsigned int key_val;
|
||||
unsigned int statusbits;
|
||||
unsigned int keycount;
|
||||
u16 keycodes[MPR121_MAX_KEY_COUNT];
|
||||
u32 keycodes[MPR121_MAX_KEY_COUNT];
|
||||
};
|
||||
|
||||
struct mpr121_init_register {
|
||||
|
@ -82,12 +83,49 @@ static const struct mpr121_init_register init_reg_table[] = {
|
|||
{ AUTO_CONFIG_CTRL_ADDR, 0x0b },
|
||||
};
|
||||
|
||||
static void mpr121_vdd_supply_disable(void *data)
|
||||
{
|
||||
struct regulator *vdd_supply = data;
|
||||
|
||||
regulator_disable(vdd_supply);
|
||||
}
|
||||
|
||||
static struct regulator *mpr121_vdd_supply_init(struct device *dev)
|
||||
{
|
||||
struct regulator *vdd_supply;
|
||||
int err;
|
||||
|
||||
vdd_supply = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(vdd_supply)) {
|
||||
dev_err(dev, "failed to get vdd regulator: %ld\n",
|
||||
PTR_ERR(vdd_supply));
|
||||
return vdd_supply;
|
||||
}
|
||||
|
||||
err = regulator_enable(vdd_supply);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable vdd regulator: %d\n", err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
err = devm_add_action(dev, mpr121_vdd_supply_disable, vdd_supply);
|
||||
if (err) {
|
||||
regulator_disable(vdd_supply);
|
||||
dev_err(dev, "failed to add disable regulator action: %d\n",
|
||||
err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return vdd_supply;
|
||||
}
|
||||
|
||||
static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct mpr121_touchkey *mpr121 = dev_id;
|
||||
struct i2c_client *client = mpr121->client;
|
||||
struct input_dev *input = mpr121->input_dev;
|
||||
unsigned int key_num, key_val, pressed;
|
||||
unsigned long bit_changed;
|
||||
unsigned int key_num;
|
||||
int reg;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
|
||||
|
@ -105,26 +143,29 @@ static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
|
|||
|
||||
reg &= TOUCH_STATUS_MASK;
|
||||
/* use old press bit to figure out which bit changed */
|
||||
key_num = ffs(reg ^ mpr121->statusbits) - 1;
|
||||
pressed = reg & (1 << key_num);
|
||||
bit_changed = reg ^ mpr121->statusbits;
|
||||
mpr121->statusbits = reg;
|
||||
for_each_set_bit(key_num, &bit_changed, mpr121->keycount) {
|
||||
unsigned int key_val, pressed;
|
||||
|
||||
key_val = mpr121->keycodes[key_num];
|
||||
pressed = reg & BIT(key_num);
|
||||
key_val = mpr121->keycodes[key_num];
|
||||
|
||||
input_event(input, EV_MSC, MSC_SCAN, key_num);
|
||||
input_report_key(input, key_val, pressed);
|
||||
input_event(input, EV_MSC, MSC_SCAN, key_num);
|
||||
input_report_key(input, key_val, pressed);
|
||||
|
||||
dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
|
||||
pressed ? "pressed" : "released");
|
||||
|
||||
}
|
||||
input_sync(input);
|
||||
|
||||
dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
|
||||
pressed ? "pressed" : "released");
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mpr121_phys_init(const struct mpr121_platform_data *pdata,
|
||||
struct mpr121_touchkey *mpr121,
|
||||
struct i2c_client *client)
|
||||
static int mpr121_phys_init(struct mpr121_touchkey *mpr121,
|
||||
struct i2c_client *client, int vdd_uv)
|
||||
{
|
||||
const struct mpr121_init_register *reg;
|
||||
unsigned char usl, lsl, tl, eleconf;
|
||||
|
@ -154,9 +195,9 @@ static int mpr121_phys_init(const struct mpr121_platform_data *pdata,
|
|||
/*
|
||||
* Capacitance on sensing input varies and needs to be compensated.
|
||||
* The internal MPR121-auto-configuration can do this if it's
|
||||
* registers are set properly (based on pdata->vdd_uv).
|
||||
* registers are set properly (based on vdd_uv).
|
||||
*/
|
||||
vdd = pdata->vdd_uv / 1000;
|
||||
vdd = vdd_uv / 1000;
|
||||
usl = ((vdd - 700) * 256) / vdd;
|
||||
lsl = (usl * 65) / 100;
|
||||
tl = (usl * 90) / 100;
|
||||
|
@ -187,72 +228,77 @@ err_i2c_write:
|
|||
static int mpr_touchkey_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct mpr121_platform_data *pdata =
|
||||
dev_get_platdata(&client->dev);
|
||||
struct device *dev = &client->dev;
|
||||
struct regulator *vdd_supply;
|
||||
int vdd_uv;
|
||||
struct mpr121_touchkey *mpr121;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "no platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->keymap || !pdata->keymap_size) {
|
||||
dev_err(&client->dev, "missing keymap data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
|
||||
dev_err(&client->dev, "too many keys defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!client->irq) {
|
||||
dev_err(&client->dev, "irq number should not be zero\n");
|
||||
dev_err(dev, "irq number should not be zero\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mpr121 = devm_kzalloc(&client->dev, sizeof(*mpr121),
|
||||
GFP_KERNEL);
|
||||
vdd_supply = mpr121_vdd_supply_init(dev);
|
||||
if (IS_ERR(vdd_supply))
|
||||
return PTR_ERR(vdd_supply);
|
||||
|
||||
vdd_uv = regulator_get_voltage(vdd_supply);
|
||||
|
||||
mpr121 = devm_kzalloc(dev, sizeof(*mpr121), GFP_KERNEL);
|
||||
if (!mpr121)
|
||||
return -ENOMEM;
|
||||
|
||||
input_dev = devm_input_allocate_device(&client->dev);
|
||||
input_dev = devm_input_allocate_device(dev);
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
mpr121->client = client;
|
||||
mpr121->input_dev = input_dev;
|
||||
mpr121->keycount = pdata->keymap_size;
|
||||
mpr121->keycount = device_property_read_u32_array(dev, "linux,keycodes",
|
||||
NULL, 0);
|
||||
if (mpr121->keycount > MPR121_MAX_KEY_COUNT) {
|
||||
dev_err(dev, "too many keys defined (%d)\n", mpr121->keycount);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = device_property_read_u32_array(dev, "linux,keycodes",
|
||||
mpr121->keycodes,
|
||||
mpr121->keycount);
|
||||
if (error) {
|
||||
dev_err(dev,
|
||||
"failed to read linux,keycode property: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
input_dev->name = "Freescale MPR121 Touchkey";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &client->dev;
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
input_dev->dev.parent = dev;
|
||||
if (device_property_read_bool(dev, "autorepeat"))
|
||||
__set_bit(EV_REP, input_dev->evbit);
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
input_dev->keycode = mpr121->keycodes;
|
||||
input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
|
||||
input_dev->keycodemax = mpr121->keycount;
|
||||
|
||||
for (i = 0; i < pdata->keymap_size; i++) {
|
||||
input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
|
||||
mpr121->keycodes[i] = pdata->keymap[i];
|
||||
}
|
||||
for (i = 0; i < mpr121->keycount; i++)
|
||||
input_set_capability(input_dev, EV_KEY, mpr121->keycodes[i]);
|
||||
|
||||
error = mpr121_phys_init(pdata, mpr121, client);
|
||||
error = mpr121_phys_init(mpr121, client, vdd_uv);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to init register\n");
|
||||
dev_err(dev, "Failed to init register\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||
mpr_touchkey_interrupt,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
client->dev.driver->name, mpr121);
|
||||
error = devm_request_threaded_irq(dev, client->irq, NULL,
|
||||
mpr_touchkey_interrupt,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
dev->driver->name, mpr121);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to register interrupt\n");
|
||||
dev_err(dev, "Failed to register interrupt\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -261,13 +307,13 @@ static int mpr_touchkey_probe(struct i2c_client *client,
|
|||
return error;
|
||||
|
||||
i2c_set_clientdata(client, mpr121);
|
||||
device_init_wakeup(&client->dev, pdata->wakeup);
|
||||
device_init_wakeup(dev,
|
||||
device_property_read_bool(dev, "wakeup-source"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mpr_suspend(struct device *dev)
|
||||
static int __maybe_unused mpr_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
|
@ -279,7 +325,7 @@ static int mpr_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mpr_resume(struct device *dev)
|
||||
static int __maybe_unused mpr_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
|
||||
|
@ -292,7 +338,6 @@ static int mpr_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
|
||||
|
||||
|
@ -302,10 +347,19 @@ static const struct i2c_device_id mpr121_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpr121_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id mpr121_touchkey_dt_match_table[] = {
|
||||
{ .compatible = "fsl,mpr121-touchkey" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpr121_touchkey_dt_match_table);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver mpr_touchkey_driver = {
|
||||
.driver = {
|
||||
.name = "mpr121",
|
||||
.pm = &mpr121_touchkey_pm_ops,
|
||||
.of_match_table = of_match_ptr(mpr121_touchkey_dt_match_table),
|
||||
},
|
||||
.id_table = mpr121_id,
|
||||
.probe = mpr_touchkey_probe,
|
||||
|
|
|
@ -249,8 +249,6 @@ static int nspire_keypad_probe(struct platform_device *pdev)
|
|||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, keypad);
|
||||
|
||||
dev_dbg(&pdev->dev,
|
||||
"TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n",
|
||||
res, keypad->row_delay, keypad->scan_interval,
|
||||
|
|
|
@ -223,8 +223,8 @@ static int omap4_keypad_parse_dt(struct device *dev,
|
|||
struct device_node *np = dev->of_node;
|
||||
int err;
|
||||
|
||||
err = matrix_keypad_parse_of_params(dev, &keypad_data->rows,
|
||||
&keypad_data->cols);
|
||||
err = matrix_keypad_parse_properties(dev, &keypad_data->rows,
|
||||
&keypad_data->cols);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -375,7 +375,6 @@ static int omap4_keypad_probe(struct platform_device *pdev)
|
|||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
free_irq(keypad_data->irq, keypad_data);
|
||||
err_free_keymap:
|
||||
kfree(keypad_data->keymap);
|
||||
|
@ -401,8 +400,6 @@ static int omap4_keypad_remove(struct platform_device *pdev)
|
|||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
|
||||
input_unregister_device(keypad_data->input);
|
||||
|
||||
iounmap(keypad_data->base);
|
||||
|
|
|
@ -75,8 +75,6 @@ static int opencores_kbd_probe(struct platform_device *pdev)
|
|||
input->name = pdev->name;
|
||||
input->phys = "opencores-kbd/input0";
|
||||
|
||||
input_set_drvdata(input, opencores_kbd);
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
|
@ -112,8 +110,6 @@ static int opencores_kbd_probe(struct platform_device *pdev)
|
|||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, opencores_kbd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -515,7 +515,7 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
|
|||
int rc;
|
||||
unsigned int ctrl_val;
|
||||
|
||||
rc = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols);
|
||||
rc = matrix_keypad_parse_properties(&pdev->dev, &rows, &cols);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
|
|||
u32 rows, cols;
|
||||
int error;
|
||||
|
||||
error = matrix_keypad_parse_of_params(dev, &rows, &cols);
|
||||
error = matrix_keypad_parse_properties(dev, &rows, &cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -445,7 +445,6 @@ static int samsung_keypad_probe(struct platform_device *pdev)
|
|||
|
||||
err_disable_runtime_pm:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
err_unprepare_clk:
|
||||
clk_unprepare(keypad->clk);
|
||||
return error;
|
||||
|
@ -456,7 +455,6 @@ static int samsung_keypad_remove(struct platform_device *pdev)
|
|||
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
input_unregister_device(keypad->input_dev);
|
||||
|
||||
|
|
|
@ -283,8 +283,6 @@ static int spear_kbd_remove(struct platform_device *pdev)
|
|||
input_unregister_device(kbd->input);
|
||||
clk_unprepare(kbd->clk);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,8 +106,8 @@ static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
|
|||
struct device_node *np = dev->of_node;
|
||||
int error;
|
||||
|
||||
error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows,
|
||||
&keypad_data->n_cols);
|
||||
error = matrix_keypad_parse_properties(dev, &keypad_data->n_rows,
|
||||
&keypad_data->n_cols);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse keypad params\n");
|
||||
return error;
|
||||
|
|
|
@ -354,7 +354,7 @@ static int stmpe_keypad_probe(struct platform_device *pdev)
|
|||
input->id.bustype = BUS_I2C;
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
error = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols);
|
||||
error = matrix_keypad_parse_properties(&pdev->dev, &rows, &cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -261,7 +261,6 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
platform_set_drvdata(pdev, lradc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,18 +24,17 @@
|
|||
* alternative licensing inquiries.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/tca8418_keypad.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* TCA8418 hardware limits */
|
||||
#define TCA8418_MAX_ROWS 8
|
||||
|
@ -264,41 +263,25 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data,
|
|||
}
|
||||
|
||||
static int tca8418_keypad_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
const struct tca8418_keypad_platform_data *pdata =
|
||||
dev_get_platdata(dev);
|
||||
struct tca8418_keypad *keypad_data;
|
||||
struct input_dev *input;
|
||||
const struct matrix_keymap_data *keymap_data = NULL;
|
||||
u32 rows = 0, cols = 0;
|
||||
bool rep = false;
|
||||
bool irq_is_gpio = false;
|
||||
int irq;
|
||||
int error, row_shift, max_keys;
|
||||
|
||||
/* Copy the platform data */
|
||||
if (pdata) {
|
||||
if (!pdata->keymap_data) {
|
||||
dev_err(dev, "no keymap data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
keymap_data = pdata->keymap_data;
|
||||
rows = pdata->rows;
|
||||
cols = pdata->cols;
|
||||
rep = pdata->rep;
|
||||
irq_is_gpio = pdata->irq_is_gpio;
|
||||
} else {
|
||||
struct device_node *np = dev->of_node;
|
||||
int err;
|
||||
|
||||
err = matrix_keypad_parse_of_params(dev, &rows, &cols);
|
||||
if (err)
|
||||
return err;
|
||||
rep = of_property_read_bool(np, "keypad,autorepeat");
|
||||
/* Check i2c driver capabilities */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
|
||||
dev_err(dev, "%s adapter not supported\n",
|
||||
dev_driver_string(&client->adapter->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = matrix_keypad_parse_properties(dev, &rows, &cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!rows || rows > TCA8418_MAX_ROWS) {
|
||||
dev_err(dev, "invalid rows\n");
|
||||
return -EINVAL;
|
||||
|
@ -309,13 +292,6 @@ static int tca8418_keypad_probe(struct i2c_client *client,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check i2c driver capabilities */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
|
||||
dev_err(dev, "%s adapter not supported\n",
|
||||
dev_driver_string(&client->adapter->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
row_shift = get_count_order(cols);
|
||||
max_keys = rows << row_shift;
|
||||
|
||||
|
@ -345,27 +321,20 @@ static int tca8418_keypad_probe(struct i2c_client *client,
|
|||
input->id.product = 0x001;
|
||||
input->id.version = 0x0001;
|
||||
|
||||
error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols,
|
||||
NULL, input);
|
||||
error = matrix_keypad_build_keymap(NULL, NULL, rows, cols, NULL, input);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to build keymap\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (rep)
|
||||
if (device_property_read_bool(dev, "keypad,autorepeat"))
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
input_set_capability(input, EV_MSC, MSC_SCAN);
|
||||
|
||||
input_set_drvdata(input, keypad_data);
|
||||
|
||||
irq = client->irq;
|
||||
if (irq_is_gpio)
|
||||
irq = gpio_to_irq(irq);
|
||||
|
||||
error = devm_request_threaded_irq(dev, irq, NULL, tca8418_irq_handler,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_SHARED |
|
||||
IRQF_ONESHOT,
|
||||
error = devm_request_threaded_irq(dev, client->irq,
|
||||
NULL, tca8418_irq_handler,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
client->name, keypad_data);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to claim irq %d; error %d\n",
|
||||
|
@ -384,30 +353,21 @@ static int tca8418_keypad_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
static const struct i2c_device_id tca8418_id[] = {
|
||||
{ TCA8418_NAME, 8418, },
|
||||
{ "tca8418", 8418, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tca8418_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id tca8418_dt_ids[] = {
|
||||
{ .compatible = "ti,tca8418", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tca8418_dt_ids);
|
||||
|
||||
/*
|
||||
* The device tree based i2c loader looks for
|
||||
* "i2c:" + second_component_of(property("compatible"))
|
||||
* and therefore we need an alias to be found.
|
||||
*/
|
||||
MODULE_ALIAS("i2c:tca8418");
|
||||
#endif
|
||||
|
||||
static struct i2c_driver tca8418_keypad_driver = {
|
||||
.driver = {
|
||||
.name = TCA8418_NAME,
|
||||
.of_match_table = of_match_ptr(tca8418_dt_ids),
|
||||
.name = "tca8418_keypad",
|
||||
.of_match_table = tca8418_dt_ids,
|
||||
},
|
||||
.probe = tca8418_keypad_probe,
|
||||
.id_table = tca8418_id,
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* TM2 touchkey device driver
|
||||
*
|
||||
* Copyright 2005 Phil Blundell
|
||||
* Copyright 2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Author: Beomho Seo <beomho.seo@samsung.com>
|
||||
* Author: Jaechul Lee <jcsing.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey"
|
||||
#define TM2_TOUCHKEY_KEYCODE_REG 0x03
|
||||
#define TM2_TOUCHKEY_BASE_REG 0x00
|
||||
#define TM2_TOUCHKEY_CMD_LED_ON 0x10
|
||||
#define TM2_TOUCHKEY_CMD_LED_OFF 0x20
|
||||
#define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3)
|
||||
#define TM2_TOUCHKEY_BIT_KEYCODE GENMASK(2, 0)
|
||||
#define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000
|
||||
#define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000
|
||||
|
||||
enum {
|
||||
TM2_TOUCHKEY_KEY_MENU = 0x1,
|
||||
TM2_TOUCHKEY_KEY_BACK,
|
||||
};
|
||||
|
||||
struct tm2_touchkey_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
struct led_classdev led_dev;
|
||||
struct regulator *vdd;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
};
|
||||
|
||||
static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct tm2_touchkey_data *touchkey =
|
||||
container_of(led_dev, struct tm2_touchkey_data, led_dev);
|
||||
u32 volt;
|
||||
u8 data;
|
||||
|
||||
if (brightness == LED_OFF) {
|
||||
volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN;
|
||||
data = TM2_TOUCHKEY_CMD_LED_OFF;
|
||||
} else {
|
||||
volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX;
|
||||
data = TM2_TOUCHKEY_CMD_LED_ON;
|
||||
}
|
||||
|
||||
regulator_set_voltage(touchkey->vdd, volt, volt);
|
||||
i2c_smbus_write_byte_data(touchkey->client,
|
||||
TM2_TOUCHKEY_BASE_REG, data);
|
||||
}
|
||||
|
||||
static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
|
||||
touchkey->regulators);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* waiting for device initialization, at least 150ms */
|
||||
msleep(150);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tm2_touchkey_power_disable(void *data)
|
||||
{
|
||||
struct tm2_touchkey_data *touchkey = data;
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
|
||||
touchkey->regulators);
|
||||
}
|
||||
|
||||
static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid)
|
||||
{
|
||||
struct tm2_touchkey_data *touchkey = devid;
|
||||
int data;
|
||||
int key;
|
||||
|
||||
data = i2c_smbus_read_byte_data(touchkey->client,
|
||||
TM2_TOUCHKEY_KEYCODE_REG);
|
||||
if (data < 0) {
|
||||
dev_err(&touchkey->client->dev,
|
||||
"failed to read i2c data: %d\n", data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (data & TM2_TOUCHKEY_BIT_KEYCODE) {
|
||||
case TM2_TOUCHKEY_KEY_MENU:
|
||||
key = KEY_PHONE;
|
||||
break;
|
||||
|
||||
case TM2_TOUCHKEY_KEY_BACK:
|
||||
key = KEY_BACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&touchkey->client->dev,
|
||||
"unhandled keycode, data %#02x\n", data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (data & TM2_TOUCHKEY_BIT_PRESS_EV) {
|
||||
input_report_key(touchkey->input_dev, KEY_PHONE, 0);
|
||||
input_report_key(touchkey->input_dev, KEY_BACK, 0);
|
||||
} else {
|
||||
input_report_key(touchkey->input_dev, key, 1);
|
||||
}
|
||||
|
||||
input_sync(touchkey->input_dev);
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tm2_touchkey_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tm2_touchkey_data *touchkey;
|
||||
int error;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
dev_err(&client->dev, "incompatible I2C adapter\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
|
||||
if (!touchkey)
|
||||
return -ENOMEM;
|
||||
|
||||
touchkey->client = client;
|
||||
i2c_set_clientdata(client, touchkey);
|
||||
|
||||
touchkey->regulators[0].supply = "vcc";
|
||||
touchkey->regulators[1].supply = "vdd";
|
||||
error = devm_regulator_bulk_get(&client->dev,
|
||||
ARRAY_SIZE(touchkey->regulators),
|
||||
touchkey->regulators);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to get regulators: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Save VDD for easy access */
|
||||
touchkey->vdd = touchkey->regulators[1].consumer;
|
||||
|
||||
error = tm2_touchkey_power_enable(touchkey);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to power up device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action_or_reset(&client->dev,
|
||||
tm2_touchkey_power_disable, touchkey);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"failed to install poweroff handler: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* input device */
|
||||
touchkey->input_dev = devm_input_allocate_device(&client->dev);
|
||||
if (!touchkey->input_dev) {
|
||||
dev_err(&client->dev, "failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
|
||||
touchkey->input_dev->id.bustype = BUS_I2C;
|
||||
|
||||
input_set_capability(touchkey->input_dev, EV_KEY, KEY_PHONE);
|
||||
input_set_capability(touchkey->input_dev, EV_KEY, KEY_BACK);
|
||||
|
||||
error = input_register_device(touchkey->input_dev);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register input device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, tm2_touchkey_irq_handler,
|
||||
IRQF_ONESHOT,
|
||||
TM2_TOUCHKEY_DEV_NAME, touchkey);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"failed to request threaded irq: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* led device */
|
||||
touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME;
|
||||
touchkey->led_dev.brightness = LED_FULL;
|
||||
touchkey->led_dev.max_brightness = LED_FULL;
|
||||
touchkey->led_dev.brightness_set = tm2_touchkey_led_brightness_set;
|
||||
|
||||
error = devm_led_classdev_register(&client->dev, &touchkey->led_dev);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register touchkey led: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tm2_touchkey_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client);
|
||||
|
||||
disable_irq(client->irq);
|
||||
tm2_touchkey_power_disable(touchkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tm2_touchkey_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
enable_irq(client->irq);
|
||||
|
||||
ret = tm2_touchkey_power_enable(touchkey);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to enable power: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops,
|
||||
tm2_touchkey_suspend, tm2_touchkey_resume);
|
||||
|
||||
static const struct i2c_device_id tm2_touchkey_id_table[] = {
|
||||
{ TM2_TOUCHKEY_DEV_NAME, 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
|
||||
|
||||
static const struct of_device_id tm2_touchkey_of_match[] = {
|
||||
{ .compatible = "cypress,tm2-touchkey", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match);
|
||||
|
||||
static struct i2c_driver tm2_touchkey_driver = {
|
||||
.driver = {
|
||||
.name = TM2_TOUCHKEY_DEV_NAME,
|
||||
.pm = &tm2_touchkey_pm_ops,
|
||||
.of_match_table = of_match_ptr(tm2_touchkey_of_match),
|
||||
},
|
||||
.probe = tm2_touchkey_probe,
|
||||
.id_table = tm2_touchkey_id_table,
|
||||
};
|
||||
module_i2c_driver(tm2_touchkey_driver);
|
||||
|
||||
MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
|
||||
MODULE_AUTHOR("Jaechul Lee <jcsing.lee@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung touchkey driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -374,8 +374,8 @@ static int twl4030_kp_probe(struct platform_device *pdev)
|
|||
kp->autorepeat = pdata->rep;
|
||||
keymap_data = pdata->keymap_data;
|
||||
} else {
|
||||
error = matrix_keypad_parse_of_params(&pdev->dev, &kp->n_rows,
|
||||
&kp->n_cols);
|
||||
error = matrix_keypad_parse_properties(&pdev->dev, &kp->n_rows,
|
||||
&kp->n_cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -441,7 +441,6 @@ static int twl4030_kp_probe(struct platform_device *pdev)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, kp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,18 +14,18 @@
|
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
static bool matrix_keypad_map_key(struct input_dev *input_dev,
|
||||
unsigned int rows, unsigned int cols,
|
||||
|
@ -49,18 +49,22 @@ static bool matrix_keypad_map_key(struct input_dev *input_dev,
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
int matrix_keypad_parse_of_params(struct device *dev,
|
||||
unsigned int *rows, unsigned int *cols)
|
||||
/**
|
||||
* matrix_keypad_parse_properties() - Read properties of matrix keypad
|
||||
*
|
||||
* @dev: Device containing properties
|
||||
* @rows: Returns number of matrix rows
|
||||
* @cols: Returns number of matrix columns
|
||||
* @return 0 if OK, <0 on error
|
||||
*/
|
||||
int matrix_keypad_parse_properties(struct device *dev,
|
||||
unsigned int *rows, unsigned int *cols)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
*rows = *cols = 0;
|
||||
|
||||
device_property_read_u32(dev, "keypad,num-rows", rows);
|
||||
device_property_read_u32(dev, "keypad,num-columns", cols);
|
||||
|
||||
if (!np) {
|
||||
dev_err(dev, "missing DT data");
|
||||
return -EINVAL;
|
||||
}
|
||||
of_property_read_u32(np, "keypad,num-rows", rows);
|
||||
of_property_read_u32(np, "keypad,num-columns", cols);
|
||||
if (!*rows || !*cols) {
|
||||
dev_err(dev, "number of keypad rows/columns not specified\n");
|
||||
return -EINVAL;
|
||||
|
@ -68,62 +72,61 @@ int matrix_keypad_parse_of_params(struct device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(matrix_keypad_parse_of_params);
|
||||
EXPORT_SYMBOL_GPL(matrix_keypad_parse_properties);
|
||||
|
||||
static int matrix_keypad_parse_of_keymap(const char *propname,
|
||||
unsigned int rows, unsigned int cols,
|
||||
struct input_dev *input_dev)
|
||||
static int matrix_keypad_parse_keymap(const char *propname,
|
||||
unsigned int rows, unsigned int cols,
|
||||
struct input_dev *input_dev)
|
||||
{
|
||||
struct device *dev = input_dev->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
unsigned int row_shift = get_count_order(cols);
|
||||
unsigned int max_keys = rows << row_shift;
|
||||
unsigned int proplen, i, size;
|
||||
const __be32 *prop;
|
||||
|
||||
if (!np)
|
||||
return -ENOENT;
|
||||
u32 *keys;
|
||||
int i;
|
||||
int size;
|
||||
int retval;
|
||||
|
||||
if (!propname)
|
||||
propname = "linux,keymap";
|
||||
|
||||
prop = of_get_property(np, propname, &proplen);
|
||||
if (!prop) {
|
||||
dev_err(dev, "OF: %s property not defined in %s\n",
|
||||
propname, np->full_name);
|
||||
return -ENOENT;
|
||||
size = device_property_read_u32_array(dev, propname, NULL, 0);
|
||||
if (size <= 0) {
|
||||
dev_err(dev, "missing or malformed property %s: %d\n",
|
||||
propname, size);
|
||||
return size < 0 ? size : -EINVAL;
|
||||
}
|
||||
|
||||
if (proplen % sizeof(u32)) {
|
||||
dev_err(dev, "OF: Malformed keycode property %s in %s\n",
|
||||
propname, np->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = proplen / sizeof(u32);
|
||||
if (size > max_keys) {
|
||||
dev_err(dev, "OF: %s size overflow\n", propname);
|
||||
dev_err(dev, "%s size overflow (%d vs max %u)\n",
|
||||
propname, size, max_keys);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keys = kmalloc_array(size, sizeof(u32), GFP_KERNEL);
|
||||
if (!keys)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = device_property_read_u32_array(dev, propname, keys, size);
|
||||
if (retval) {
|
||||
dev_err(dev, "failed to read %s property: %d\n",
|
||||
propname, retval);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
unsigned int key = be32_to_cpup(prop + i);
|
||||
|
||||
if (!matrix_keypad_map_key(input_dev, rows, cols,
|
||||
row_shift, key))
|
||||
return -EINVAL;
|
||||
row_shift, keys[i])) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
kfree(keys);
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
static int matrix_keypad_parse_of_keymap(const char *propname,
|
||||
unsigned int rows, unsigned int cols,
|
||||
struct input_dev *input_dev)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* matrix_keypad_build_keymap - convert platform keymap into matrix keymap
|
||||
|
@ -192,8 +195,8 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
|
|||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
|
||||
input_dev);
|
||||
error = matrix_keypad_parse_keymap(keymap_name, rows, cols,
|
||||
input_dev);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,6 @@ static int pm80x_onkey_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct pm80x_onkey_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
pm80x_free_irq(info->pm80x, info->irq, info);
|
||||
input_unregister_device(info->idev);
|
||||
kfree(info);
|
||||
|
|
|
@ -234,16 +234,6 @@ config INPUT_MMA8450
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called mma8450.
|
||||
|
||||
config INPUT_MPU3050
|
||||
tristate "MPU3050 Triaxial gyroscope sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to support InvenSense MPU3050
|
||||
connected via an I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mpu3050.
|
||||
|
||||
config INPUT_APANEL
|
||||
tristate "Fujitsu Lifebook Application Panel buttons"
|
||||
depends on X86 && I2C && LEDS_CLASS
|
||||
|
|
|
@ -48,7 +48,6 @@ obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
|||
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
||||
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
|
||||
obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o
|
||||
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
|
||||
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
|
||||
|
|
|
@ -109,7 +109,6 @@ static int ab8500_ponkey_probe(struct platform_device *pdev)
|
|||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ponkey);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,8 +201,6 @@ static int arizona_haptics_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, haptics);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,6 @@ static int atmel_captouch_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
capdev->client = client;
|
||||
i2c_set_clientdata(client, capdev);
|
||||
|
||||
err = atmel_read(capdev, REG_KEY_STATE,
|
||||
&capdev->prev_btn, sizeof(capdev->prev_btn));
|
||||
|
|
|
@ -147,19 +147,18 @@ static int bfin_rotary_probe(struct platform_device *pdev)
|
|||
|
||||
if (pdata->pin_list) {
|
||||
error = peripheral_request_list(pdata->pin_list,
|
||||
dev_name(&pdev->dev));
|
||||
dev_name(dev));
|
||||
if (error) {
|
||||
dev_err(dev, "requesting peripherals failed: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(dev, bfin_rotary_free_action,
|
||||
pdata->pin_list);
|
||||
error = devm_add_action_or_reset(dev, bfin_rotary_free_action,
|
||||
pdata->pin_list);
|
||||
if (error) {
|
||||
dev_err(dev, "setting cleanup action failed: %d\n",
|
||||
error);
|
||||
peripheral_free_list(pdata->pin_list);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +188,7 @@ static int bfin_rotary_probe(struct platform_device *pdev)
|
|||
|
||||
input->name = pdev->name;
|
||||
input->phys = "bfin-rotary/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->dev.parent = dev;
|
||||
|
||||
input_set_drvdata(input, rotary);
|
||||
|
||||
|
@ -239,7 +238,7 @@ static int bfin_rotary_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
platform_set_drvdata(pdev, rotary);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
device_init_wakeup(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
|
|||
return error;
|
||||
|
||||
if (mode == BMA150_MODE_NORMAL)
|
||||
msleep(2);
|
||||
usleep_range(2000, 2100);
|
||||
|
||||
bma150->mode = mode;
|
||||
return 0;
|
||||
|
@ -222,7 +222,7 @@ static int bma150_soft_reset(struct bma150_data *bma150)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
msleep(2);
|
||||
usleep_range(2000, 2100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -287,7 +287,6 @@ static int da9063_onkey_probe(struct platform_device *pdev)
|
|||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, onkey);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,8 +195,6 @@ static int dm355evm_keys_probe(struct platform_device *pdev)
|
|||
goto fail1;
|
||||
keys->irq = status;
|
||||
|
||||
input_set_drvdata(input, keys);
|
||||
|
||||
input->name = "DM355 EVM Controls";
|
||||
input->phys = "dm355evm/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
|
|
@ -538,7 +538,7 @@ static int drv260x_probe(struct i2c_client *client,
|
|||
|
||||
haptics->input_dev = devm_input_allocate_device(dev);
|
||||
if (!haptics->input_dev) {
|
||||
dev_err(&client->dev, "Failed to allocate input device\n");
|
||||
dev_err(dev, "Failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,17 +120,10 @@ static int e3x0_button_probe(struct platform_device *pdev)
|
|||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, input);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e3x0_button_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id e3x0_button_match[] = {
|
||||
{ .compatible = "ettus,e3x0-button", },
|
||||
|
@ -146,7 +139,6 @@ static struct platform_driver e3x0_button_driver = {
|
|||
.pm = &e3x0_button_pm_ops,
|
||||
},
|
||||
.probe = e3x0_button_probe,
|
||||
.remove = e3x0_button_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(e3x0_button_driver);
|
||||
|
|
|
@ -210,8 +210,6 @@ static int gp2a_remove(struct i2c_client *client)
|
|||
struct gp2a_data *dt = i2c_get_clientdata(client);
|
||||
const struct gp2a_platform_data *pdata = dt->pdata;
|
||||
|
||||
device_init_wakeup(&client->dev, false);
|
||||
|
||||
free_irq(client->irq, dt);
|
||||
|
||||
input_unregister_device(dt->input);
|
||||
|
|
|
@ -110,7 +110,6 @@ static int gpio_decoder_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "failed to register polled device\n");
|
||||
return err;
|
||||
}
|
||||
platform_set_drvdata(pdev, decoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ static int gpio_tilt_polled_probe(struct platform_device *pdev)
|
|||
|
||||
input->name = pdev->name;
|
||||
input->phys = DRV_NAME"/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->dev.parent = dev;
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
|
|
|
@ -75,9 +75,9 @@ static int hi65xx_powerkey_probe(struct platform_device *pdev)
|
|||
struct input_dev *input;
|
||||
int irq, i, error;
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
input = devm_input_allocate_device(dev);
|
||||
if (!input) {
|
||||
dev_err(&pdev->dev, "failed to allocate input device\n");
|
||||
dev_err(dev, "failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -111,19 +111,11 @@ static int hi65xx_powerkey_probe(struct platform_device *pdev)
|
|||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register input device: %d\n",
|
||||
error);
|
||||
dev_err(dev, "failed to register input device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hi65xx_powerkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
device_init_wakeup(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -133,7 +125,6 @@ static struct platform_driver hi65xx_powerkey_driver = {
|
|||
.name = "hi65xx-powerkey",
|
||||
},
|
||||
.probe = hi65xx_powerkey_probe,
|
||||
.remove = hi65xx_powerkey_remove,
|
||||
};
|
||||
module_platform_driver(hi65xx_powerkey_driver);
|
||||
|
||||
|
|
|
@ -205,8 +205,6 @@ static int mma8450_probe(struct i2c_client *c,
|
|||
return err;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(c, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,481 +0,0 @@
|
|||
/*
|
||||
* MPU3050 Tri-axis gyroscope driver
|
||||
*
|
||||
* Copyright (C) 2011 Wistron Co.Ltd
|
||||
* Joseph Lai <joseph_lai@wistron.com>
|
||||
*
|
||||
* Trimmed down by Alan Cox <alan@linux.intel.com> to produce this version
|
||||
*
|
||||
* This is a 'lite' version of the driver, while we consider the right way
|
||||
* to present the other features to user space. In particular it requires the
|
||||
* device has an IRQ, and it only provides an input interface, so is not much
|
||||
* use for device orientation. A fuller version is available from the Meego
|
||||
* tree.
|
||||
*
|
||||
* This program is based on bma023.c.
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define MPU3050_CHIP_ID 0x69
|
||||
|
||||
#define MPU3050_AUTO_DELAY 1000
|
||||
|
||||
#define MPU3050_MIN_VALUE -32768
|
||||
#define MPU3050_MAX_VALUE 32767
|
||||
|
||||
#define MPU3050_DEFAULT_POLL_INTERVAL 200
|
||||
#define MPU3050_DEFAULT_FS_RANGE 3
|
||||
|
||||
/* Register map */
|
||||
#define MPU3050_CHIP_ID_REG 0x00
|
||||
#define MPU3050_SMPLRT_DIV 0x15
|
||||
#define MPU3050_DLPF_FS_SYNC 0x16
|
||||
#define MPU3050_INT_CFG 0x17
|
||||
#define MPU3050_XOUT_H 0x1D
|
||||
#define MPU3050_PWR_MGM 0x3E
|
||||
#define MPU3050_PWR_MGM_POS 6
|
||||
|
||||
/* Register bits */
|
||||
|
||||
/* DLPF_FS_SYNC */
|
||||
#define MPU3050_EXT_SYNC_NONE 0x00
|
||||
#define MPU3050_EXT_SYNC_TEMP 0x20
|
||||
#define MPU3050_EXT_SYNC_GYROX 0x40
|
||||
#define MPU3050_EXT_SYNC_GYROY 0x60
|
||||
#define MPU3050_EXT_SYNC_GYROZ 0x80
|
||||
#define MPU3050_EXT_SYNC_ACCELX 0xA0
|
||||
#define MPU3050_EXT_SYNC_ACCELY 0xC0
|
||||
#define MPU3050_EXT_SYNC_ACCELZ 0xE0
|
||||
#define MPU3050_EXT_SYNC_MASK 0xE0
|
||||
#define MPU3050_FS_250DPS 0x00
|
||||
#define MPU3050_FS_500DPS 0x08
|
||||
#define MPU3050_FS_1000DPS 0x10
|
||||
#define MPU3050_FS_2000DPS 0x18
|
||||
#define MPU3050_FS_MASK 0x18
|
||||
#define MPU3050_DLPF_CFG_256HZ_NOLPF2 0x00
|
||||
#define MPU3050_DLPF_CFG_188HZ 0x01
|
||||
#define MPU3050_DLPF_CFG_98HZ 0x02
|
||||
#define MPU3050_DLPF_CFG_42HZ 0x03
|
||||
#define MPU3050_DLPF_CFG_20HZ 0x04
|
||||
#define MPU3050_DLPF_CFG_10HZ 0x05
|
||||
#define MPU3050_DLPF_CFG_5HZ 0x06
|
||||
#define MPU3050_DLPF_CFG_2100HZ_NOLPF 0x07
|
||||
#define MPU3050_DLPF_CFG_MASK 0x07
|
||||
/* INT_CFG */
|
||||
#define MPU3050_RAW_RDY_EN 0x01
|
||||
#define MPU3050_MPU_RDY_EN 0x02
|
||||
#define MPU3050_LATCH_INT_EN 0x04
|
||||
/* PWR_MGM */
|
||||
#define MPU3050_PWR_MGM_PLL_X 0x01
|
||||
#define MPU3050_PWR_MGM_PLL_Y 0x02
|
||||
#define MPU3050_PWR_MGM_PLL_Z 0x03
|
||||
#define MPU3050_PWR_MGM_CLKSEL 0x07
|
||||
#define MPU3050_PWR_MGM_STBY_ZG 0x08
|
||||
#define MPU3050_PWR_MGM_STBY_YG 0x10
|
||||
#define MPU3050_PWR_MGM_STBY_XG 0x20
|
||||
#define MPU3050_PWR_MGM_SLEEP 0x40
|
||||
#define MPU3050_PWR_MGM_RESET 0x80
|
||||
#define MPU3050_PWR_MGM_MASK 0x40
|
||||
|
||||
struct axis_data {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 z;
|
||||
};
|
||||
|
||||
struct mpu3050_sensor {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct input_dev *idev;
|
||||
};
|
||||
|
||||
/**
|
||||
* mpu3050_xyz_read_reg - read the axes values
|
||||
* @buffer: provide register addr and get register
|
||||
* @length: length of register
|
||||
*
|
||||
* Reads the register values in one transaction or returns a negative
|
||||
* error code on failure.
|
||||
*/
|
||||
static int mpu3050_xyz_read_reg(struct i2c_client *client,
|
||||
u8 *buffer, int length)
|
||||
{
|
||||
/*
|
||||
* Annoying we can't make this const because the i2c layer doesn't
|
||||
* declare input buffers const.
|
||||
*/
|
||||
char cmd = MPU3050_XOUT_H;
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &cmd,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = length,
|
||||
.buf = buffer,
|
||||
},
|
||||
};
|
||||
|
||||
return i2c_transfer(client->adapter, msg, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_read_xyz - get co-ordinates from device
|
||||
* @client: i2c address of sensor
|
||||
* @coords: co-ordinates to update
|
||||
*
|
||||
* Return the converted X Y and Z co-ordinates from the sensor device
|
||||
*/
|
||||
static void mpu3050_read_xyz(struct i2c_client *client,
|
||||
struct axis_data *coords)
|
||||
{
|
||||
u16 buffer[3];
|
||||
|
||||
mpu3050_xyz_read_reg(client, (u8 *)buffer, 6);
|
||||
coords->x = be16_to_cpu(buffer[0]);
|
||||
coords->y = be16_to_cpu(buffer[1]);
|
||||
coords->z = be16_to_cpu(buffer[2]);
|
||||
dev_dbg(&client->dev, "%s: x %d, y %d, z %d\n", __func__,
|
||||
coords->x, coords->y, coords->z);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_set_power_mode - set the power mode
|
||||
* @client: i2c client for the sensor
|
||||
* @val: value to switch on/off of power, 1: normal power, 0: low power
|
||||
*
|
||||
* Put device to normal-power mode or low-power mode.
|
||||
*/
|
||||
static void mpu3050_set_power_mode(struct i2c_client *client, u8 val)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
|
||||
value = (value & ~MPU3050_PWR_MGM_MASK) |
|
||||
(((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^
|
||||
MPU3050_PWR_MGM_MASK);
|
||||
i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_input_open - called on input event open
|
||||
* @input: input dev of opened device
|
||||
*
|
||||
* The input layer calls this function when input event is opened. The
|
||||
* function will push the device to resume. Then, the device is ready
|
||||
* to provide data.
|
||||
*/
|
||||
static int mpu3050_input_open(struct input_dev *input)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = input_get_drvdata(input);
|
||||
int error;
|
||||
|
||||
pm_runtime_get(sensor->dev);
|
||||
|
||||
/* Enable interrupts */
|
||||
error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
|
||||
MPU3050_LATCH_INT_EN |
|
||||
MPU3050_RAW_RDY_EN |
|
||||
MPU3050_MPU_RDY_EN);
|
||||
if (error < 0) {
|
||||
pm_runtime_put(sensor->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_input_close - called on input event close
|
||||
* @input: input dev of closed device
|
||||
*
|
||||
* The input layer calls this function when input event is closed. The
|
||||
* function will push the device to suspend.
|
||||
*/
|
||||
static void mpu3050_input_close(struct input_dev *input)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = input_get_drvdata(input);
|
||||
|
||||
pm_runtime_put(sensor->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_interrupt_thread - handle an IRQ
|
||||
* @irq: interrupt numner
|
||||
* @data: the sensor
|
||||
*
|
||||
* Called by the kernel single threaded after an interrupt occurs. Read
|
||||
* the sensor data and generate an input event for it.
|
||||
*/
|
||||
static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = data;
|
||||
struct axis_data axis;
|
||||
|
||||
mpu3050_read_xyz(sensor->client, &axis);
|
||||
|
||||
input_report_abs(sensor->idev, ABS_X, axis.x);
|
||||
input_report_abs(sensor->idev, ABS_Y, axis.y);
|
||||
input_report_abs(sensor->idev, ABS_Z, axis.z);
|
||||
input_sync(sensor->idev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_hw_init - initialize hardware
|
||||
* @sensor: the sensor
|
||||
*
|
||||
* Called during device probe; configures the sampling method.
|
||||
*/
|
||||
static int mpu3050_hw_init(struct mpu3050_sensor *sensor)
|
||||
{
|
||||
struct i2c_client *client = sensor->client;
|
||||
int ret;
|
||||
u8 reg;
|
||||
|
||||
/* Reset */
|
||||
ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
|
||||
MPU3050_PWR_MGM_RESET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret &= ~MPU3050_PWR_MGM_CLKSEL;
|
||||
ret |= MPU3050_PWR_MGM_PLL_Z;
|
||||
ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Output frequency divider. The poll interval */
|
||||
ret = i2c_smbus_write_byte_data(client, MPU3050_SMPLRT_DIV,
|
||||
MPU3050_DEFAULT_POLL_INTERVAL - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set low pass filter and full scale */
|
||||
reg = MPU3050_DEFAULT_FS_RANGE;
|
||||
reg |= MPU3050_DLPF_CFG_42HZ << 3;
|
||||
reg |= MPU3050_EXT_SYNC_NONE << 5;
|
||||
ret = i2c_smbus_write_byte_data(client, MPU3050_DLPF_FS_SYNC, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_probe - device detection callback
|
||||
* @client: i2c client of found device
|
||||
* @id: id match information
|
||||
*
|
||||
* The I2C layer calls us when it believes a sensor is present at this
|
||||
* address. Probe to see if this is correct and to validate the device.
|
||||
*
|
||||
* If present install the relevant sysfs interfaces and input device.
|
||||
*/
|
||||
static int mpu3050_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct mpu3050_sensor *sensor;
|
||||
struct input_dev *idev;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL);
|
||||
idev = input_allocate_device();
|
||||
if (!sensor || !idev) {
|
||||
dev_err(&client->dev, "failed to allocate driver data\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
sensor->client = client;
|
||||
sensor->dev = &client->dev;
|
||||
sensor->idev = idev;
|
||||
|
||||
mpu3050_set_power_mode(client, 1);
|
||||
msleep(10);
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to detect device\n");
|
||||
error = -ENXIO;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (ret != MPU3050_CHIP_ID) {
|
||||
dev_err(&client->dev, "unsupported chip id\n");
|
||||
error = -ENXIO;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
idev->name = "MPU3050";
|
||||
idev->id.bustype = BUS_I2C;
|
||||
idev->dev.parent = &client->dev;
|
||||
|
||||
idev->open = mpu3050_input_open;
|
||||
idev->close = mpu3050_input_close;
|
||||
|
||||
__set_bit(EV_ABS, idev->evbit);
|
||||
input_set_abs_params(idev, ABS_X,
|
||||
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Y,
|
||||
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Z,
|
||||
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
|
||||
|
||||
input_set_drvdata(idev, sensor);
|
||||
|
||||
pm_runtime_set_active(&client->dev);
|
||||
|
||||
error = mpu3050_hw_init(sensor);
|
||||
if (error)
|
||||
goto err_pm_set_suspended;
|
||||
|
||||
error = request_threaded_irq(client->irq,
|
||||
NULL, mpu3050_interrupt_thread,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"mpu3050", sensor);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"can't get IRQ %d, error %d\n", client->irq, error);
|
||||
goto err_pm_set_suspended;
|
||||
}
|
||||
|
||||
error = input_register_device(idev);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to register input device\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
|
||||
i2c_set_clientdata(client, sensor);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, sensor);
|
||||
err_pm_set_suspended:
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
err_free_mem:
|
||||
input_free_device(idev);
|
||||
kfree(sensor);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_remove - remove a sensor
|
||||
* @client: i2c client of sensor being removed
|
||||
*
|
||||
* Our sensor is going away, clean up the resources.
|
||||
*/
|
||||
static int mpu3050_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
free_irq(client->irq, sensor);
|
||||
input_unregister_device(sensor->idev);
|
||||
kfree(sensor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* mpu3050_suspend - called on device suspend
|
||||
* @dev: device being suspended
|
||||
*
|
||||
* Put the device into sleep mode before we suspend the machine.
|
||||
*/
|
||||
static int mpu3050_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
mpu3050_set_power_mode(client, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_resume - called on device resume
|
||||
* @dev: device being resumed
|
||||
*
|
||||
* Put the device into powered mode on resume.
|
||||
*/
|
||||
static int mpu3050_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
mpu3050_set_power_mode(client, 1);
|
||||
msleep(100); /* wait for gyro chip resume */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
|
||||
|
||||
static const struct i2c_device_id mpu3050_ids[] = {
|
||||
{ "mpu3050", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpu3050_ids);
|
||||
|
||||
static const struct of_device_id mpu3050_of_match[] = {
|
||||
{ .compatible = "invn,mpu3050", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpu3050_of_match);
|
||||
|
||||
static struct i2c_driver mpu3050_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "mpu3050",
|
||||
.pm = &mpu3050_pm,
|
||||
.of_match_table = mpu3050_of_match,
|
||||
},
|
||||
.probe = mpu3050_probe,
|
||||
.remove = mpu3050_remove,
|
||||
.id_table = mpu3050_ids,
|
||||
};
|
||||
|
||||
module_i2c_driver(mpu3050_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Wistron Corp.");
|
||||
MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -266,7 +266,6 @@ static int pm8941_pwrkey_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
unregister_reboot_notifier(&pwrkey->reboot_notifier);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -438,13 +438,6 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pm8xxx_pwr_key_id_table[] = {
|
||||
{ .compatible = "qcom,pm8058-pwrkey", .data = &pm8058_pwrkey_shutdown },
|
||||
{ .compatible = "qcom,pm8921-pwrkey", .data = &pm8921_pwrkey_shutdown },
|
||||
|
@ -454,7 +447,6 @@ MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table);
|
|||
|
||||
static struct platform_driver pmic8xxx_pwrkey_driver = {
|
||||
.probe = pmic8xxx_pwrkey_probe,
|
||||
.remove = pmic8xxx_pwrkey_remove,
|
||||
.shutdown = pmic8xxx_pwrkey_shutdown,
|
||||
.driver = {
|
||||
.name = "pm8xxx-pwrkey",
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -25,29 +26,62 @@
|
|||
struct pwm_beeper {
|
||||
struct input_dev *input;
|
||||
struct pwm_device *pwm;
|
||||
struct regulator *amplifier;
|
||||
struct work_struct work;
|
||||
unsigned long period;
|
||||
bool suspended;
|
||||
bool amplifier_on;
|
||||
};
|
||||
|
||||
#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
|
||||
|
||||
static void __pwm_beeper_set(struct pwm_beeper *beeper)
|
||||
static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
|
||||
{
|
||||
unsigned long period = beeper->period;
|
||||
struct pwm_state state;
|
||||
int error;
|
||||
|
||||
if (period) {
|
||||
pwm_config(beeper->pwm, period / 2, period);
|
||||
pwm_enable(beeper->pwm);
|
||||
} else
|
||||
pwm_disable(beeper->pwm);
|
||||
pwm_get_state(beeper->pwm, &state);
|
||||
|
||||
state.enabled = true;
|
||||
state.period = period;
|
||||
pwm_set_relative_duty_cycle(&state, 50, 100);
|
||||
|
||||
error = pwm_apply_state(beeper->pwm, &state);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!beeper->amplifier_on) {
|
||||
error = regulator_enable(beeper->amplifier);
|
||||
if (error) {
|
||||
pwm_disable(beeper->pwm);
|
||||
return error;
|
||||
}
|
||||
|
||||
beeper->amplifier_on = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_beeper_off(struct pwm_beeper *beeper)
|
||||
{
|
||||
if (beeper->amplifier_on) {
|
||||
regulator_disable(beeper->amplifier);
|
||||
beeper->amplifier_on = false;
|
||||
}
|
||||
|
||||
pwm_disable(beeper->pwm);
|
||||
}
|
||||
|
||||
static void pwm_beeper_work(struct work_struct *work)
|
||||
{
|
||||
struct pwm_beeper *beeper =
|
||||
container_of(work, struct pwm_beeper, work);
|
||||
struct pwm_beeper *beeper = container_of(work, struct pwm_beeper, work);
|
||||
unsigned long period = READ_ONCE(beeper->period);
|
||||
|
||||
__pwm_beeper_set(beeper);
|
||||
if (period)
|
||||
pwm_beeper_on(beeper, period);
|
||||
else
|
||||
pwm_beeper_off(beeper);
|
||||
}
|
||||
|
||||
static int pwm_beeper_event(struct input_dev *input,
|
||||
|
@ -73,7 +107,8 @@ static int pwm_beeper_event(struct input_dev *input,
|
|||
else
|
||||
beeper->period = HZ_TO_NANOSECONDS(value);
|
||||
|
||||
schedule_work(&beeper->work);
|
||||
if (!beeper->suspended)
|
||||
schedule_work(&beeper->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -81,9 +116,7 @@ static int pwm_beeper_event(struct input_dev *input,
|
|||
static void pwm_beeper_stop(struct pwm_beeper *beeper)
|
||||
{
|
||||
cancel_work_sync(&beeper->work);
|
||||
|
||||
if (beeper->period)
|
||||
pwm_disable(beeper->pwm);
|
||||
pwm_beeper_off(beeper);
|
||||
}
|
||||
|
||||
static void pwm_beeper_close(struct input_dev *input)
|
||||
|
@ -95,41 +128,50 @@ static void pwm_beeper_close(struct input_dev *input)
|
|||
|
||||
static int pwm_beeper_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_beeper *beeper;
|
||||
struct pwm_state state;
|
||||
int error;
|
||||
|
||||
beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
|
||||
beeper = devm_kzalloc(dev, sizeof(*beeper), GFP_KERNEL);
|
||||
if (!beeper)
|
||||
return -ENOMEM;
|
||||
|
||||
beeper->pwm = pwm_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(beeper->pwm)) {
|
||||
dev_dbg(&pdev->dev, "unable to request PWM, trying legacy API\n");
|
||||
beeper->pwm = pwm_request(pwm_id, "pwm beeper");
|
||||
}
|
||||
|
||||
beeper->pwm = devm_pwm_get(dev, NULL);
|
||||
if (IS_ERR(beeper->pwm)) {
|
||||
error = PTR_ERR(beeper->pwm);
|
||||
dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
|
||||
goto err_free;
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to request PWM device: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: pwm_apply_args() should be removed when switching to
|
||||
* the atomic PWM API.
|
||||
*/
|
||||
pwm_apply_args(beeper->pwm);
|
||||
/* Sync up PWM state and ensure it is off. */
|
||||
pwm_init_state(beeper->pwm, &state);
|
||||
state.enabled = false;
|
||||
error = pwm_apply_state(beeper->pwm, &state);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to apply initial PWM state: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
beeper->amplifier = devm_regulator_get(dev, "amp");
|
||||
if (IS_ERR(beeper->amplifier)) {
|
||||
error = PTR_ERR(beeper->amplifier);
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get 'amp' regulator: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
INIT_WORK(&beeper->work, pwm_beeper_work);
|
||||
|
||||
beeper->input = input_allocate_device();
|
||||
beeper->input = devm_input_allocate_device(dev);
|
||||
if (!beeper->input) {
|
||||
dev_err(&pdev->dev, "Failed to allocate input device\n");
|
||||
error = -ENOMEM;
|
||||
goto err_pwm_free;
|
||||
dev_err(dev, "Failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
beeper->input->dev.parent = &pdev->dev;
|
||||
|
||||
beeper->input->name = "pwm-beeper";
|
||||
beeper->input->phys = "pwm/input0";
|
||||
|
@ -138,8 +180,8 @@ static int pwm_beeper_probe(struct platform_device *pdev)
|
|||
beeper->input->id.product = 0x0001;
|
||||
beeper->input->id.version = 0x0100;
|
||||
|
||||
beeper->input->evbit[0] = BIT(EV_SND);
|
||||
beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
|
||||
input_set_capability(beeper->input, EV_SND, SND_TONE);
|
||||
input_set_capability(beeper->input, EV_SND, SND_BELL);
|
||||
|
||||
beeper->input->event = pwm_beeper_event;
|
||||
beeper->input->close = pwm_beeper_close;
|
||||
|
@ -148,34 +190,12 @@ static int pwm_beeper_probe(struct platform_device *pdev)
|
|||
|
||||
error = input_register_device(beeper->input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
|
||||
goto err_input_free;
|
||||
dev_err(dev, "Failed to register input device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, beeper);
|
||||
|
||||
return 0;
|
||||
|
||||
err_input_free:
|
||||
input_free_device(beeper->input);
|
||||
err_pwm_free:
|
||||
pwm_free(beeper->pwm);
|
||||
err_free:
|
||||
kfree(beeper);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int pwm_beeper_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_beeper *beeper = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(beeper->input);
|
||||
|
||||
pwm_free(beeper->pwm);
|
||||
|
||||
kfree(beeper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -183,6 +203,15 @@ static int __maybe_unused pwm_beeper_suspend(struct device *dev)
|
|||
{
|
||||
struct pwm_beeper *beeper = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* Spinlock is taken here is not to protect write to
|
||||
* beeper->suspended, but to ensure that pwm_beeper_event
|
||||
* does not re-submit work once flag is set.
|
||||
*/
|
||||
spin_lock_irq(&beeper->input->event_lock);
|
||||
beeper->suspended = true;
|
||||
spin_unlock_irq(&beeper->input->event_lock);
|
||||
|
||||
pwm_beeper_stop(beeper);
|
||||
|
||||
return 0;
|
||||
|
@ -192,8 +221,12 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev)
|
|||
{
|
||||
struct pwm_beeper *beeper = dev_get_drvdata(dev);
|
||||
|
||||
if (beeper->period)
|
||||
__pwm_beeper_set(beeper);
|
||||
spin_lock_irq(&beeper->input->event_lock);
|
||||
beeper->suspended = false;
|
||||
spin_unlock_irq(&beeper->input->event_lock);
|
||||
|
||||
/* Let worker figure out if we should resume beeping */
|
||||
schedule_work(&beeper->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -211,7 +244,6 @@ MODULE_DEVICE_TABLE(of, pwm_beeper_match);
|
|||
|
||||
static struct platform_driver pwm_beeper_driver = {
|
||||
.probe = pwm_beeper_probe,
|
||||
.remove = pwm_beeper_remove,
|
||||
.driver = {
|
||||
.name = "pwm-beeper",
|
||||
.pm = &pwm_beeper_pm_ops,
|
||||
|
|
|
@ -76,14 +76,8 @@ static int retu_pwrbutton_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int retu_pwrbutton_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver retu_pwrbutton_driver = {
|
||||
.probe = retu_pwrbutton_probe,
|
||||
.remove = retu_pwrbutton_remove,
|
||||
.driver = {
|
||||
.name = "retu-pwrbutton",
|
||||
},
|
||||
|
|
|
@ -172,13 +172,6 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sirfsoc_pwrc_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sirfsoc_pwrc_resume(struct device *dev)
|
||||
{
|
||||
struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
|
||||
|
@ -200,7 +193,6 @@ static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
|
|||
|
||||
static struct platform_driver sirfsoc_pwrc_driver = {
|
||||
.probe = sirfsoc_pwrc_probe,
|
||||
.remove = sirfsoc_pwrc_remove,
|
||||
.driver = {
|
||||
.name = "sirfsoc-pwrc",
|
||||
.pm = &sirfsoc_pwrc_pm_ops,
|
||||
|
|
|
@ -102,6 +102,8 @@ soc_button_device_create(struct platform_device *pdev,
|
|||
gpio_keys[n_buttons].active_low = 1;
|
||||
gpio_keys[n_buttons].desc = info->name;
|
||||
gpio_keys[n_buttons].wakeup = info->wakeup;
|
||||
/* These devices often use cheap buttons, use 50 ms debounce */
|
||||
gpio_keys[n_buttons].debounce_interval = 50;
|
||||
n_buttons++;
|
||||
}
|
||||
|
||||
|
@ -167,12 +169,12 @@ static int soc_button_probe(struct platform_device *pdev)
|
|||
|
||||
button_info = (struct soc_button_info *)id->driver_data;
|
||||
|
||||
if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
|
||||
dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n");
|
||||
if (gpiod_count(dev, KBUILD_MODNAME) <= 0) {
|
||||
dev_dbg(dev, "no GPIO attached, ignoring...\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ static int tps6521x_pb_probe(struct platform_device *pdev)
|
|||
int error;
|
||||
int irq;
|
||||
|
||||
match = of_match_node(of_tps6521x_pb_match, pdev->dev.of_node);
|
||||
match = of_match_node(of_tps6521x_pb_match, dev->of_node);
|
||||
if (!match)
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -118,10 +118,9 @@ static int tps6521x_pb_probe(struct platform_device *pdev)
|
|||
|
||||
input_set_capability(idev, EV_KEY, KEY_POWER);
|
||||
|
||||
pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
pwr->regmap = dev_get_regmap(dev->parent, NULL);
|
||||
pwr->dev = dev;
|
||||
pwr->idev = idev;
|
||||
platform_set_drvdata(pdev, pwr);
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
@ -136,8 +135,7 @@ static int tps6521x_pb_probe(struct platform_device *pdev)
|
|||
IRQF_ONESHOT,
|
||||
pwr->data->name, pwr);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to request IRQ #%d: %d\n",
|
||||
irq, error);
|
||||
dev_err(dev, "failed to request IRQ #%d: %d\n", irq, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pwr);
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1855,7 +1855,7 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
|
|||
* Switch mouse to poll (remote) mode so motion data will not
|
||||
* get in our way
|
||||
*/
|
||||
return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
|
||||
return ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
|
||||
}
|
||||
|
||||
static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word)
|
||||
|
|
|
@ -665,7 +665,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
|
|||
char *data;
|
||||
|
||||
/* Type 3 does not require a mode switch */
|
||||
if (dev->cfg.tp_type == TYPE3)
|
||||
if (c->tp_type == TYPE3)
|
||||
return 0;
|
||||
|
||||
data = kmalloc(c->um_size, GFP_KERNEL);
|
||||
|
|
|
@ -832,8 +832,8 @@ static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
|
|||
int error;
|
||||
|
||||
if (device_can_wakeup(dev)) {
|
||||
error = sysfs_merge_group(&client->dev.kobj,
|
||||
&cyapa_power_wakeup_group);
|
||||
error = sysfs_merge_group(&dev->kobj,
|
||||
&cyapa_power_wakeup_group);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to add power wakeup group: %d\n",
|
||||
error);
|
||||
|
@ -1312,7 +1312,7 @@ static int cyapa_probe(struct i2c_client *client,
|
|||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group);
|
||||
error = sysfs_create_group(&dev->kobj, &cyapa_sysfs_group);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to create sysfs entries: %d\n", error);
|
||||
return error;
|
||||
|
|
|
@ -562,7 +562,7 @@ static int cyapa_gen3_bl_exit(struct cyapa *cyapa)
|
|||
* Wait for bootloader to exit, and operation mode to start.
|
||||
* Normally, this takes at least 50 ms.
|
||||
*/
|
||||
usleep_range(50000, 100000);
|
||||
msleep(50);
|
||||
/*
|
||||
* In addition, when a device boots for the first time after being
|
||||
* updated to new firmware, it must first calibrate its sensors, which
|
||||
|
@ -789,7 +789,7 @@ static ssize_t cyapa_gen3_do_calibrate(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct cyapa *cyapa = dev_get_drvdata(dev);
|
||||
int tries;
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
|
||||
|
@ -812,31 +812,28 @@ static ssize_t cyapa_gen3_do_calibrate(struct device *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
tries = 20; /* max recalibration timeout 2s. */
|
||||
/* max recalibration timeout 2s. */
|
||||
timeout = jiffies + 2 * HZ;
|
||||
do {
|
||||
/*
|
||||
* For this recalibration, the max time will not exceed 2s.
|
||||
* The average time is approximately 500 - 700 ms, and we
|
||||
* will check the status every 100 - 200ms.
|
||||
*/
|
||||
usleep_range(100000, 200000);
|
||||
|
||||
msleep(100);
|
||||
ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error reading dev status: %d\n",
|
||||
ret);
|
||||
dev_err(dev, "Error reading dev status: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL)
|
||||
break;
|
||||
} while (--tries);
|
||||
if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) {
|
||||
dev_dbg(dev, "Calibration successful.\n");
|
||||
goto out;
|
||||
}
|
||||
} while (time_is_after_jiffies(timeout));
|
||||
|
||||
if (tries == 0) {
|
||||
dev_err(dev, "Failed to calibrate. Timeout.\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
dev_dbg(dev, "Calibration successful.\n");
|
||||
dev_err(dev, "Failed to calibrate. Timeout.\n");
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
out:
|
||||
return ret < 0 ? ret : count;
|
||||
|
|
|
@ -107,7 +107,7 @@ static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
|
|||
enum psmouse_state old_state;
|
||||
int pktsize;
|
||||
|
||||
ps2_begin_command(&psmouse->ps2dev);
|
||||
ps2_begin_command(ps2dev);
|
||||
|
||||
old_state = psmouse->state;
|
||||
psmouse->state = PSMOUSE_CMD_MODE;
|
||||
|
@ -133,7 +133,7 @@ out:
|
|||
psmouse->state = old_state;
|
||||
psmouse->pktcnt = 0;
|
||||
|
||||
ps2_end_command(&psmouse->ps2dev);
|
||||
ps2_end_command(ps2dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -414,8 +414,6 @@ static int cypress_set_input_params(struct input_dev *input,
|
|||
__set_bit(BTN_RIGHT, input->keybit);
|
||||
__set_bit(BTN_MIDDLE, input->keybit);
|
||||
|
||||
input_set_drvdata(input, cytp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1041,8 +1041,7 @@ static int elan_probe(struct i2c_client *client,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct elan_tp_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct elan_tp_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1053,29 +1052,25 @@ static int elan_probe(struct i2c_client *client,
|
|||
init_completion(&data->fw_completion);
|
||||
mutex_init(&data->sysfs_mutex);
|
||||
|
||||
data->vcc = devm_regulator_get(&client->dev, "vcc");
|
||||
data->vcc = devm_regulator_get(dev, "vcc");
|
||||
if (IS_ERR(data->vcc)) {
|
||||
error = PTR_ERR(data->vcc);
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(&client->dev,
|
||||
"Failed to get 'vcc' regulator: %d\n",
|
||||
dev_err(dev, "Failed to get 'vcc' regulator: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = regulator_enable(data->vcc);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to enable regulator: %d\n", error);
|
||||
dev_err(dev, "Failed to enable regulator: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(&client->dev,
|
||||
elan_disable_regulator, data);
|
||||
error = devm_add_action(dev, elan_disable_regulator, data);
|
||||
if (error) {
|
||||
regulator_disable(data->vcc);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add disable regulator action: %d\n",
|
||||
dev_err(dev, "Failed to add disable regulator action: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
@ -1093,14 +1088,14 @@ static int elan_probe(struct i2c_client *client,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
dev_info(&client->dev,
|
||||
dev_info(dev,
|
||||
"Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n",
|
||||
data->product_id,
|
||||
data->fw_version,
|
||||
data->sm_version,
|
||||
data->iap_version);
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
dev_dbg(dev,
|
||||
"Elan Touchpad Extra Information:\n"
|
||||
" Max ABS X,Y: %d,%d\n"
|
||||
" Width X,Y: %d,%d\n"
|
||||
|
@ -1118,38 +1113,33 @@ static int elan_probe(struct i2c_client *client,
|
|||
* Systems using device tree should set up interrupt via DTS,
|
||||
* the rest will use the default falling edge interrupts.
|
||||
*/
|
||||
irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING;
|
||||
irqflags = dev->of_node ? 0 : IRQF_TRIGGER_FALLING;
|
||||
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, elan_isr,
|
||||
error = devm_request_threaded_irq(dev, client->irq, NULL, elan_isr,
|
||||
irqflags | IRQF_ONESHOT,
|
||||
client->name, data);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "cannot register irq=%d\n", client->irq);
|
||||
dev_err(dev, "cannot register irq=%d\n", client->irq);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_groups(&client->dev.kobj, elan_sysfs_groups);
|
||||
error = sysfs_create_groups(&dev->kobj, elan_sysfs_groups);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
|
||||
error);
|
||||
dev_err(dev, "failed to create sysfs attributes: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(&client->dev,
|
||||
elan_remove_sysfs_groups, data);
|
||||
error = devm_add_action(dev, elan_remove_sysfs_groups, data);
|
||||
if (error) {
|
||||
elan_remove_sysfs_groups(data);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n",
|
||||
dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(data->input);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to register input device: %d\n",
|
||||
error);
|
||||
dev_err(dev, "failed to register input device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1157,8 +1147,8 @@ static int elan_probe(struct i2c_client *client,
|
|||
* Systems using device tree should set up wakeup via DTS,
|
||||
* the rest will configure device as wakeup source by default.
|
||||
*/
|
||||
if (!client->dev.of_node)
|
||||
device_init_wakeup(&client->dev, true);
|
||||
if (!dev->of_node)
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1412,7 +1412,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
|
|||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[3];
|
||||
|
||||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
|
||||
|
||||
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
|
||||
|
|
|
@ -713,8 +713,7 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
|
|||
* the upper bound. (in practice, it takes about 3 loops.)
|
||||
*/
|
||||
for (timeo = 20; timeo > 0; timeo--) {
|
||||
if (!ps2_sendbyte(&psmouse->ps2dev,
|
||||
PSMOUSE_CMD_DISABLE, 20))
|
||||
if (!ps2_sendbyte(ps2dev, PSMOUSE_CMD_DISABLE, 20))
|
||||
break;
|
||||
msleep(25);
|
||||
}
|
||||
|
@ -740,7 +739,7 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
|
|||
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
|
||||
|
||||
/* probably won't see an ACK, the touchpad will be off */
|
||||
ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
|
||||
ps2_sendbyte(ps2dev, 0xec, 20);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -402,7 +402,7 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
|
|||
psmouse->set_resolution = ps2pp_set_resolution;
|
||||
psmouse->disconnect = ps2pp_disconnect;
|
||||
|
||||
error = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
error = device_create_file(&ps2dev->serio->dev,
|
||||
&psmouse_attr_smartscroll.dattr);
|
||||
if (error) {
|
||||
psmouse_err(psmouse,
|
||||
|
|
|
@ -87,7 +87,6 @@ static int probe_maple_mouse(struct device *dev)
|
|||
mse->dev = input_dev;
|
||||
mse->mdev = mdev;
|
||||
|
||||
input_set_drvdata(input_dev, mse);
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
||||
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
|
||||
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
|
||||
|
|
|
@ -127,6 +127,13 @@ struct psmouse_protocol {
|
|||
int (*init)(struct psmouse *);
|
||||
};
|
||||
|
||||
static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
|
||||
{
|
||||
input_report_key(dev, BTN_LEFT, buttons & BIT(0));
|
||||
input_report_key(dev, BTN_MIDDLE, buttons & BIT(2));
|
||||
input_report_key(dev, BTN_RIGHT, buttons & BIT(1));
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_process_byte() analyzes the PS/2 data stream and reports
|
||||
* relevant events to the input module once full packet has arrived.
|
||||
|
@ -199,9 +206,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
|
|||
}
|
||||
|
||||
/* Generic PS/2 Mouse */
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 1);
|
||||
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
|
||||
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
|
||||
psmouse_report_standard_buttons(dev,
|
||||
packet[0] | psmouse->extra_buttons);
|
||||
|
||||
input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
|
||||
|
@ -282,6 +288,30 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
|
||||
{
|
||||
switch (psmouse->oob_data_type) {
|
||||
case PSMOUSE_OOB_NONE:
|
||||
psmouse->oob_data_type = data;
|
||||
break;
|
||||
|
||||
case PSMOUSE_OOB_EXTRA_BTNS:
|
||||
psmouse_report_standard_buttons(psmouse->dev, data);
|
||||
input_sync(psmouse->dev);
|
||||
|
||||
psmouse->extra_buttons = data;
|
||||
psmouse->oob_data_type = PSMOUSE_OOB_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
psmouse_warn(psmouse,
|
||||
"unknown OOB_DATA type: 0x%02x\n",
|
||||
psmouse->oob_data_type);
|
||||
psmouse->oob_data_type = PSMOUSE_OOB_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_interrupt() handles incoming characters, either passing them
|
||||
* for normal processing or gathering them as command response.
|
||||
|
@ -306,6 +336,11 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (flags & SERIO_OOB_DATA) {
|
||||
psmouse_handle_oob_data(psmouse, data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
|
||||
if (ps2_handle_ack(&psmouse->ps2dev, data))
|
||||
goto out;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef _PSMOUSE_H
|
||||
#define _PSMOUSE_H
|
||||
|
||||
#define PSMOUSE_OOB_NONE 0x00
|
||||
#define PSMOUSE_OOB_EXTRA_BTNS 0x01
|
||||
|
||||
#define PSMOUSE_CMD_SETSCALE11 0x00e6
|
||||
#define PSMOUSE_CMD_SETSCALE21 0x00e7
|
||||
#define PSMOUSE_CMD_SETRES 0x10e8
|
||||
|
@ -53,6 +56,8 @@ struct psmouse {
|
|||
unsigned char pktcnt;
|
||||
unsigned char pktsize;
|
||||
unsigned char type;
|
||||
unsigned char oob_data_type;
|
||||
unsigned char extra_buttons;
|
||||
bool ignore_parity;
|
||||
bool acks_disable_command;
|
||||
unsigned int model;
|
||||
|
|
|
@ -597,15 +597,13 @@ static int synaptics_is_pt_packet(unsigned char *buf)
|
|||
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
|
||||
}
|
||||
|
||||
static void synaptics_pass_pt_packet(struct psmouse *psmouse,
|
||||
struct serio *ptport,
|
||||
static void synaptics_pass_pt_packet(struct serio *ptport,
|
||||
unsigned char *packet)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
struct psmouse *child = serio_get_drvdata(ptport);
|
||||
|
||||
if (child && child->state == PSMOUSE_ACTIVATED) {
|
||||
serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
|
||||
serio_interrupt(ptport, packet[1], 0);
|
||||
serio_interrupt(ptport, packet[4], 0);
|
||||
serio_interrupt(ptport, packet[5], 0);
|
||||
if (child->pktsize == 4)
|
||||
|
@ -856,7 +854,6 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
|
|||
struct input_dev *dev = psmouse->dev;
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
|
||||
char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
int i;
|
||||
|
||||
if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
|
||||
|
@ -883,15 +880,18 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
|
|||
* physically wired to the touchpad. Re-route them through
|
||||
* the pass-through interface.
|
||||
*/
|
||||
if (!priv->pt_port)
|
||||
return;
|
||||
if (priv->pt_port) {
|
||||
u8 pt_buttons;
|
||||
|
||||
/* The trackstick expects at most 3 buttons */
|
||||
priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) |
|
||||
SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
|
||||
SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
|
||||
/* The trackstick expects at most 3 buttons */
|
||||
pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) |
|
||||
SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
|
||||
SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
|
||||
|
||||
synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
|
||||
serio_interrupt(priv->pt_port,
|
||||
PSMOUSE_OOB_EXTRA_BTNS, SERIO_OOB_DATA);
|
||||
serio_interrupt(priv->pt_port, pt_buttons, SERIO_OOB_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
static void synaptics_report_buttons(struct psmouse *psmouse,
|
||||
|
@ -1132,7 +1132,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
|
|||
if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
|
||||
synaptics_is_pt_packet(psmouse->packet)) {
|
||||
if (priv->pt_port)
|
||||
synaptics_pass_pt_packet(psmouse, priv->pt_port,
|
||||
synaptics_pass_pt_packet(priv->pt_port,
|
||||
psmouse->packet);
|
||||
} else
|
||||
synaptics_process_packet(psmouse);
|
||||
|
|
|
@ -183,7 +183,6 @@ struct synaptics_data {
|
|||
bool disable_gesture; /* disable gestures */
|
||||
|
||||
struct serio *pt_port; /* Pass-through serio port */
|
||||
unsigned char pt_buttons; /* Pass-through buttons */
|
||||
|
||||
/*
|
||||
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
|
||||
|
|
|
@ -379,7 +379,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
|||
if (!set_properties)
|
||||
return 0;
|
||||
|
||||
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
|
||||
if (trackpoint_read(ps2dev, TP_EXT_BTN, &button_info)) {
|
||||
psmouse_warn(psmouse, "failed to get extended button data\n");
|
||||
button_info = 0;
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
|||
|
||||
trackpoint_defaults(psmouse->private);
|
||||
|
||||
error = trackpoint_power_on_reset(&psmouse->ps2dev);
|
||||
error = trackpoint_power_on_reset(ps2dev);
|
||||
|
||||
/* Write defaults to TP only if reset fails. */
|
||||
if (error)
|
||||
|
|
|
@ -9,9 +9,11 @@ config RMI4_CORE
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
if RMI4_CORE
|
||||
|
||||
config RMI4_I2C
|
||||
tristate "RMI4 I2C Support"
|
||||
depends on RMI4_CORE && I2C
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to support RMI4 devices connected to an I2C
|
||||
bus.
|
||||
|
@ -20,7 +22,7 @@ config RMI4_I2C
|
|||
|
||||
config RMI4_SPI
|
||||
tristate "RMI4 SPI Support"
|
||||
depends on RMI4_CORE && SPI
|
||||
depends on SPI
|
||||
help
|
||||
Say Y here if you want to support RMI4 devices connected to a SPI
|
||||
bus.
|
||||
|
@ -29,7 +31,7 @@ config RMI4_SPI
|
|||
|
||||
config RMI4_SMB
|
||||
tristate "RMI4 SMB Support"
|
||||
depends on RMI4_CORE && I2C
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to support RMI4 devices connected to an SMB
|
||||
bus.
|
||||
|
@ -40,13 +42,13 @@ config RMI4_SMB
|
|||
called rmi_smbus.
|
||||
|
||||
config RMI4_F03
|
||||
bool "RMI4 Function 03 (PS2 Guest)"
|
||||
bool "RMI4 Function 03 (PS2 Guest)"
|
||||
depends on RMI4_CORE
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 03.
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 03.
|
||||
|
||||
Function 03 provides PS2 guest support for RMI4 devices. This
|
||||
includes support for TrackPoints on TouchPads.
|
||||
Function 03 provides PS2 guest support for RMI4 devices. This
|
||||
includes support for TrackPoints on TouchPads.
|
||||
|
||||
config RMI4_F03_SERIO
|
||||
tristate
|
||||
|
@ -57,12 +59,10 @@ config RMI4_F03_SERIO
|
|||
|
||||
config RMI4_2D_SENSOR
|
||||
bool
|
||||
depends on RMI4_CORE
|
||||
|
||||
config RMI4_F11
|
||||
bool "RMI4 Function 11 (2D pointing)"
|
||||
select RMI4_2D_SENSOR
|
||||
depends on RMI4_CORE
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 11.
|
||||
|
||||
|
@ -73,7 +73,6 @@ config RMI4_F11
|
|||
config RMI4_F12
|
||||
bool "RMI4 Function 12 (2D pointing)"
|
||||
select RMI4_2D_SENSOR
|
||||
depends on RMI4_CORE
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 12.
|
||||
|
||||
|
@ -83,7 +82,6 @@ config RMI4_F12
|
|||
|
||||
config RMI4_F30
|
||||
bool "RMI4 Function 30 (GPIO LED)"
|
||||
depends on RMI4_CORE
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 30.
|
||||
|
||||
|
@ -92,7 +90,6 @@ config RMI4_F30
|
|||
|
||||
config RMI4_F34
|
||||
bool "RMI4 Function 34 (Device reflash)"
|
||||
depends on RMI4_CORE
|
||||
select FW_LOADER
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 34.
|
||||
|
@ -103,7 +100,6 @@ config RMI4_F34
|
|||
|
||||
config RMI4_F54
|
||||
bool "RMI4 Function 54 (Analog diagnostics)"
|
||||
depends on RMI4_CORE
|
||||
depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
|
||||
select VIDEOBUF2_VMALLOC
|
||||
select RMI4_F55
|
||||
|
@ -115,9 +111,10 @@ config RMI4_F54
|
|||
|
||||
config RMI4_F55
|
||||
bool "RMI4 Function 55 (Sensor tuning)"
|
||||
depends on RMI4_CORE
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 55
|
||||
|
||||
Function 55 provides access to the RMI4 touch sensor tuning
|
||||
mechanism.
|
||||
|
||||
endif # RMI_CORE
|
||||
|
|
|
@ -144,8 +144,13 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
|
|||
int input_flags = 0;
|
||||
|
||||
if (sensor->report_abs) {
|
||||
if (sensor->axis_align.swap_axes)
|
||||
if (sensor->axis_align.swap_axes) {
|
||||
swap(sensor->max_x, sensor->max_y);
|
||||
swap(sensor->axis_align.clip_x_low,
|
||||
sensor->axis_align.clip_y_low);
|
||||
swap(sensor->axis_align.clip_x_high,
|
||||
sensor->axis_align.clip_y_high);
|
||||
}
|
||||
|
||||
sensor->min_x = sensor->axis_align.clip_x_low;
|
||||
if (sensor->axis_align.clip_x_high)
|
||||
|
|
|
@ -55,7 +55,7 @@ static void rmi_release_device(struct device *dev)
|
|||
kfree(rmi_dev);
|
||||
}
|
||||
|
||||
static struct device_type rmi_device_type = {
|
||||
static const struct device_type rmi_device_type = {
|
||||
.name = "rmi4_sensor",
|
||||
.release = rmi_release_device,
|
||||
};
|
||||
|
@ -134,7 +134,7 @@ static void rmi_release_function(struct device *dev)
|
|||
kfree(fn);
|
||||
}
|
||||
|
||||
static struct device_type rmi_function_type = {
|
||||
static const struct device_type rmi_function_type = {
|
||||
.name = "rmi4_function",
|
||||
.release = rmi_release_function,
|
||||
};
|
||||
|
@ -261,10 +261,10 @@ int __rmi_register_function_handler(struct rmi_function_handler *handler,
|
|||
driver->probe = rmi_function_probe;
|
||||
driver->remove = rmi_function_remove;
|
||||
|
||||
error = driver_register(&handler->driver);
|
||||
error = driver_register(driver);
|
||||
if (error) {
|
||||
pr_err("driver_register() failed for %s, error: %d\n",
|
||||
handler->driver.name, error);
|
||||
driver->name, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -265,6 +265,19 @@ static int rmi_irq_init(struct rmi_device *rmi_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct rmi_function *rmi_find_function(struct rmi_device *rmi_dev, u8 number)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct rmi_function *entry;
|
||||
|
||||
list_for_each_entry(entry, &data->function_list, node) {
|
||||
if (entry->fd.function_number == number)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int suspend_one_function(struct rmi_function *fn)
|
||||
{
|
||||
struct rmi_function_handler *fh;
|
||||
|
@ -364,7 +377,7 @@ static void rmi_driver_set_input_name(struct rmi_device *rmi_dev,
|
|||
struct input_dev *input)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
char *device_name = rmi_f01_get_product_ID(data->f01_container);
|
||||
const char *device_name = rmi_f01_get_product_ID(data->f01_container);
|
||||
char *name;
|
||||
|
||||
name = devm_kasprintf(&rmi_dev->dev, GFP_KERNEL,
|
||||
|
@ -836,7 +849,7 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
|
|||
void *ctx, const struct pdt_entry *pdt)
|
||||
{
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
int *current_irq_count = ctx;
|
||||
struct rmi_function *fn;
|
||||
int i;
|
||||
|
@ -1040,7 +1053,7 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
|
|||
}
|
||||
|
||||
if (data->bootloader_mode)
|
||||
dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
|
||||
dev_warn(dev, "Device in bootloader mode.\n");
|
||||
|
||||
data->irq_count = irq_count;
|
||||
data->num_of_irq_regs = (data->irq_count + 7) / 8;
|
||||
|
@ -1049,7 +1062,7 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
|
|||
data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
|
||||
if (!data->irq_memory) {
|
||||
dev_err(dev, "Failed to allocate memory for irq masks.\n");
|
||||
return retval;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->irq_status = data->irq_memory + size * 0;
|
||||
|
|
|
@ -93,6 +93,7 @@ bool rmi_is_physical_driver(struct device_driver *);
|
|||
int rmi_register_physical_driver(void);
|
||||
void rmi_unregister_physical_driver(void);
|
||||
void rmi_free_function_list(struct rmi_device *rmi_dev);
|
||||
struct rmi_function *rmi_find_function(struct rmi_device *rmi_dev, u8 number);
|
||||
int rmi_enable_sensor(struct rmi_device *rmi_dev);
|
||||
int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
|
||||
int (*callback)(struct rmi_device *rmi_dev, void *ctx,
|
||||
|
@ -104,7 +105,20 @@ int rmi_init_functions(struct rmi_driver_data *data);
|
|||
int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
|
||||
const struct pdt_entry *pdt);
|
||||
|
||||
char *rmi_f01_get_product_ID(struct rmi_function *fn);
|
||||
const char *rmi_f01_get_product_ID(struct rmi_function *fn);
|
||||
|
||||
#ifdef CONFIG_RMI4_F03
|
||||
int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button,
|
||||
int value);
|
||||
void rmi_f03_commit_buttons(struct rmi_function *fn);
|
||||
#else
|
||||
static inline int rmi_f03_overwrite_button(struct rmi_function *fn,
|
||||
unsigned int button, int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void rmi_f03_commit_buttons(struct rmi_function *fn) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RMI4_F34
|
||||
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "rmi_driver.h"
|
||||
|
||||
#define RMI_PRODUCT_ID_LENGTH 10
|
||||
|
@ -54,6 +55,7 @@ struct f01_basic_properties {
|
|||
u8 product_id[RMI_PRODUCT_ID_LENGTH + 1];
|
||||
u16 productinfo;
|
||||
u32 firmware_id;
|
||||
u32 package_id;
|
||||
};
|
||||
|
||||
/* F01 device status bits */
|
||||
|
@ -220,8 +222,19 @@ static int rmi_f01_read_properties(struct rmi_device *rmi_dev,
|
|||
has_build_id_query = !!(queries[0] & BIT(1));
|
||||
}
|
||||
|
||||
if (has_package_id_query)
|
||||
if (has_package_id_query) {
|
||||
ret = rmi_read_block(rmi_dev, prod_info_addr,
|
||||
queries, sizeof(__le64));
|
||||
if (ret) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read package info: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
props->package_id = get_unaligned_le64(queries);
|
||||
prod_info_addr++;
|
||||
}
|
||||
|
||||
if (has_build_id_query) {
|
||||
ret = rmi_read_block(rmi_dev, prod_info_addr, queries,
|
||||
|
@ -241,13 +254,90 @@ static int rmi_f01_read_properties(struct rmi_device *rmi_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *rmi_f01_get_product_ID(struct rmi_function *fn)
|
||||
const char *rmi_f01_get_product_ID(struct rmi_function *fn)
|
||||
{
|
||||
struct f01_data *f01 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
return f01->properties.product_id;
|
||||
}
|
||||
|
||||
static ssize_t rmi_driver_manufacturer_id_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n",
|
||||
f01->properties.manufacturer_id);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(manufacturer_id, 0444,
|
||||
rmi_driver_manufacturer_id_show, NULL);
|
||||
|
||||
static ssize_t rmi_driver_dom_show(struct device *dev,
|
||||
struct device_attribute *dattr, char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.dom);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(date_of_manufacture, 0444, rmi_driver_dom_show, NULL);
|
||||
|
||||
static ssize_t rmi_driver_product_id_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.product_id);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(product_id, 0444, rmi_driver_product_id_show, NULL);
|
||||
|
||||
static ssize_t rmi_driver_firmware_id_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", f01->properties.firmware_id);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(firmware_id, 0444, rmi_driver_firmware_id_show, NULL);
|
||||
|
||||
static ssize_t rmi_driver_package_id_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||
|
||||
u32 package_id = f01->properties.package_id;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%04x.%04x\n",
|
||||
package_id & 0xffff, (package_id >> 16) & 0xffff);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(package_id, 0444, rmi_driver_package_id_show, NULL);
|
||||
|
||||
static struct attribute *rmi_f01_attrs[] = {
|
||||
&dev_attr_manufacturer_id.attr,
|
||||
&dev_attr_date_of_manufacture.attr,
|
||||
&dev_attr_product_id.attr,
|
||||
&dev_attr_firmware_id.attr,
|
||||
&dev_attr_package_id.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group rmi_f01_attr_group = {
|
||||
.attrs = rmi_f01_attrs,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int rmi_f01_of_probe(struct device *dev,
|
||||
struct rmi_device_platform_data *pdata)
|
||||
|
@ -480,9 +570,18 @@ static int rmi_f01_probe(struct rmi_function *fn)
|
|||
|
||||
dev_set_drvdata(&fn->dev, f01);
|
||||
|
||||
error = sysfs_create_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group);
|
||||
if (error)
|
||||
dev_warn(&fn->dev, "Failed to create sysfs group: %d\n", error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_f01_remove(struct rmi_function *fn)
|
||||
{
|
||||
sysfs_remove_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group);
|
||||
}
|
||||
|
||||
static int rmi_f01_config(struct rmi_function *fn)
|
||||
{
|
||||
struct f01_data *f01 = dev_get_drvdata(&fn->dev);
|
||||
|
@ -622,6 +721,7 @@ struct rmi_function_handler rmi_f01_handler = {
|
|||
},
|
||||
.func = 0x01,
|
||||
.probe = rmi_f01_probe,
|
||||
.remove = rmi_f01_remove,
|
||||
.config = rmi_f01_config,
|
||||
.attention = rmi_f01_attention,
|
||||
.suspend = rmi_f01_suspend,
|
||||
|
|
|
@ -26,15 +26,53 @@
|
|||
#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
|
||||
#define RMI_F03_QUEUE_LENGTH 0x0F
|
||||
|
||||
#define PSMOUSE_OOB_EXTRA_BTNS 0x01
|
||||
|
||||
struct f03_data {
|
||||
struct rmi_function *fn;
|
||||
|
||||
struct serio *serio;
|
||||
|
||||
unsigned int overwrite_buttons;
|
||||
|
||||
u8 device_count;
|
||||
u8 rx_queue_length;
|
||||
};
|
||||
|
||||
int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button,
|
||||
int value)
|
||||
{
|
||||
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
|
||||
unsigned int bit;
|
||||
|
||||
if (button < BTN_LEFT || button > BTN_MIDDLE)
|
||||
return -EINVAL;
|
||||
|
||||
bit = BIT(button - BTN_LEFT);
|
||||
|
||||
if (value)
|
||||
f03->overwrite_buttons |= bit;
|
||||
else
|
||||
f03->overwrite_buttons &= ~bit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rmi_f03_commit_buttons(struct rmi_function *fn)
|
||||
{
|
||||
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
|
||||
struct serio *serio = f03->serio;
|
||||
|
||||
serio_pause_rx(serio);
|
||||
if (serio->drv) {
|
||||
serio->drv->interrupt(serio, PSMOUSE_OOB_EXTRA_BTNS,
|
||||
SERIO_OOB_DATA);
|
||||
serio->drv->interrupt(serio, f03->overwrite_buttons,
|
||||
SERIO_OOB_DATA);
|
||||
}
|
||||
serio_continue_rx(serio);
|
||||
}
|
||||
|
||||
static int rmi_f03_pt_write(struct serio *id, unsigned char val)
|
||||
{
|
||||
struct f03_data *f03 = id->port_data;
|
||||
|
@ -175,9 +213,6 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
|||
int i;
|
||||
int error;
|
||||
|
||||
if (!rmi_dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (drvdata->attn_data.data) {
|
||||
/* First grab the data passed by the transport device */
|
||||
if (drvdata->attn_data.size < ob_len) {
|
||||
|
|
|
@ -16,30 +16,24 @@
|
|||
|
||||
/* Defs for Query 0 */
|
||||
#define RMI_F30_EXTENDED_PATTERNS 0x01
|
||||
#define RMI_F30_HAS_MAPPABLE_BUTTONS (1 << 1)
|
||||
#define RMI_F30_HAS_LED (1 << 2)
|
||||
#define RMI_F30_HAS_GPIO (1 << 3)
|
||||
#define RMI_F30_HAS_HAPTIC (1 << 4)
|
||||
#define RMI_F30_HAS_GPIO_DRV_CTL (1 << 5)
|
||||
#define RMI_F30_HAS_MECH_MOUSE_BTNS (1 << 6)
|
||||
#define RMI_F30_HAS_MAPPABLE_BUTTONS BIT(1)
|
||||
#define RMI_F30_HAS_LED BIT(2)
|
||||
#define RMI_F30_HAS_GPIO BIT(3)
|
||||
#define RMI_F30_HAS_HAPTIC BIT(4)
|
||||
#define RMI_F30_HAS_GPIO_DRV_CTL BIT(5)
|
||||
#define RMI_F30_HAS_MECH_MOUSE_BTNS BIT(6)
|
||||
|
||||
/* Defs for Query 1 */
|
||||
#define RMI_F30_GPIO_LED_COUNT 0x1F
|
||||
|
||||
/* Defs for Control Registers */
|
||||
#define RMI_F30_CTRL_1_GPIO_DEBOUNCE 0x01
|
||||
#define RMI_F30_CTRL_1_HALT (1 << 4)
|
||||
#define RMI_F30_CTRL_1_HALTED (1 << 5)
|
||||
#define RMI_F30_CTRL_1_HALT BIT(4)
|
||||
#define RMI_F30_CTRL_1_HALTED BIT(5)
|
||||
#define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS 0x03
|
||||
|
||||
struct rmi_f30_ctrl_data {
|
||||
int address;
|
||||
int length;
|
||||
u8 *regs;
|
||||
};
|
||||
|
||||
#define RMI_F30_CTRL_MAX_REGS 32
|
||||
#define RMI_F30_CTRL_MAX_BYTES ((RMI_F30_CTRL_MAX_REGS + 7) >> 3)
|
||||
#define RMI_F30_CTRL_MAX_BYTES DIV_ROUND_UP(RMI_F30_CTRL_MAX_REGS, 8)
|
||||
#define RMI_F30_CTRL_MAX_REG_BLOCKS 11
|
||||
|
||||
#define RMI_F30_CTRL_REGS_MAX_SIZE (RMI_F30_CTRL_MAX_BYTES \
|
||||
|
@ -54,6 +48,15 @@ struct rmi_f30_ctrl_data {
|
|||
+ 1 \
|
||||
+ 1)
|
||||
|
||||
#define TRACKSTICK_RANGE_START 3
|
||||
#define TRACKSTICK_RANGE_END 6
|
||||
|
||||
struct rmi_f30_ctrl_data {
|
||||
int address;
|
||||
int length;
|
||||
u8 *regs;
|
||||
};
|
||||
|
||||
struct f30_data {
|
||||
/* Query Data */
|
||||
bool has_extended_pattern;
|
||||
|
@ -76,18 +79,21 @@ struct f30_data {
|
|||
u16 *gpioled_key_map;
|
||||
|
||||
struct input_dev *input;
|
||||
|
||||
struct rmi_function *f03;
|
||||
bool trackstick_buttons;
|
||||
};
|
||||
|
||||
static int rmi_f30_read_control_parameters(struct rmi_function *fn,
|
||||
struct f30_data *f30)
|
||||
{
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
error = rmi_read_block(rmi_dev, fn->fd.control_base_addr,
|
||||
f30->ctrl_regs, f30->ctrl_regs_size);
|
||||
error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
|
||||
f30->ctrl_regs, f30->ctrl_regs_size);
|
||||
if (error) {
|
||||
dev_err(&rmi_dev->dev, "%s : Could not read control registers at 0x%x error (%d)\n",
|
||||
dev_err(&fn->dev,
|
||||
"%s: Could not read control registers at 0x%x: %d\n",
|
||||
__func__, fn->fd.control_base_addr, error);
|
||||
return error;
|
||||
}
|
||||
|
@ -95,24 +101,39 @@ static int rmi_f30_read_control_parameters(struct rmi_function *fn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_f30_report_button(struct rmi_function *fn,
|
||||
struct f30_data *f30, unsigned int button)
|
||||
{
|
||||
unsigned int reg_num = button >> 3;
|
||||
unsigned int bit_num = button & 0x07;
|
||||
u16 key_code = f30->gpioled_key_map[button];
|
||||
bool key_down = !(f30->data_regs[reg_num] & BIT(bit_num));
|
||||
|
||||
if (f30->trackstick_buttons &&
|
||||
button >= TRACKSTICK_RANGE_START &&
|
||||
button <= TRACKSTICK_RANGE_END) {
|
||||
rmi_f03_overwrite_button(f30->f03, key_code, key_down);
|
||||
} else {
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
|
||||
"%s: call input report key (0x%04x) value (0x%02x)",
|
||||
__func__, key_code, key_down);
|
||||
|
||||
input_report_key(f30->input, key_code, key_down);
|
||||
}
|
||||
}
|
||||
|
||||
static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
{
|
||||
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
int retval;
|
||||
int gpiled = 0;
|
||||
int value = 0;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
|
||||
int error;
|
||||
int i;
|
||||
int reg_num;
|
||||
|
||||
if (!f30->input)
|
||||
return 0;
|
||||
|
||||
/* Read the gpi led data. */
|
||||
if (drvdata->attn_data.data) {
|
||||
if (drvdata->attn_data.size < f30->register_count) {
|
||||
dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
|
||||
dev_warn(&fn->dev,
|
||||
"F30 interrupted, but data is missing\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy(f30->data_regs, drvdata->attn_data.data,
|
||||
|
@ -120,75 +141,27 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
|||
drvdata->attn_data.data += f30->register_count;
|
||||
drvdata->attn_data.size -= f30->register_count;
|
||||
} else {
|
||||
retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
|
||||
f30->data_regs, f30->register_count);
|
||||
|
||||
if (retval) {
|
||||
dev_err(&fn->dev, "%s: Failed to read F30 data registers.\n",
|
||||
__func__);
|
||||
return retval;
|
||||
error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
|
||||
f30->data_regs, f30->register_count);
|
||||
if (error) {
|
||||
dev_err(&fn->dev,
|
||||
"%s: Failed to read F30 data registers: %d\n",
|
||||
__func__, error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
for (reg_num = 0; reg_num < f30->register_count; ++reg_num) {
|
||||
for (i = 0; gpiled < f30->gpioled_count && i < 8; ++i,
|
||||
++gpiled) {
|
||||
if (f30->gpioled_key_map[gpiled] != 0) {
|
||||
/* buttons have pull up resistors */
|
||||
value = (((f30->data_regs[reg_num] >> i) & 0x01)
|
||||
== 0);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
|
||||
"%s: call input report key (0x%04x) value (0x%02x)",
|
||||
__func__,
|
||||
f30->gpioled_key_map[gpiled], value);
|
||||
input_report_key(f30->input,
|
||||
f30->gpioled_key_map[gpiled],
|
||||
value);
|
||||
}
|
||||
|
||||
}
|
||||
if (f30->has_gpio) {
|
||||
for (i = 0; i < f30->gpioled_count; i++)
|
||||
if (f30->gpioled_key_map[i] != KEY_RESERVED)
|
||||
rmi_f30_report_button(fn, f30, i);
|
||||
if (f30->trackstick_buttons)
|
||||
rmi_f03_commit_buttons(f30->f03);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f30_register_device(struct rmi_function *fn)
|
||||
{
|
||||
int i;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
|
||||
struct input_dev *input_dev;
|
||||
int button_count = 0;
|
||||
|
||||
input_dev = drv_data->input;
|
||||
if (!input_dev) {
|
||||
dev_info(&fn->dev, "F30: no input device found, ignoring.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f30->input = input_dev;
|
||||
|
||||
set_bit(EV_KEY, input_dev->evbit);
|
||||
|
||||
input_dev->keycode = f30->gpioled_key_map;
|
||||
input_dev->keycodesize = sizeof(u16);
|
||||
input_dev->keycodemax = f30->gpioled_count;
|
||||
|
||||
for (i = 0; i < f30->gpioled_count; i++) {
|
||||
if (f30->gpioled_key_map[i] != 0) {
|
||||
input_set_capability(input_dev, EV_KEY,
|
||||
f30->gpioled_key_map[i]);
|
||||
button_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (button_count == 1)
|
||||
__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f30_config(struct rmi_function *fn)
|
||||
{
|
||||
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
|
||||
|
@ -197,6 +170,12 @@ static int rmi_f30_config(struct rmi_function *fn)
|
|||
rmi_get_platform_data(fn->rmi_dev);
|
||||
int error;
|
||||
|
||||
if (pdata->f30_data.trackstick_buttons) {
|
||||
/* Try [re-]establish link to F03. */
|
||||
f30->f03 = rmi_find_function(fn->rmi_dev, 0x03);
|
||||
f30->trackstick_buttons = f30->f03 != NULL;
|
||||
}
|
||||
|
||||
if (pdata->f30_data.disable) {
|
||||
drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
|
||||
} else {
|
||||
|
@ -204,19 +183,20 @@ static int rmi_f30_config(struct rmi_function *fn)
|
|||
error = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
|
||||
f30->ctrl_regs, f30->ctrl_regs_size);
|
||||
if (error) {
|
||||
dev_err(&fn->rmi_dev->dev,
|
||||
"%s : Could not write control registers at 0x%x error (%d)\n",
|
||||
dev_err(&fn->dev,
|
||||
"%s: Could not write control registers at 0x%x: %d\n",
|
||||
__func__, fn->fd.control_base_addr, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
|
||||
int *ctrl_addr, int len, u8 **reg)
|
||||
static void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
|
||||
int *ctrl_addr, int len, u8 **reg)
|
||||
{
|
||||
ctrl->address = *ctrl_addr;
|
||||
ctrl->length = len;
|
||||
|
@ -225,8 +205,7 @@ static inline void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
|
|||
*reg += len;
|
||||
}
|
||||
|
||||
static inline bool rmi_f30_is_valid_button(int button,
|
||||
struct rmi_f30_ctrl_data *ctrl)
|
||||
static bool rmi_f30_is_valid_button(int button, struct rmi_f30_ctrl_data *ctrl)
|
||||
{
|
||||
int byte_position = button >> 3;
|
||||
int bit_position = button & 0x07;
|
||||
|
@ -239,32 +218,66 @@ static inline bool rmi_f30_is_valid_button(int button,
|
|||
(ctrl[3].regs[byte_position] & BIT(bit_position));
|
||||
}
|
||||
|
||||
static inline int rmi_f30_initialize(struct rmi_function *fn)
|
||||
static int rmi_f30_map_gpios(struct rmi_function *fn,
|
||||
struct f30_data *f30)
|
||||
{
|
||||
struct f30_data *f30;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
const struct rmi_device_platform_data *pdata;
|
||||
int retval = 0;
|
||||
int control_address;
|
||||
const struct rmi_device_platform_data *pdata =
|
||||
rmi_get_platform_data(fn->rmi_dev);
|
||||
struct input_dev *input = f30->input;
|
||||
unsigned int button = BTN_LEFT;
|
||||
unsigned int trackstick_button = BTN_LEFT;
|
||||
bool button_mapped = false;
|
||||
int i;
|
||||
int button;
|
||||
u8 buf[RMI_F30_QUERY_SIZE];
|
||||
u8 *ctrl_reg;
|
||||
u8 *map_memory;
|
||||
|
||||
f30 = devm_kzalloc(&fn->dev, sizeof(struct f30_data),
|
||||
GFP_KERNEL);
|
||||
if (!f30)
|
||||
f30->gpioled_key_map = devm_kcalloc(&fn->dev,
|
||||
f30->gpioled_count,
|
||||
sizeof(f30->gpioled_key_map[0]),
|
||||
GFP_KERNEL);
|
||||
if (!f30->gpioled_key_map) {
|
||||
dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&fn->dev, f30);
|
||||
for (i = 0; i < f30->gpioled_count; i++) {
|
||||
if (!rmi_f30_is_valid_button(i, f30->ctrl))
|
||||
continue;
|
||||
|
||||
retval = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, buf,
|
||||
RMI_F30_QUERY_SIZE);
|
||||
if (pdata->f30_data.trackstick_buttons &&
|
||||
i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) {
|
||||
f30->gpioled_key_map[i] = trackstick_button++;
|
||||
} else if (!pdata->f30_data.buttonpad || !button_mapped) {
|
||||
f30->gpioled_key_map[i] = button;
|
||||
input_set_capability(input, EV_KEY, button++);
|
||||
button_mapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval) {
|
||||
dev_err(&fn->dev, "Failed to read query register.\n");
|
||||
return retval;
|
||||
input->keycode = f30->gpioled_key_map;
|
||||
input->keycodesize = sizeof(f30->gpioled_key_map[0]);
|
||||
input->keycodemax = f30->gpioled_count;
|
||||
|
||||
/*
|
||||
* Buttonpad could be also inferred from f30->has_mech_mouse_btns,
|
||||
* but I am not sure, so use only the pdata info.
|
||||
*/
|
||||
if (pdata->f30_data.buttonpad)
|
||||
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f30_initialize(struct rmi_function *fn, struct f30_data *f30)
|
||||
{
|
||||
u8 *ctrl_reg = f30->ctrl_regs;
|
||||
int control_address = fn->fd.control_base_addr;
|
||||
u8 buf[RMI_F30_QUERY_SIZE];
|
||||
int error;
|
||||
|
||||
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
|
||||
buf, RMI_F30_QUERY_SIZE);
|
||||
if (error) {
|
||||
dev_err(&fn->dev, "Failed to read query register\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
f30->has_extended_pattern = buf[0] & RMI_F30_EXTENDED_PATTERNS;
|
||||
|
@ -276,101 +289,71 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
|
|||
f30->has_mech_mouse_btns = buf[0] & RMI_F30_HAS_MECH_MOUSE_BTNS;
|
||||
f30->gpioled_count = buf[1] & RMI_F30_GPIO_LED_COUNT;
|
||||
|
||||
f30->register_count = (f30->gpioled_count + 7) >> 3;
|
||||
|
||||
control_address = fn->fd.control_base_addr;
|
||||
ctrl_reg = f30->ctrl_regs;
|
||||
f30->register_count = DIV_ROUND_UP(f30->gpioled_count, 8);
|
||||
|
||||
if (f30->has_gpio && f30->has_led)
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[0], &control_address,
|
||||
f30->register_count, &ctrl_reg);
|
||||
f30->register_count, &ctrl_reg);
|
||||
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address, sizeof(u8),
|
||||
&ctrl_reg);
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address,
|
||||
sizeof(u8), &ctrl_reg);
|
||||
|
||||
if (f30->has_gpio) {
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[2], &control_address,
|
||||
f30->register_count, &ctrl_reg);
|
||||
f30->register_count, &ctrl_reg);
|
||||
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[3], &control_address,
|
||||
f30->register_count, &ctrl_reg);
|
||||
f30->register_count, &ctrl_reg);
|
||||
}
|
||||
|
||||
if (f30->has_led) {
|
||||
int ctrl5_len;
|
||||
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address,
|
||||
f30->register_count, &ctrl_reg);
|
||||
|
||||
if (f30->has_extended_pattern)
|
||||
ctrl5_len = 6;
|
||||
else
|
||||
ctrl5_len = 2;
|
||||
f30->register_count, &ctrl_reg);
|
||||
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address,
|
||||
ctrl5_len, &ctrl_reg);
|
||||
f30->has_extended_pattern ? 6 : 2,
|
||||
&ctrl_reg);
|
||||
}
|
||||
|
||||
if (f30->has_led || f30->has_gpio_driver_control) {
|
||||
/* control 6 uses a byte per gpio/led */
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[6], &control_address,
|
||||
f30->gpioled_count, &ctrl_reg);
|
||||
f30->gpioled_count, &ctrl_reg);
|
||||
}
|
||||
|
||||
if (f30->has_mappable_buttons) {
|
||||
/* control 7 uses a byte per gpio/led */
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[7], &control_address,
|
||||
f30->gpioled_count, &ctrl_reg);
|
||||
f30->gpioled_count, &ctrl_reg);
|
||||
}
|
||||
|
||||
if (f30->has_haptic) {
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[8], &control_address,
|
||||
f30->register_count, &ctrl_reg);
|
||||
f30->register_count, &ctrl_reg);
|
||||
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[9], &control_address,
|
||||
sizeof(u8), &ctrl_reg);
|
||||
sizeof(u8), &ctrl_reg);
|
||||
}
|
||||
|
||||
if (f30->has_mech_mouse_btns)
|
||||
rmi_f30_set_ctrl_data(&f30->ctrl[10], &control_address,
|
||||
sizeof(u8), &ctrl_reg);
|
||||
sizeof(u8), &ctrl_reg);
|
||||
|
||||
f30->ctrl_regs_size = ctrl_reg - f30->ctrl_regs
|
||||
?: RMI_F30_CTRL_REGS_MAX_SIZE;
|
||||
f30->ctrl_regs_size = ctrl_reg -
|
||||
f30->ctrl_regs ?: RMI_F30_CTRL_REGS_MAX_SIZE;
|
||||
|
||||
retval = rmi_f30_read_control_parameters(fn, f30);
|
||||
if (retval < 0) {
|
||||
error = rmi_f30_read_control_parameters(fn, f30);
|
||||
if (error) {
|
||||
dev_err(&fn->dev,
|
||||
"Failed to initialize F19 control params.\n");
|
||||
return retval;
|
||||
"Failed to initialize F30 control params: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
map_memory = devm_kzalloc(&fn->dev,
|
||||
(f30->gpioled_count * (sizeof(u16))),
|
||||
GFP_KERNEL);
|
||||
if (!map_memory) {
|
||||
dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
f30->gpioled_key_map = (u16 *)map_memory;
|
||||
|
||||
pdata = rmi_get_platform_data(rmi_dev);
|
||||
if (f30->has_gpio) {
|
||||
button = BTN_LEFT;
|
||||
for (i = 0; i < f30->gpioled_count; i++) {
|
||||
if (rmi_f30_is_valid_button(i, f30->ctrl)) {
|
||||
f30->gpioled_key_map[i] = button++;
|
||||
|
||||
/*
|
||||
* buttonpad might be given by
|
||||
* f30->has_mech_mouse_btns, but I am
|
||||
* not sure, so use only the pdata info
|
||||
*/
|
||||
if (pdata->f30_data.buttonpad)
|
||||
break;
|
||||
}
|
||||
}
|
||||
error = rmi_f30_map_gpios(fn, f30);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -378,26 +361,33 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
|
|||
|
||||
static int rmi_f30_probe(struct rmi_function *fn)
|
||||
{
|
||||
int rc;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
const struct rmi_device_platform_data *pdata =
|
||||
rmi_get_platform_data(fn->rmi_dev);
|
||||
rmi_get_platform_data(rmi_dev);
|
||||
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct f30_data *f30;
|
||||
int error;
|
||||
|
||||
if (pdata->f30_data.disable)
|
||||
return 0;
|
||||
|
||||
rc = rmi_f30_initialize(fn);
|
||||
if (rc < 0)
|
||||
goto error_exit;
|
||||
if (!drv_data->input) {
|
||||
dev_info(&fn->dev, "F30: no input device found, ignoring\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rc = rmi_f30_register_device(fn);
|
||||
if (rc < 0)
|
||||
goto error_exit;
|
||||
f30 = devm_kzalloc(&fn->dev, sizeof(*f30), GFP_KERNEL);
|
||||
if (!f30)
|
||||
return -ENOMEM;
|
||||
|
||||
f30->input = drv_data->input;
|
||||
|
||||
error = rmi_f30_initialize(fn, f30);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
dev_set_drvdata(&fn->dev, f30);
|
||||
return 0;
|
||||
|
||||
error_exit:
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
struct rmi_function_handler rmi_f30_handler = {
|
||||
|
|
|
@ -157,6 +157,9 @@ static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
|
|||
i + 1, block_count);
|
||||
|
||||
data += f34->v5.block_size;
|
||||
f34->update_progress += f34->v5.block_size;
|
||||
f34->update_status = (f34->update_progress * 100) /
|
||||
f34->update_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -174,7 +177,7 @@ static int rmi_f34_write_config(struct f34_data *f34, const void *data)
|
|||
F34_WRITE_CONFIG_BLOCK);
|
||||
}
|
||||
|
||||
int rmi_f34_enable_flash(struct f34_data *f34)
|
||||
static int rmi_f34_enable_flash(struct f34_data *f34)
|
||||
{
|
||||
return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
|
||||
F34_ENABLE_WAIT_MS, true);
|
||||
|
@ -184,9 +187,14 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
|
|||
const struct rmi_f34_firmware *syn_fw)
|
||||
{
|
||||
struct rmi_function *fn = f34->fn;
|
||||
u32 image_size = le32_to_cpu(syn_fw->image_size);
|
||||
u32 config_size = le32_to_cpu(syn_fw->config_size);
|
||||
int ret;
|
||||
|
||||
if (syn_fw->image_size) {
|
||||
f34->update_progress = 0;
|
||||
f34->update_size = image_size + config_size;
|
||||
|
||||
if (image_size) {
|
||||
dev_info(&fn->dev, "Erasing firmware...\n");
|
||||
ret = rmi_f34_command(f34, F34_ERASE_ALL,
|
||||
F34_ERASE_WAIT_MS, true);
|
||||
|
@ -194,18 +202,18 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
|
|||
return ret;
|
||||
|
||||
dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
|
||||
syn_fw->image_size);
|
||||
image_size);
|
||||
ret = rmi_f34_write_firmware(f34, syn_fw->data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (syn_fw->config_size) {
|
||||
if (config_size) {
|
||||
/*
|
||||
* We only need to erase config if we haven't updated
|
||||
* firmware.
|
||||
*/
|
||||
if (!syn_fw->image_size) {
|
||||
if (!image_size) {
|
||||
dev_info(&fn->dev, "Erasing config...\n");
|
||||
ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
|
||||
F34_ERASE_WAIT_MS, true);
|
||||
|
@ -214,9 +222,8 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
|
|||
}
|
||||
|
||||
dev_info(&fn->dev, "Writing config (%d bytes)...\n",
|
||||
syn_fw->config_size);
|
||||
ret = rmi_f34_write_config(f34,
|
||||
&syn_fw->data[syn_fw->image_size]);
|
||||
config_size);
|
||||
ret = rmi_f34_write_config(f34, &syn_fw->data[image_size]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -224,21 +231,23 @@ static int rmi_f34_flash_firmware(struct f34_data *f34,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
|
||||
static int rmi_f34_update_firmware(struct f34_data *f34,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
const struct rmi_f34_firmware *syn_fw;
|
||||
const struct rmi_f34_firmware *syn_fw =
|
||||
(const struct rmi_f34_firmware *)fw->data;
|
||||
u32 image_size = le32_to_cpu(syn_fw->image_size);
|
||||
u32 config_size = le32_to_cpu(syn_fw->config_size);
|
||||
int ret;
|
||||
|
||||
syn_fw = (const struct rmi_f34_firmware *)fw->data;
|
||||
BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
|
||||
F34_FW_IMAGE_OFFSET);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
|
||||
"FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n",
|
||||
(int)fw->size,
|
||||
"FW size:%zd, checksum:%08x, image_size:%d, config_size:%d\n",
|
||||
fw->size,
|
||||
le32_to_cpu(syn_fw->checksum),
|
||||
le32_to_cpu(syn_fw->image_size),
|
||||
le32_to_cpu(syn_fw->config_size));
|
||||
image_size, config_size);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
|
||||
"FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
|
||||
|
@ -246,27 +255,25 @@ int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
|
|||
(int)sizeof(syn_fw->product_id), syn_fw->product_id,
|
||||
syn_fw->product_info[0], syn_fw->product_info[1]);
|
||||
|
||||
if (syn_fw->image_size &&
|
||||
syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
|
||||
if (image_size && image_size != f34->v5.fw_blocks * f34->v5.block_size) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"Bad firmware image: fw size %d, expected %d\n",
|
||||
syn_fw->image_size,
|
||||
f34->v5.fw_blocks * f34->v5.block_size);
|
||||
image_size, f34->v5.fw_blocks * f34->v5.block_size);
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (syn_fw->config_size &&
|
||||
syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) {
|
||||
if (config_size &&
|
||||
config_size != f34->v5.config_blocks * f34->v5.block_size) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"Bad firmware image: config size %d, expected %d\n",
|
||||
syn_fw->config_size,
|
||||
config_size,
|
||||
f34->v5.config_blocks * f34->v5.block_size);
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (syn_fw->image_size && !syn_fw->config_size) {
|
||||
if (image_size && !config_size) {
|
||||
dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
|
@ -283,6 +290,63 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int rmi_f34_status(struct rmi_function *fn)
|
||||
{
|
||||
struct f34_data *f34 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
/*
|
||||
* The status is the percentage complete, or once complete,
|
||||
* zero for success or a negative return code.
|
||||
*/
|
||||
return f34->update_status;
|
||||
}
|
||||
|
||||
static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct rmi_function *fn = data->f34_container;
|
||||
struct f34_data *f34;
|
||||
|
||||
if (fn) {
|
||||
f34 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
if (f34->bl_version == 5)
|
||||
return scnprintf(buf, PAGE_SIZE, "%c%c\n",
|
||||
f34->bootloader_id[0],
|
||||
f34->bootloader_id[1]);
|
||||
else
|
||||
return scnprintf(buf, PAGE_SIZE, "V%d.%d\n",
|
||||
f34->bootloader_id[1],
|
||||
f34->bootloader_id[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL);
|
||||
|
||||
static ssize_t rmi_driver_configuration_id_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
struct rmi_function *fn = data->f34_container;
|
||||
struct f34_data *f34;
|
||||
|
||||
if (fn) {
|
||||
f34 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", f34->configuration_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(configuration_id, 0444,
|
||||
rmi_driver_configuration_id_show, NULL);
|
||||
|
||||
static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
|
@ -346,7 +410,13 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
|
|||
else
|
||||
ret = rmi_f34_update_firmware(f34, fw);
|
||||
|
||||
dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
|
||||
if (ret) {
|
||||
f34->update_status = ret;
|
||||
dev_err(&f34->fn->dev,
|
||||
"Firmware update failed, status: %d\n", ret);
|
||||
} else {
|
||||
dev_info(&f34->fn->dev, "Firmware update complete\n");
|
||||
}
|
||||
|
||||
rmi_disable_irq(rmi_dev, false);
|
||||
|
||||
|
@ -377,9 +447,6 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
const struct firmware *fw);
|
||||
|
||||
static ssize_t rmi_driver_update_fw_store(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
const char *buf, size_t count)
|
||||
|
@ -414,8 +481,27 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
|
||||
|
||||
static ssize_t rmi_driver_update_fw_status_show(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
char *buf)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
int update_status = 0;
|
||||
|
||||
if (data->f34_container)
|
||||
update_status = rmi_f34_status(data->f34_container);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", update_status);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(update_fw_status, 0444,
|
||||
rmi_driver_update_fw_status_show, NULL);
|
||||
|
||||
static struct attribute *rmi_firmware_attrs[] = {
|
||||
&dev_attr_bootloader_id.attr,
|
||||
&dev_attr_configuration_id.attr,
|
||||
&dev_attr_update_fw.attr,
|
||||
&dev_attr_update_fw_status.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -441,8 +527,6 @@ static int rmi_f34_probe(struct rmi_function *fn)
|
|||
/* v5 code only supported version 0, try V7 probe */
|
||||
if (version > 0)
|
||||
return rmi_f34v7_probe(f34);
|
||||
else if (version != 0)
|
||||
return -ENODEV;
|
||||
|
||||
f34->bl_version = 5;
|
||||
|
||||
|
|
|
@ -301,6 +301,10 @@ struct f34_data {
|
|||
unsigned char bootloader_id[5];
|
||||
unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
|
||||
|
||||
int update_status;
|
||||
int update_progress;
|
||||
int update_size;
|
||||
|
||||
union {
|
||||
struct f34v5_data v5;
|
||||
struct f34v7_data v7;
|
||||
|
|
|
@ -588,6 +588,7 @@ static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34)
|
|||
u16 block_count;
|
||||
|
||||
block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
|
||||
f34->update_size += block_count;
|
||||
|
||||
if (block_count != f34->v7.blkcount.ui_firmware) {
|
||||
dev_err(&f34->fn->dev,
|
||||
|
@ -604,6 +605,7 @@ static int rmi_f34v7_check_ui_config_size(struct f34_data *f34)
|
|||
u16 block_count;
|
||||
|
||||
block_count = f34->v7.img.ui_config.size / f34->v7.block_size;
|
||||
f34->update_size += block_count;
|
||||
|
||||
if (block_count != f34->v7.blkcount.ui_config) {
|
||||
dev_err(&f34->fn->dev, "UI config size mismatch\n");
|
||||
|
@ -618,6 +620,7 @@ static int rmi_f34v7_check_dp_config_size(struct f34_data *f34)
|
|||
u16 block_count;
|
||||
|
||||
block_count = f34->v7.img.dp_config.size / f34->v7.block_size;
|
||||
f34->update_size += block_count;
|
||||
|
||||
if (block_count != f34->v7.blkcount.dp_config) {
|
||||
dev_err(&f34->fn->dev, "Display config size mismatch\n");
|
||||
|
@ -632,6 +635,8 @@ static int rmi_f34v7_check_guest_code_size(struct f34_data *f34)
|
|||
u16 block_count;
|
||||
|
||||
block_count = f34->v7.img.guest_code.size / f34->v7.block_size;
|
||||
f34->update_size += block_count;
|
||||
|
||||
if (block_count != f34->v7.blkcount.guest_code) {
|
||||
dev_err(&f34->fn->dev, "Guest code size mismatch\n");
|
||||
return -EINVAL;
|
||||
|
@ -645,6 +650,7 @@ static int rmi_f34v7_check_bl_config_size(struct f34_data *f34)
|
|||
u16 block_count;
|
||||
|
||||
block_count = f34->v7.img.bl_config.size / f34->v7.block_size;
|
||||
f34->update_size += block_count;
|
||||
|
||||
if (block_count != f34->v7.blkcount.bl_config) {
|
||||
dev_err(&f34->fn->dev, "Bootloader config size mismatch\n");
|
||||
|
@ -881,6 +887,9 @@ static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34,
|
|||
|
||||
block_ptr += (transfer * f34->v7.block_size);
|
||||
remaining -= transfer;
|
||||
f34->update_progress += transfer;
|
||||
f34->update_status = (f34->update_progress * 100) /
|
||||
f34->update_size;
|
||||
} while (remaining);
|
||||
|
||||
return 0;
|
||||
|
@ -1191,6 +1200,8 @@ int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw)
|
|||
rmi_f34v7_read_queries_bl_version(f34);
|
||||
|
||||
f34->v7.image = fw->data;
|
||||
f34->update_progress = 0;
|
||||
f34->update_size = 0;
|
||||
|
||||
ret = rmi_f34v7_parse_image_info(f34);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -159,13 +159,12 @@ static int psif_open(struct serio *io)
|
|||
|
||||
retval = clk_enable(psif->pclk);
|
||||
if (retval)
|
||||
goto out;
|
||||
return retval;
|
||||
|
||||
psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
|
||||
psif_writel(psif, IER, PSIF_BIT(RXRDY));
|
||||
|
||||
psif->open = true;
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -210,16 +209,12 @@ static int __init psif_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
psif = kzalloc(sizeof(struct psif), GFP_KERNEL);
|
||||
if (!psif) {
|
||||
dev_dbg(&pdev->dev, "out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!psif)
|
||||
return -ENOMEM;
|
||||
psif->pdev = pdev;
|
||||
|
||||
io = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
if (!io) {
|
||||
dev_dbg(&pdev->dev, "out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_psif;
|
||||
}
|
||||
|
@ -297,7 +292,6 @@ out_free_io:
|
|||
kfree(io);
|
||||
out_free_psif:
|
||||
kfree(psif);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -402,7 +402,6 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
|
|||
{
|
||||
struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
|
||||
|
||||
device_init_wakeup(&hv_dev->device, false);
|
||||
serio_unregister_port(kbd_dev->hv_serio);
|
||||
vmbus_close(hv_dev->channel);
|
||||
kfree(kbd_dev);
|
||||
|
|
|
@ -923,6 +923,10 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
|
|||
.name = "i8042 kbd",
|
||||
.id_table = pnp_kbd_devids,
|
||||
.probe = i8042_pnp_kbd_probe,
|
||||
.driver = {
|
||||
.probe_type = PROBE_FORCE_SYNCHRONOUS,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static struct pnp_device_id pnp_aux_devids[] = {
|
||||
|
@ -945,6 +949,10 @@ static struct pnp_driver i8042_pnp_aux_driver = {
|
|||
.name = "i8042 aux",
|
||||
.id_table = pnp_aux_devids,
|
||||
.probe = i8042_pnp_aux_probe,
|
||||
.driver = {
|
||||
.probe_type = PROBE_FORCE_SYNCHRONOUS,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static void i8042_pnp_exit(void)
|
||||
|
|
|
@ -312,8 +312,10 @@ static int __i8042_command(unsigned char *param, int command)
|
|||
|
||||
for (i = 0; i < ((command >> 12) & 0xf); i++) {
|
||||
error = i8042_wait_write();
|
||||
if (error)
|
||||
if (error) {
|
||||
dbg(" -- i8042 (wait write timeout)\n");
|
||||
return error;
|
||||
}
|
||||
dbg("%02x -> i8042 (parameter)\n", param[i]);
|
||||
i8042_write_data(param[i]);
|
||||
}
|
||||
|
@ -321,7 +323,7 @@ static int __i8042_command(unsigned char *param, int command)
|
|||
for (i = 0; i < ((command >> 8) & 0xf); i++) {
|
||||
error = i8042_wait_read();
|
||||
if (error) {
|
||||
dbg(" -- i8042 (timeout)\n");
|
||||
dbg(" -- i8042 (wait read timeout)\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -243,18 +243,17 @@ static int xps2_of_probe(struct platform_device *ofdev)
|
|||
unsigned int irq;
|
||||
int error;
|
||||
|
||||
dev_info(dev, "Device Tree Probing \'%s\'\n",
|
||||
ofdev->dev.of_node->name);
|
||||
dev_info(dev, "Device Tree Probing \'%s\'\n", dev->of_node->name);
|
||||
|
||||
/* Get iospace for the device */
|
||||
error = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
|
||||
error = of_address_to_resource(dev->of_node, 0, &r_mem);
|
||||
if (error) {
|
||||
dev_err(dev, "invalid address\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Get IRQ for the device */
|
||||
irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
|
||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!irq) {
|
||||
dev_err(dev, "no IRQ found\n");
|
||||
return -ENODEV;
|
||||
|
|
|
@ -240,8 +240,6 @@ static int pm860x_touch_probe(struct platform_device *pdev)
|
|||
if (!touch)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, touch);
|
||||
|
||||
touch->idev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!touch->idev) {
|
||||
dev_err(&pdev->dev, "Failed to allocate input device!\n");
|
||||
|
@ -285,7 +283,6 @@ static int pm860x_touch_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, touch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -546,18 +546,6 @@ config TOUCHSCREEN_INEXIO
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called inexio.
|
||||
|
||||
config TOUCHSCREEN_INTEL_MID
|
||||
tristate "Intel MID platform resistive touchscreen"
|
||||
depends on INTEL_SCU_IPC
|
||||
help
|
||||
Say Y here if you have a Intel MID based touchscreen in
|
||||
your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called intel_mid_touch.
|
||||
|
||||
config TOUCHSCREEN_MK712
|
||||
tristate "ICS MicroClock MK712 touchscreen"
|
||||
help
|
||||
|
@ -1177,6 +1165,17 @@ config TOUCHSCREEN_TPS6507X
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called tps6507x_ts.
|
||||
|
||||
config TOUCHSCREEN_ZET6223
|
||||
tristate "Zeitec ZET6223 touchscreen driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have a touchscreen using Zeitec ZET6223
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called zet6223.
|
||||
|
||||
config TOUCHSCREEN_ZFORCE
|
||||
tristate "Neonode zForce infrared touchscreens"
|
||||
depends on I2C
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче