Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:
 "Just one new driver (Cypress StreetFighter touchkey), and no input
  core changes this time.

  Plus various fixes and enhancements to existing drivers"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (54 commits)
  Input: iforce - fix control-message timeout
  Input: wacom_i2c - use macros for the bit masks
  Input: ili210x - reduce sample period to 15ms
  Input: ili210x - improve polled sample spacing
  Input: ili210x - special case ili251x sample read out
  Input: elantench - fix misreporting trackpoint coordinates
  Input: synaptics-rmi4 - Fix device hierarchy
  Input: i8042 - Add quirk for Fujitsu Lifebook T725
  Input: cap11xx - add support for cap1206
  Input: remove unused header <linux/input/cy8ctmg110_pdata.h>
  Input: ili210x - add ili251x firmware update support
  Input: ili210x - export ili251x version details via sysfs
  Input: ili210x - use resolution from ili251x firmware
  Input: pm8941-pwrkey - respect reboot_mode for warm reset
  reboot: export symbol 'reboot_mode'
  Input: max77693-haptic - drop unneeded MODULE_ALIAS
  Input: cpcap-pwrbutton - do not set input parent explicitly
  Input: max8925_onkey - don't mark comment as kernel-doc
  Input: ads7846 - do not attempt IRQ workaround when deferring probe
  Input: ads7846 - use input_set_capability()
  ...
This commit is contained in:
Linus Torvalds 2021-11-12 11:53:16 -08:00
commit f78e9de80f
45 changed files with 1853 additions and 480 deletions

View File

@ -0,0 +1,61 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/cypress-sf.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cypress StreetFighter touchkey controller
maintainers:
- Yassine Oudjana <y.oudjana@protonmail.com>
allOf:
- $ref: input.yaml#
properties:
compatible:
const: cypress,sf3155
reg:
maxItems: 1
interrupts:
maxItems: 1
avdd-supply:
description: Regulator for AVDD analog voltage
vdd-supply:
description: Regulator for VDD digital voltage
linux,keycodes:
minItems: 1
maxItems: 8
required:
- compatible
- reg
- interrupts
- avdd-supply
- vdd-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchkey@28 {
compatible = "cypress,sf3155";
reg = <0x28>;
interrupt-parent = <&msmgpio>;
interrupts = <77 IRQ_TYPE_EDGE_FALLING>;
avdd-supply = <&vreg_l6a_1p8>;
vdd-supply = <&vdd_3v2_tp>;
linux,keycodes = <KEY_BACK KEY_MENU>;
};
};

View File

@ -19,6 +19,7 @@ properties:
- microchip,cap1106
- microchip,cap1126
- microchip,cap1188
- microchip,cap1206
reg:
maxItems: 1

View File

@ -4459,7 +4459,7 @@ CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
F: Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml
F: drivers/input/touchscreen/chipone_icn8318.c
CHIPONE ICN8505 I2C TOUCHSCREEN DRIVER
@ -5205,6 +5205,13 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/cy8ctma140.c
CYPRESS STREETFIGHTER TOUCHKEYS DRIVER
M: Yassine Oudjana <y.oudjana@protonmail.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/cypress-sf.yaml
F: drivers/input/keyboard/cypress-sf.c
CYTTSP TOUCHSCREEN DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-input@vger.kernel.org
@ -8063,9 +8070,10 @@ F: drivers/media/usb/go7007/
GOODIX TOUCHSCREEN
M: Bastien Nocera <hadess@hadess.net>
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/goodix.c
F: drivers/input/touchscreen/goodix*
GOOGLE ETHERNET DRIVERS
M: Jeroen de Borst <jeroendb@google.com>

View File

@ -19,6 +19,7 @@
#include <linux/input.h>
#include <linux/gameport.h>
#include <linux/jiffies.h>
#include <linux/seq_buf.h>
#include <linux/timex.h>
#include <linux/timekeeping.h>
@ -338,23 +339,24 @@ static void analog_calibrate_timer(struct analog_port *port)
static void analog_name(struct analog *analog)
{
snprintf(analog->name, sizeof(analog->name), "Analog %d-axis %d-button",
struct seq_buf s;
seq_buf_init(&s, analog->name, sizeof(analog->name));
seq_buf_printf(&s, "Analog %d-axis %d-button",
hweight8(analog->mask & ANALOG_AXES_STD),
hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
if (analog->mask & ANALOG_HATS_ALL)
snprintf(analog->name, sizeof(analog->name), "%s %d-hat",
analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
seq_buf_printf(&s, " %d-hat",
hweight16(analog->mask & ANALOG_HATS_ALL));
if (analog->mask & ANALOG_HAT_FCS)
strlcat(analog->name, " FCS", sizeof(analog->name));
seq_buf_printf(&s, " FCS");
if (analog->mask & ANALOG_ANY_CHF)
strlcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF",
sizeof(analog->name));
seq_buf_printf(&s, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
strlcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick",
sizeof(analog->name));
seq_buf_printf(&s, (analog->mask & ANALOG_GAMEPAD) ? " gamepad" : " joystick");
}
/*

View File

@ -92,7 +92,7 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 id,
id,
USB_TYPE_VENDOR | USB_DIR_IN |
USB_RECIP_INTERFACE,
0, 0, buf, IFORCE_MAX_LENGTH, HZ);
0, 0, buf, IFORCE_MAX_LENGTH, 1000);
if (status < 0) {
dev_err(&iforce_usb->intf->dev,
"usb_submit_urb failed: %d\n", status);

View File

@ -83,7 +83,7 @@ static const struct tmdc_model {
const signed char *axes;
const short *buttons;
} tmdc_models[] = {
{ 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
{ 1, "ThrustMaster Millennium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
{ 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
{ 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
{ 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },

View File

@ -788,4 +788,14 @@ config KEYBOARD_MTK_PMIC
To compile this driver as a module, choose M here: the
module will be called pmic-keys.
config KEYBOARD_CYPRESS_SF
tristate "Cypress StreetFighter touchkey support"
depends on I2C
help
Say Y here if you want to enable support for Cypress StreetFighter
touchkeys.
To compile this driver as a module, choose M here: the
module will be called cypress-sf.
endif

View File

@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o

View File

@ -91,18 +91,21 @@ struct cap11xx_hw_model {
u8 product_id;
unsigned int num_channels;
unsigned int num_leds;
bool no_gain;
};
enum {
CAP1106,
CAP1126,
CAP1188,
CAP1206,
};
static const struct cap11xx_hw_model cap11xx_devices[] = {
[CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0 },
[CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2 },
[CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8 },
[CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0, .no_gain = false },
[CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2, .no_gain = false },
[CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8, .no_gain = false },
[CAP1206] = { .product_id = 0x67, .num_channels = 6, .num_leds = 0, .no_gain = true },
};
static const struct reg_default cap11xx_reg_defaults[] = {
@ -378,17 +381,24 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
node = dev->of_node;
if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
if (is_power_of_2(gain32) && gain32 <= 8)
if (cap->no_gain)
dev_warn(dev,
"This version doesn't support sensor gain\n");
else if (is_power_of_2(gain32) && gain32 <= 8)
gain = ilog2(gain32);
else
dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
}
if (of_property_read_bool(node, "microchip,irq-active-high")) {
error = regmap_update_bits(priv->regmap, CAP11XX_REG_CONFIG2,
CAP11XX_REG_CONFIG2_ALT_POL, 0);
if (error)
return error;
if (id->driver_data != CAP1206) {
if (of_property_read_bool(node, "microchip,irq-active-high")) {
error = regmap_update_bits(priv->regmap,
CAP11XX_REG_CONFIG2,
CAP11XX_REG_CONFIG2_ALT_POL,
0);
if (error)
return error;
}
}
/* Provide some useful defaults */
@ -398,11 +408,14 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
of_property_read_u32_array(node, "linux,keycodes",
priv->keycodes, cap->num_channels);
error = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL,
CAP11XX_REG_MAIN_CONTROL_GAIN_MASK,
gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT);
if (error)
return error;
if (!cap->no_gain) {
error = regmap_update_bits(priv->regmap,
CAP11XX_REG_MAIN_CONTROL,
CAP11XX_REG_MAIN_CONTROL_GAIN_MASK,
gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT);
if (error)
return error;
}
/* Disable autorepeat. The Linux input system has its own handling. */
error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
@ -470,6 +483,7 @@ static const struct of_device_id cap11xx_dt_ids[] = {
{ .compatible = "microchip,cap1106", },
{ .compatible = "microchip,cap1126", },
{ .compatible = "microchip,cap1188", },
{ .compatible = "microchip,cap1206", },
{}
};
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
@ -478,6 +492,7 @@ static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ "cap1106", CAP1106 },
{ "cap1126", CAP1126 },
{ "cap1188", CAP1188 },
{ "cap1206", CAP1206 },
{}
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);

View File

@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Cypress StreetFighter Touchkey Driver
*
* Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#define CYPRESS_SF_DEV_NAME "cypress-sf"
#define CYPRESS_SF_REG_BUTTON_STATUS 0x4a
struct cypress_sf_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct regulator_bulk_data regulators[2];
u32 *keycodes;
unsigned long keystates;
int num_keys;
};
static irqreturn_t cypress_sf_irq_handler(int irq, void *devid)
{
struct cypress_sf_data *touchkey = devid;
unsigned long keystates, changed;
bool new_state;
int val, key;
val = i2c_smbus_read_byte_data(touchkey->client,
CYPRESS_SF_REG_BUTTON_STATUS);
if (val < 0) {
dev_err(&touchkey->client->dev,
"Failed to read button status: %d", val);
return IRQ_NONE;
}
keystates = val;
bitmap_xor(&changed, &keystates, &touchkey->keystates,
touchkey->num_keys);
for_each_set_bit(key, &changed, touchkey->num_keys) {
new_state = keystates & BIT(key);
dev_dbg(&touchkey->client->dev,
"Key %d changed to %d", key, new_state);
input_report_key(touchkey->input_dev,
touchkey->keycodes[key], new_state);
}
input_sync(touchkey->input_dev);
touchkey->keystates = keystates;
return IRQ_HANDLED;
}
static int cypress_sf_probe(struct i2c_client *client)
{
struct cypress_sf_data *touchkey;
int key, error;
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 = "vdd";
touchkey->regulators[1].supply = "avdd";
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;
}
touchkey->num_keys = device_property_read_u32_array(&client->dev,
"linux,keycodes",
NULL, 0);
if (touchkey->num_keys < 0) {
/* Default key count */
touchkey->num_keys = 2;
}
touchkey->keycodes = devm_kcalloc(&client->dev,
touchkey->num_keys,
sizeof(*touchkey->keycodes),
GFP_KERNEL);
if (!touchkey->keycodes)
return -ENOMEM;
error = device_property_read_u32_array(&client->dev, "linux,keycodes",
touchkey->keycodes,
touchkey->num_keys);
if (error) {
dev_warn(&client->dev,
"Failed to read keycodes: %d, using defaults\n",
error);
/* Default keycodes */
touchkey->keycodes[0] = KEY_BACK;
touchkey->keycodes[1] = KEY_MENU;
}
error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(&client->dev,
"Failed to enable regulators: %d\n", error);
return error;
}
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 = CYPRESS_SF_DEV_NAME;
touchkey->input_dev->id.bustype = BUS_I2C;
for (key = 0; key < touchkey->num_keys; ++key)
input_set_capability(touchkey->input_dev,
EV_KEY, touchkey->keycodes[key]);
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, cypress_sf_irq_handler,
IRQF_ONESHOT,
CYPRESS_SF_DEV_NAME, touchkey);
if (error) {
dev_err(&client->dev,
"Failed to register threaded irq: %d", error);
return error;
}
return 0;
};
static int __maybe_unused cypress_sf_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
int error;
disable_irq(client->irq);
error = regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(dev, "Failed to disable regulators: %d", error);
enable_irq(client->irq);
return error;
}
return 0;
}
static int __maybe_unused cypress_sf_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cypress_sf_data *touchkey = i2c_get_clientdata(client);
int error;
error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
if (error) {
dev_err(dev, "Failed to enable regulators: %d", error);
return error;
}
enable_irq(client->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
cypress_sf_suspend, cypress_sf_resume);
static struct i2c_device_id cypress_sf_id_table[] = {
{ CYPRESS_SF_DEV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
#ifdef CONFIG_OF
static const struct of_device_id cypress_sf_of_match[] = {
{ .compatible = "cypress,sf3155", },
{ },
};
MODULE_DEVICE_TABLE(of, cypress_sf_of_match);
#endif
static struct i2c_driver cypress_sf_driver = {
.driver = {
.name = CYPRESS_SF_DEV_NAME,
.pm = &cypress_sf_pm_ops,
.of_match_table = of_match_ptr(cypress_sf_of_match),
},
.id_table = cypress_sf_id_table,
.probe_new = cypress_sf_probe,
};
module_i2c_driver(cypress_sf_driver);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver");
MODULE_LICENSE("GPL v2");

View File

@ -17,6 +17,7 @@
* flag.
*/
#include <linux/bits.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@ -26,6 +27,7 @@
#include <linux/slab.h>
#include <linux/soc/cirrus/ep93xx.h>
#include <linux/platform_data/keypad-ep93xx.h>
#include <linux/pm_wakeirq.h>
/*
* Keypad Interface Register offsets
@ -35,28 +37,28 @@
#define KEY_REG 0x08 /* Key Value Capture register */
/* Key Scan Initialization Register bit defines */
#define KEY_INIT_DBNC_MASK (0x00ff0000)
#define KEY_INIT_DBNC_SHIFT (16)
#define KEY_INIT_DIS3KY (1<<15)
#define KEY_INIT_DIAG (1<<14)
#define KEY_INIT_BACK (1<<13)
#define KEY_INIT_T2 (1<<12)
#define KEY_INIT_PRSCL_MASK (0x000003ff)
#define KEY_INIT_PRSCL_SHIFT (0)
#define KEY_INIT_DBNC_MASK GENMASK(23, 16)
#define KEY_INIT_DBNC_SHIFT 16
#define KEY_INIT_DIS3KY BIT(15)
#define KEY_INIT_DIAG BIT(14)
#define KEY_INIT_BACK BIT(13)
#define KEY_INIT_T2 BIT(12)
#define KEY_INIT_PRSCL_MASK GENMASK(9, 0)
#define KEY_INIT_PRSCL_SHIFT 0
/* Key Scan Diagnostic Register bit defines */
#define KEY_DIAG_MASK (0x0000003f)
#define KEY_DIAG_SHIFT (0)
#define KEY_DIAG_MASK GENMASK(5, 0)
#define KEY_DIAG_SHIFT 0
/* Key Value Capture Register bit defines */
#define KEY_REG_K (1<<15)
#define KEY_REG_INT (1<<14)
#define KEY_REG_2KEYS (1<<13)
#define KEY_REG_1KEY (1<<12)
#define KEY_REG_KEY2_MASK (0x00000fc0)
#define KEY_REG_KEY2_SHIFT (6)
#define KEY_REG_KEY1_MASK (0x0000003f)
#define KEY_REG_KEY1_SHIFT (0)
#define KEY_REG_K BIT(15)
#define KEY_REG_INT BIT(14)
#define KEY_REG_2KEYS BIT(13)
#define KEY_REG_1KEY BIT(12)
#define KEY_REG_KEY2_MASK GENMASK(11, 6)
#define KEY_REG_KEY2_SHIFT 6
#define KEY_REG_KEY1_MASK GENMASK(5, 0)
#define KEY_REG_KEY1_SHIFT 0
#define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS)
@ -175,8 +177,7 @@ static void ep93xx_keypad_close(struct input_dev *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int ep93xx_keypad_suspend(struct device *dev)
static int __maybe_unused ep93xx_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
@ -191,21 +192,15 @@ static int ep93xx_keypad_suspend(struct device *dev)
mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(keypad->irq);
return 0;
}
static int ep93xx_keypad_resume(struct device *dev)
static int __maybe_unused ep93xx_keypad_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(keypad->irq);
mutex_lock(&input_dev->mutex);
if (input_device_enabled(input_dev)) {
@ -220,11 +215,17 @@ static int ep93xx_keypad_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
ep93xx_keypad_suspend, ep93xx_keypad_resume);
static void ep93xx_keypad_release_gpio_action(void *_pdev)
{
struct platform_device *pdev = _pdev;
ep93xx_keypad_release_gpio(pdev);
}
static int ep93xx_keypad_probe(struct platform_device *pdev)
{
struct ep93xx_keypad *keypad;
@ -233,61 +234,46 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
struct resource *res;
int err;
keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL);
keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad)
return -ENOMEM;
keypad->pdata = dev_get_platdata(&pdev->dev);
if (!keypad->pdata) {
err = -EINVAL;
goto failed_free;
}
if (!keypad->pdata)
return -EINVAL;
keymap_data = keypad->pdata->keymap_data;
if (!keymap_data) {
err = -EINVAL;
goto failed_free;
}
if (!keymap_data)
return -EINVAL;
keypad->irq = platform_get_irq(pdev, 0);
if (keypad->irq < 0) {
err = keypad->irq;
goto failed_free;
}
if (keypad->irq < 0)
return keypad->irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
err = -ENXIO;
goto failed_free;
}
if (!res)
return -ENXIO;
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
err = -EBUSY;
goto failed_free;
}
keypad->mmio_base = ioremap(res->start, resource_size(res));
if (keypad->mmio_base == NULL) {
err = -ENXIO;
goto failed_free_mem;
}
keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(keypad->mmio_base))
return PTR_ERR(keypad->mmio_base);
err = ep93xx_keypad_acquire_gpio(pdev);
if (err)
goto failed_free_io;
return err;
keypad->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk)) {
err = PTR_ERR(keypad->clk);
goto failed_free_gpio;
}
err = devm_add_action_or_reset(&pdev->dev,
ep93xx_keypad_release_gpio_action, pdev);
if (err)
return err;
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
goto failed_put_clk;
}
keypad->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk))
return PTR_ERR(keypad->clk);
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
keypad->input_dev = input_dev;
@ -295,70 +281,40 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
input_dev->id.bustype = BUS_HOST;
input_dev->open = ep93xx_keypad_open;
input_dev->close = ep93xx_keypad_close;
input_dev->dev.parent = &pdev->dev;
err = matrix_keypad_build_keymap(keymap_data, NULL,
EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
keypad->keycodes, input_dev);
if (err)
goto failed_free_dev;
return err;
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
__set_bit(EV_REP, input_dev->evbit);
input_set_drvdata(input_dev, keypad);
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
0, pdev->name, keypad);
err = devm_request_irq(&pdev->dev, keypad->irq,
ep93xx_keypad_irq_handler,
0, pdev->name, keypad);
if (err)
goto failed_free_dev;
return err;
err = input_register_device(input_dev);
if (err)
goto failed_free_irq;
return err;
platform_set_drvdata(pdev, keypad);
device_init_wakeup(&pdev->dev, 1);
err = dev_pm_set_wake_irq(&pdev->dev, keypad->irq);
if (err)
dev_warn(&pdev->dev, "failed to set up wakeup irq: %d\n", err);
return 0;
failed_free_irq:
free_irq(keypad->irq, keypad);
failed_free_dev:
input_free_device(input_dev);
failed_put_clk:
clk_put(keypad->clk);
failed_free_gpio:
ep93xx_keypad_release_gpio(pdev);
failed_free_io:
iounmap(keypad->mmio_base);
failed_free_mem:
release_mem_region(res->start, resource_size(res));
failed_free:
kfree(keypad);
return err;
}
static int ep93xx_keypad_remove(struct platform_device *pdev)
{
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
free_irq(keypad->irq, keypad);
if (keypad->enabled)
clk_disable(keypad->clk);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
ep93xx_keypad_release_gpio(pdev);
iounmap(keypad->mmio_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
kfree(keypad);
dev_pm_clear_wake_irq(&pdev->dev);
return 0;
}

View File

@ -107,9 +107,9 @@ static struct regulator *mpr121_vdd_supply_init(struct device *dev)
return ERR_PTR(err);
}
err = devm_add_action(dev, mpr121_vdd_supply_disable, vdd_supply);
err = devm_add_action_or_reset(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);

View File

@ -190,8 +190,7 @@ static int omap_kp_probe(struct platform_device *pdev)
row_shift = get_count_order(pdata->cols);
keycodemax = pdata->rows << row_shift;
omap_kp = kzalloc(sizeof(struct omap_kp) +
keycodemax * sizeof(unsigned short), GFP_KERNEL);
omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL);
input_dev = input_allocate_device();
if (!omap_kp || !input_dev) {
kfree(omap_kp);

View File

@ -156,6 +156,8 @@ static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid)
goto out;
}
input_event(touchkey->input_dev, EV_MSC, MSC_SCAN, index);
if (data & TM2_TOUCHKEY_BIT_PRESS_EV) {
for (i = 0; i < touchkey->num_keycodes; i++)
input_report_key(touchkey->input_dev,
@ -250,6 +252,11 @@ static int tm2_touchkey_probe(struct i2c_client *client,
touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
touchkey->input_dev->id.bustype = BUS_I2C;
touchkey->input_dev->keycode = touchkey->keycodes;
touchkey->input_dev->keycodemax = touchkey->num_keycodes;
touchkey->input_dev->keycodesize = sizeof(touchkey->keycodes[0]);
input_set_capability(touchkey->input_dev, EV_MSC, MSC_SCAN);
for (i = 0; i < touchkey->num_keycodes; i++)
input_set_capability(touchkey->input_dev, EV_KEY,
touchkey->keycodes[i]);

View File

@ -103,7 +103,9 @@ static int adxl34x_i2c_remove(struct i2c_client *client)
{
struct adxl34x *ac = i2c_get_clientdata(client);
return adxl34x_remove(ac);
adxl34x_remove(ac);
return 0;
}
static int __maybe_unused adxl34x_i2c_suspend(struct device *dev)

View File

@ -91,7 +91,9 @@ static int adxl34x_spi_remove(struct spi_device *spi)
{
struct adxl34x *ac = spi_get_drvdata(spi);
return adxl34x_remove(ac);
adxl34x_remove(ac);
return 0;
}
static int __maybe_unused adxl34x_spi_suspend(struct device *dev)

View File

@ -237,7 +237,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
{
short buf[3];
__le16 buf[3];
ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
@ -896,15 +896,13 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
}
EXPORT_SYMBOL_GPL(adxl34x_probe);
int adxl34x_remove(struct adxl34x *ac)
void adxl34x_remove(struct adxl34x *ac)
{
sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
free_irq(ac->irq, ac);
input_unregister_device(ac->input);
dev_dbg(ac->dev, "unregistered accelerometer\n");
kfree(ac);
return 0;
}
EXPORT_SYMBOL_GPL(adxl34x_remove);

View File

@ -25,6 +25,6 @@ void adxl34x_resume(struct adxl34x *ac);
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
bool fifo_delay_default,
const struct adxl34x_bus_ops *bops);
int adxl34x_remove(struct adxl34x *ac);
void adxl34x_remove(struct adxl34x *ac);
#endif

View File

@ -149,12 +149,19 @@ static const struct of_device_id ariel_pwrbutton_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
static const struct spi_device_id ariel_pwrbutton_spi_ids[] = {
{ .name = "wyse-ariel-ec-input" },
{ }
};
MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_spi_ids);
static struct spi_driver ariel_pwrbutton_driver = {
.driver = {
.name = "dell-wyse-ariel-ec-input",
.of_match_table = ariel_pwrbutton_of_match,
},
.probe = ariel_pwrbutton_probe,
.id_table = ariel_pwrbutton_spi_ids,
};
module_spi_driver(ariel_pwrbutton_driver);

View File

@ -54,9 +54,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button)
static int cpcap_power_button_probe(struct platform_device *pdev)
{
struct cpcap_power_button *button;
int irq = platform_get_irq(pdev, 0);
int irq;
int err;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
if (!button)
return -ENOMEM;
@ -73,7 +77,6 @@ static int cpcap_power_button_probe(struct platform_device *pdev)
button->idev->name = "cpcap-pwrbutton";
button->idev->phys = "cpcap-pwrbutton/input0";
button->idev->dev.parent = button->dev;
input_set_capability(button->idev, EV_KEY, KEY_POWER);
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,

View File

@ -424,5 +424,4 @@ module_platform_driver(max77693_haptic_driver);
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver");
MODULE_ALIAS("platform:max77693-haptic");
MODULE_LICENSE("GPL");

View File

@ -1,4 +1,4 @@
/**
/*
* MAX8925 ONKEY driver
*
* Copyright (C) 2009 Marvell International Ltd.

View File

@ -210,6 +210,11 @@ static int palmas_pwron_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
pwron->irq = platform_get_irq(pdev, 0);
if (pwron->irq < 0) {
error = pwron->irq;
goto err_free_input;
}
error = request_threaded_irq(pwron->irq, NULL, pwron_irq,
IRQF_TRIGGER_HIGH |
IRQF_TRIGGER_LOW |

View File

@ -29,6 +29,7 @@
#define PON_PS_HOLD_RST_CTL2 0x5b
#define PON_PS_HOLD_ENABLE BIT(7)
#define PON_PS_HOLD_TYPE_MASK 0x0f
#define PON_PS_HOLD_TYPE_WARM_RESET 1
#define PON_PS_HOLD_TYPE_SHUTDOWN 4
#define PON_PS_HOLD_TYPE_HARD_RESET 7
@ -99,7 +100,10 @@ static int pm8941_reboot_notify(struct notifier_block *nb,
break;
case SYS_RESTART:
default:
reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
if (reboot_mode == REBOOT_WARM)
reset_type = PON_PS_HOLD_TYPE_WARM_RESET;
else
reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
break;
}

View File

@ -517,6 +517,19 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
case 0x16008020U:
case 0x26800010U:
case 0x36808000U:
/*
* This firmware misreport coordinates for trackpoint
* occasionally. Discard packets outside of [-127, 127] range
* to prevent cursor jumps.
*/
if (packet[4] == 0x80 || packet[5] == 0x80 ||
packet[1] >> 7 == packet[4] >> 7 ||
packet[2] >> 7 == packet[5] >> 7) {
elantech_debug("discarding packet [%6ph]\n", packet);
break;
}
x = packet[4] - (int)((packet[1]^0x80) << 1);
y = (int)((packet[2]^0x80) << 1) - packet[5];

View File

@ -90,6 +90,7 @@ int rmi_register_transport_device(struct rmi_transport_dev *xport)
rmi_dev->dev.bus = &rmi_bus_type;
rmi_dev->dev.type = &rmi_device_type;
rmi_dev->dev.parent = xport->dev;
xport->rmi_dev = rmi_dev;

View File

@ -272,6 +272,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
},
},
{
/* Fujitsu Lifebook T725 laptop */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
},
},
{
/* Fujitsu Lifebook U745 */
.matches = {
@ -840,6 +847,13 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
},
},
{
/* Fujitsu Lifebook T725 laptop */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
},
},
{
/* Fujitsu U574 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */

View File

@ -425,6 +425,7 @@ config TOUCHSCREEN_HYCON_HY46XX
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
select CRC_CCITT
help
Say Y here if you have a ILI210X based touchscreen
controller. This driver supports models ILI2102,

View File

@ -6,6 +6,7 @@
# Each configuration option enables a list of files.
wm97xx-ts-y := wm97xx-core.o
goodix_ts-y := goodix.o goodix_fwupload.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
@ -44,7 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o

View File

@ -101,10 +101,6 @@ struct ads7846 {
struct spi_device *spi;
struct regulator *reg;
#if IS_ENABLED(CONFIG_HWMON)
struct device *hwmon;
#endif
u16 model;
u16 vref_mv;
u16 vref_delay_usecs;
@ -142,13 +138,18 @@ struct ads7846 {
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
int gpio_pendown;
void (*wait_for_sync)(void);
};
enum ads7846_filter {
ADS7846_FILTER_OK,
ADS7846_FILTER_REPEAT,
ADS7846_FILTER_IGNORE,
};
/* leave chip selected when we're done, for quicker re-select? */
#if 0
#define CS_CHANGE(xfer) ((xfer).cs_change = 1)
@ -549,6 +550,8 @@ __ATTRIBUTE_GROUPS(ads7846_attr);
static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
{
struct device *hwmon;
/* hwmon sensors need a reference voltage */
switch (ts->model) {
case 7846:
@ -569,17 +572,11 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
break;
}
ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias,
ts, ads7846_attr_groups);
hwmon = devm_hwmon_device_register_with_groups(&spi->dev,
spi->modalias, ts,
ads7846_attr_groups);
return PTR_ERR_OR_ZERO(ts->hwmon);
}
static void ads784x_hwmon_unregister(struct spi_device *spi,
struct ads7846 *ts)
{
if (ts->hwmon)
hwmon_device_unregister(ts->hwmon);
return PTR_ERR_OR_ZERO(hwmon);
}
#else
@ -588,11 +585,6 @@ static inline int ads784x_hwmon_register(struct spi_device *spi,
{
return 0;
}
static inline void ads784x_hwmon_unregister(struct spi_device *spi,
struct ads7846 *ts)
{
}
#endif
static ssize_t ads7846_pen_down_show(struct device *dev,
@ -1014,8 +1006,8 @@ static int ads7846_setup_pendown(struct spi_device *spi,
ts->get_pendown_state = pdata->get_pendown_state;
} else if (gpio_is_valid(pdata->gpio_pendown)) {
err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN,
"ads7846_pendown");
err = devm_gpio_request_one(&spi->dev, pdata->gpio_pendown,
GPIOF_IN, "ads7846_pendown");
if (err) {
dev_err(&spi->dev,
"failed to request/setup pendown GPIO%d: %d\n",
@ -1212,24 +1204,30 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
}
#endif
static void ads7846_regulator_disable(void *regulator)
{
regulator_disable(regulator);
}
static int ads7846_probe(struct spi_device *spi)
{
const struct ads7846_platform_data *pdata;
struct ads7846 *ts;
struct device *dev = &spi->dev;
struct ads7846_packet *packet;
struct input_dev *input_dev;
unsigned long irq_flags;
int err;
if (!spi->irq) {
dev_dbg(&spi->dev, "no IRQ?\n");
dev_dbg(dev, "no IRQ?\n");
return -EINVAL;
}
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_err(&spi->dev, "f(sample) %d KHz?\n",
(spi->max_speed_hz/SAMPLE_BITS)/1000);
dev_err(dev, "f(sample) %d KHz?\n",
(spi->max_speed_hz/SAMPLE_BITS)/1000);
return -EINVAL;
}
@ -1245,13 +1243,17 @@ static int ads7846_probe(struct spi_device *spi)
if (err < 0)
return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !packet || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
ts = devm_kzalloc(dev, sizeof(struct ads7846), GFP_KERNEL);
if (!ts)
return -ENOMEM;
packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL);
if (!packet)
return -ENOMEM;
input_dev = devm_input_allocate_device(dev);
if (!input_dev)
return -ENOMEM;
spi_set_drvdata(spi, ts);
@ -1262,13 +1264,11 @@ static int ads7846_probe(struct spi_device *spi)
mutex_init(&ts->lock);
init_waitqueue_head(&ts->wait);
pdata = dev_get_platdata(&spi->dev);
pdata = dev_get_platdata(dev);
if (!pdata) {
pdata = ads7846_probe_dt(&spi->dev);
if (IS_ERR(pdata)) {
err = PTR_ERR(pdata);
goto err_free_mem;
}
pdata = ads7846_probe_dt(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
ts->model = pdata->model ? : 7846;
@ -1276,15 +1276,7 @@ static int ads7846_probe(struct spi_device *spi)
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->vref_mv = pdata->vref_mv;
if (pdata->filter != NULL) {
if (pdata->filter_init != NULL) {
err = pdata->filter_init(pdata, &ts->filter_data);
if (err < 0)
goto err_free_mem;
}
ts->filter = pdata->filter;
ts->filter_cleanup = pdata->filter_cleanup;
} else if (pdata->debounce_max) {
if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
if (ts->debounce_max < 2)
ts->debounce_max = 2;
@ -1298,7 +1290,7 @@ static int ads7846_probe(struct spi_device *spi)
err = ads7846_setup_pendown(spi, ts, pdata);
if (err)
goto err_cleanup_filter;
return err;
if (pdata->penirq_recheck_delay_usecs)
ts->penirq_recheck_delay_usecs =
@ -1306,15 +1298,16 @@ static int ads7846_probe(struct spi_device *spi)
ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
input_dev->name = ts->name;
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_dev->id.bustype = BUS_SPI;
input_dev->id.product = pdata->model;
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
@ -1345,125 +1338,84 @@ static int ads7846_probe(struct spi_device *spi)
ads7846_setup_spi_msg(ts, pdata);
ts->reg = regulator_get(&spi->dev, "vcc");
ts->reg = devm_regulator_get(dev, "vcc");
if (IS_ERR(ts->reg)) {
err = PTR_ERR(ts->reg);
dev_err(&spi->dev, "unable to get regulator: %d\n", err);
goto err_free_gpio;
dev_err(dev, "unable to get regulator: %d\n", err);
return err;
}
err = regulator_enable(ts->reg);
if (err) {
dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
goto err_put_regulator;
dev_err(dev, "unable to enable regulator: %d\n", err);
return err;
}
err = devm_add_action_or_reset(dev, ads7846_regulator_disable, ts->reg);
if (err)
return err;
irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
irq_flags |= IRQF_ONESHOT;
err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
irq_flags, spi->dev.driver->name, ts);
if (err && !pdata->irq_flags) {
dev_info(&spi->dev,
err = devm_request_threaded_irq(dev, spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, dev->driver->name, ts);
if (err && err != -EPROBE_DEFER && !pdata->irq_flags) {
dev_info(dev,
"trying pin change workaround on irq %d\n", spi->irq);
irq_flags |= IRQF_TRIGGER_RISING;
err = request_threaded_irq(spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, spi->dev.driver->name, ts);
err = devm_request_threaded_irq(dev, spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, dev->driver->name,
ts);
}
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_disable_regulator;
dev_dbg(dev, "irq %d busy?\n", spi->irq);
return err;
}
err = ads784x_hwmon_register(spi, ts);
if (err)
goto err_free_irq;
return err;
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
dev_info(dev, "touchscreen, irq %d\n", spi->irq);
/*
* Take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
if (ts->model == 7845)
ads7845_read12_ser(&spi->dev, PWRDOWN);
ads7845_read12_ser(dev, PWRDOWN);
else
(void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
(void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux));
err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
err = devm_device_add_group(dev, &ads784x_attr_group);
if (err)
goto err_remove_hwmon;
return err;
err = input_register_device(input_dev);
if (err)
goto err_remove_attr_group;
return err;
device_init_wakeup(&spi->dev, pdata->wakeup);
device_init_wakeup(dev, pdata->wakeup);
/*
* If device does not carry platform data we must have allocated it
* when parsing DT data.
*/
if (!dev_get_platdata(&spi->dev))
devm_kfree(&spi->dev, (void *)pdata);
if (!dev_get_platdata(dev))
devm_kfree(dev, (void *)pdata);
return 0;
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
err_remove_hwmon:
ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
err_disable_regulator:
regulator_disable(ts->reg);
err_put_regulator:
regulator_put(ts->reg);
err_free_gpio:
if (!ts->get_pendown_state)
gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
err_free_mem:
input_free_device(input_dev);
kfree(packet);
kfree(ts);
return err;
}
static int ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
ads7846_disable(ts);
free_irq(ts->spi->irq, ts);
input_unregister_device(ts->input);
ads784x_hwmon_unregister(spi, ts);
regulator_put(ts->reg);
if (!ts->get_pendown_state) {
/*
* If we are not using specialized pendown method we must
* have been relying on gpio we set up ourselves.
*/
gpio_free(ts->gpio_pendown);
}
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
kfree(ts->packet);
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
ads7846_stop(ts);
return 0;
}

View File

@ -1439,11 +1439,11 @@ static int elants_i2c_probe(struct i2c_client *client)
if (error)
return error;
error = devm_add_action(&client->dev, elants_i2c_power_off, ts);
error = devm_add_action_or_reset(&client->dev,
elants_i2c_power_off, ts);
if (error) {
dev_err(&client->dev,
"failed to install power off action: %d\n", error);
elants_i2c_power_off(ts);
return error;
}

View File

@ -14,20 +14,15 @@
#include <linux/kernel.h>
#include <linux/dmi.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <asm/unaligned.h>
#include "goodix.h"
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
@ -38,22 +33,11 @@
#define GOODIX_CONTACT_SIZE 8
#define GOODIX_MAX_CONTACT_SIZE 9
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_MAX_KEYS 7
#define GOODIX_CONFIG_MIN_LENGTH 186
#define GOODIX_CONFIG_911_LENGTH 186
#define GOODIX_CONFIG_967_LENGTH 228
#define GOODIX_CONFIG_GT9X_LENGTH 240
#define GOODIX_CONFIG_MAX_LENGTH 240
/* Register defines */
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
#define GOODIX_BUFFER_STATUS_READY BIT(7)
#define GOODIX_HAVE_KEY BIT(4)
@ -68,55 +52,11 @@
#define ACPI_GPIO_SUPPORT
#endif
struct goodix_ts_data;
enum goodix_irq_pin_access_method {
IRQ_PIN_ACCESS_NONE,
IRQ_PIN_ACCESS_GPIO,
IRQ_PIN_ACCESS_ACPI_GPIO,
IRQ_PIN_ACCESS_ACPI_METHOD,
};
struct goodix_chip_data {
u16 config_addr;
int config_len;
int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
void (*calc_config_checksum)(struct goodix_ts_data *ts);
};
struct goodix_chip_id {
const char *id;
const struct goodix_chip_data *data;
};
#define GOODIX_ID_MAX_LEN 4
struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct goodix_chip_data *chip;
struct touchscreen_properties prop;
unsigned int max_touch_num;
unsigned int int_trigger_type;
struct regulator *avdd28;
struct regulator *vddio;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
char id[GOODIX_ID_MAX_LEN + 1];
u16 version;
const char *cfg_name;
bool reset_controller_at_probe;
bool load_cfg_from_disk;
struct completion firmware_loading_complete;
unsigned long irq_flags;
enum goodix_irq_pin_access_method irq_pin_access_method;
unsigned int contact_size;
u8 config[GOODIX_CONFIG_MAX_LENGTH];
unsigned short keymap[GOODIX_MAX_KEYS];
};
static int goodix_check_cfg_8(struct goodix_ts_data *ts,
const u8 *cfg, int len);
static int goodix_check_cfg_16(struct goodix_ts_data *ts,
@ -215,8 +155,7 @@ static const struct dmi_system_id inverted_x_screen[] = {
* @buf: raw write data buffer.
* @len: length of the buffer to write
*/
static int goodix_i2c_read(struct i2c_client *client,
u16 reg, u8 *buf, int len)
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len)
{
struct i2c_msg msgs[2];
__be16 wbuf = cpu_to_be16(reg);
@ -233,7 +172,13 @@ static int goodix_i2c_read(struct i2c_client *client,
msgs[1].buf = buf;
ret = i2c_transfer(client->adapter, msgs, 2);
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
if (ret >= 0)
ret = (ret == ARRAY_SIZE(msgs) ? 0 : -EIO);
if (ret)
dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d\n",
len, reg, ret);
return ret;
}
/**
@ -244,8 +189,7 @@ static int goodix_i2c_read(struct i2c_client *client,
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
unsigned len)
int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len)
{
u8 *addr_buf;
struct i2c_msg msg;
@ -265,11 +209,18 @@ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
msg.len = len + 2;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret >= 0)
ret = (ret == 1 ? 0 : -EIO);
kfree(addr_buf);
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
if (ret)
dev_err(&client->dev, "Error writing %d bytes to 0x%04x: %d\n",
len, reg, ret);
return ret;
}
static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
{
return goodix_i2c_write(client, reg, &value, sizeof(value));
}
@ -308,11 +259,8 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
do {
error = goodix_i2c_read(ts->client, addr, data,
header_contact_keycode_size);
if (error) {
dev_err(&ts->client->dev, "I2C transfer error: %d\n",
error);
if (error)
return error;
}
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
touch_num = data[0] & 0x0f;
@ -333,6 +281,11 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
return touch_num;
}
if (data[0] == 0 && ts->firmware_name) {
if (goodix_handle_fw_request(ts))
return 0;
}
usleep_range(1000, 2000); /* Poll every 1 - 2 ms */
} while (time_before(jiffies, max_timeout));
@ -435,9 +388,7 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
struct goodix_ts_data *ts = dev_id;
goodix_process_events(ts);
if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)
dev_err(&ts->client->dev, "I2C write end_cmd error\n");
goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
return IRQ_HANDLED;
}
@ -553,7 +504,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
* @cfg: config firmware to write to device
* @len: config data length
*/
static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
{
int error;
@ -562,11 +513,9 @@ static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
return error;
error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len);
if (error) {
dev_err(&ts->client->dev, "Failed to write config data: %d",
error);
if (error)
return error;
}
dev_dbg(&ts->client->dev, "Config sent successfully.");
/* Let the firmware reconfigure itself, so sleep for 10ms */
@ -651,21 +600,66 @@ static int goodix_irq_direction_input(struct goodix_ts_data *ts)
return -EINVAL; /* Never reached */
}
static int goodix_int_sync(struct goodix_ts_data *ts)
int goodix_int_sync(struct goodix_ts_data *ts)
{
int error;
error = goodix_irq_direction_output(ts, 0);
if (error)
return error;
goto error;
msleep(50); /* T5: 50ms */
error = goodix_irq_direction_input(ts);
if (error)
return error;
goto error;
return 0;
error:
dev_err(&ts->client->dev, "Controller irq sync failed.\n");
return error;
}
/**
* goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode
*
* @ts: goodix_ts_data pointer
*/
int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
error = gpiod_direction_output(ts->gpiod_rst, 0);
if (error)
goto error;
msleep(20); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
if (error)
goto error;
usleep_range(100, 2000); /* T3: > 100us */
error = gpiod_direction_output(ts->gpiod_rst, 1);
if (error)
goto error;
usleep_range(6000, 10000); /* T4: > 5ms */
/* end select I2C slave addr */
error = gpiod_direction_input(ts->gpiod_rst);
if (error)
goto error;
return 0;
error:
dev_err(&ts->client->dev, "Controller reset failed.\n");
return error;
}
/**
@ -677,36 +671,11 @@ static int goodix_reset(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
error = gpiod_direction_output(ts->gpiod_rst, 0);
error = goodix_reset_no_int_sync(ts);
if (error)
return error;
msleep(20); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
if (error)
return error;
usleep_range(100, 2000); /* T3: > 100us */
error = gpiod_direction_output(ts->gpiod_rst, 1);
if (error)
return error;
usleep_range(6000, 10000); /* T4: > 5ms */
/* end select I2C slave addr */
error = gpiod_direction_input(ts->gpiod_rst);
if (error)
return error;
error = goodix_int_sync(ts);
if (error)
return error;
return 0;
return goodix_int_sync(ts);
}
#ifdef ACPI_GPIO_SUPPORT
@ -931,14 +900,19 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int x_max, y_max;
int error;
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
ts->config, ts->chip->config_len);
if (error) {
dev_warn(&ts->client->dev, "Error reading config: %d\n",
error);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
/*
* On controllers where we need to upload the firmware
* (controllers without flash) ts->config already has the config
* at this point and the controller itself does not have it yet!
*/
if (!ts->firmware_name) {
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
ts->config, ts->chip->config_len);
if (error) {
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
}
}
ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
@ -966,10 +940,8 @@ static int goodix_read_version(struct goodix_ts_data *ts)
char id_str[GOODIX_ID_MAX_LEN + 1];
error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
dev_err(&ts->client->dev, "read version failed: %d\n", error);
if (error)
return error;
}
memcpy(id_str, buf, GOODIX_ID_MAX_LEN);
id_str[GOODIX_ID_MAX_LEN] = 0;
@ -995,13 +967,10 @@ static int goodix_i2c_test(struct i2c_client *client)
u8 test;
while (retry++ < 2) {
error = goodix_i2c_read(client, GOODIX_REG_ID,
&test, 1);
error = goodix_i2c_read(client, GOODIX_REG_ID, &test, 1);
if (!error)
return 0;
dev_err(&client->dev, "i2c test failed attempt %d: %d\n",
retry, error);
msleep(20);
}
@ -1130,7 +1099,16 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx)
struct goodix_ts_data *ts = ctx;
int error;
if (cfg) {
if (ts->firmware_name) {
if (!cfg)
goto err_release_cfg;
error = goodix_check_cfg(ts, cfg->data, cfg->size);
if (error)
goto err_release_cfg;
memcpy(ts->config, cfg->data, cfg->size);
} else if (cfg) {
/* send device configuration to the firmware */
error = goodix_send_cfg(ts, cfg->data, cfg->size);
if (error)
@ -1156,6 +1134,7 @@ static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct goodix_ts_data *ts;
const char *cfg_name;
int error;
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
@ -1205,10 +1184,8 @@ reset:
if (ts->reset_controller_at_probe) {
/* reset the controller */
error = goodix_reset(ts);
if (error) {
dev_err(&client->dev, "Controller reset failed.\n");
if (error)
return error;
}
}
error = goodix_i2c_test(client);
@ -1223,20 +1200,27 @@ reset:
return error;
}
error = goodix_read_version(ts);
if (error) {
dev_err(&client->dev, "Read version failed.\n");
error = goodix_firmware_check(ts);
if (error)
return error;
error = goodix_read_version(ts);
if (error)
return error;
}
ts->chip = goodix_get_chip_data(ts->id);
if (ts->load_cfg_from_disk) {
/* update device config */
ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
"goodix_%s_cfg.bin", ts->id);
if (!ts->cfg_name)
return -ENOMEM;
error = device_property_read_string(&client->dev,
"goodix,config-name",
&cfg_name);
if (!error)
snprintf(ts->cfg_name, sizeof(ts->cfg_name),
"goodix/%s", cfg_name);
else
snprintf(ts->cfg_name, sizeof(ts->cfg_name),
"goodix_%s_cfg.bin", ts->id);
error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
&client->dev, GFP_KERNEL, ts,
@ -1286,6 +1270,9 @@ static int __maybe_unused goodix_suspend(struct device *dev)
/* Free IRQ as IRQ pin is used as output in the suspend sequence */
goodix_free_irq(ts);
/* Save reference (calibration) info if necessary */
goodix_save_bak_ref(ts);
/* Output LOW on the INT pin for 5 ms */
error = goodix_irq_direction_output(ts, 0);
if (error) {
@ -1298,7 +1285,6 @@ static int __maybe_unused goodix_suspend(struct device *dev)
error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
GOODIX_CMD_SCREEN_OFF);
if (error) {
dev_err(&ts->client->dev, "Screen off command failed\n");
goodix_irq_direction_input(ts);
goodix_request_irq(ts);
return -EAGAIN;
@ -1341,19 +1327,14 @@ static int __maybe_unused goodix_resume(struct device *dev)
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
&config_ver, 1);
if (error)
dev_warn(dev, "Error reading config version: %d, resetting controller\n",
error);
else if (config_ver != ts->config[0])
if (!error && config_ver != ts->config[0])
dev_info(dev, "Config version mismatch %d != %d, resetting controller\n",
config_ver, ts->config[0]);
if (error != 0 || config_ver != ts->config[0]) {
error = goodix_reset(ts);
if (error) {
dev_err(dev, "Controller reset failed.\n");
if (error)
return error;
}
error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
if (error)

View File

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __GOODIX_H__
#define __GOODIX_H__
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/regulator/consumer.h>
/* Register defines */
#define GOODIX_REG_MISCTL_DSP_CTL 0x4010
#define GOODIX_REG_MISCTL_SRAM_BANK 0x4048
#define GOODIX_REG_MISCTL_MEM_CD_EN 0x4049
#define GOODIX_REG_MISCTL_CACHE_EN 0x404B
#define GOODIX_REG_MISCTL_TMR0_EN 0x40B0
#define GOODIX_REG_MISCTL_SWRST 0x4180
#define GOODIX_REG_MISCTL_CPU_SWRST_PULSE 0x4184
#define GOODIX_REG_MISCTL_BOOTCTL 0x4190
#define GOODIX_REG_MISCTL_BOOT_OPT 0x4218
#define GOODIX_REG_MISCTL_BOOT_CTL 0x5094
#define GOODIX_REG_FW_SIG 0x8000
#define GOODIX_FW_SIG_LEN 10
#define GOODIX_REG_MAIN_CLK 0x8020
#define GOODIX_MAIN_CLK_LEN 6
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_REG_SW_WDT 0x8041
#define GOODIX_REG_REQUEST 0x8043
#define GOODIX_RQST_RESPONDED 0x00
#define GOODIX_RQST_CONFIG 0x01
#define GOODIX_RQST_BAK_REF 0x02
#define GOODIX_RQST_RESET 0x03
#define GOODIX_RQST_MAIN_CLOCK 0x04
/*
* Unknown request which gets send by the controller aprox.
* every 34 seconds once it is up and running.
*/
#define GOODIX_RQST_UNKNOWN 0x06
#define GOODIX_RQST_IDLE 0xFF
#define GOODIX_REG_STATUS 0x8044
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_BAK_REF 0x99D0
#define GOODIX_ID_MAX_LEN 4
#define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_MAX_KEYS 7
enum goodix_irq_pin_access_method {
IRQ_PIN_ACCESS_NONE,
IRQ_PIN_ACCESS_GPIO,
IRQ_PIN_ACCESS_ACPI_GPIO,
IRQ_PIN_ACCESS_ACPI_METHOD,
};
struct goodix_ts_data;
struct goodix_chip_data {
u16 config_addr;
int config_len;
int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
void (*calc_config_checksum)(struct goodix_ts_data *ts);
};
struct goodix_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct goodix_chip_data *chip;
const char *firmware_name;
struct touchscreen_properties prop;
unsigned int max_touch_num;
unsigned int int_trigger_type;
struct regulator *avdd28;
struct regulator *vddio;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
char id[GOODIX_ID_MAX_LEN + 1];
char cfg_name[64];
u16 version;
bool reset_controller_at_probe;
bool load_cfg_from_disk;
struct completion firmware_loading_complete;
unsigned long irq_flags;
enum goodix_irq_pin_access_method irq_pin_access_method;
unsigned int contact_size;
u8 config[GOODIX_CONFIG_MAX_LENGTH];
unsigned short keymap[GOODIX_MAX_KEYS];
u8 main_clk[GOODIX_MAIN_CLK_LEN];
int bak_ref_len;
u8 *bak_ref;
};
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len);
int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value);
int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len);
int goodix_int_sync(struct goodix_ts_data *ts);
int goodix_reset_no_int_sync(struct goodix_ts_data *ts);
int goodix_firmware_check(struct goodix_ts_data *ts);
bool goodix_handle_fw_request(struct goodix_ts_data *ts);
void goodix_save_bak_ref(struct goodix_ts_data *ts);
#endif

View File

@ -0,0 +1,427 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Goodix Touchscreen firmware upload support
*
* Copyright (c) 2021 Hans de Goede <hdegoede@redhat.com>
*
* This is a rewrite of gt9xx_update.c from the Allwinner H3 BSP which is:
* Copyright (c) 2010 - 2012 Goodix Technology.
* Author: andrew@goodix.com
*/
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include "goodix.h"
#define GOODIX_FW_HEADER_LENGTH sizeof(struct goodix_fw_header)
#define GOODIX_FW_SECTION_LENGTH 0x2000
#define GOODIX_FW_DSP_LENGTH 0x1000
#define GOODIX_FW_UPLOAD_ADDRESS 0xc000
#define GOODIX_CFG_LOC_HAVE_KEY 7
#define GOODIX_CFG_LOC_DRVA_NUM 27
#define GOODIX_CFG_LOC_DRVB_NUM 28
#define GOODIX_CFG_LOC_SENS_NUM 29
struct goodix_fw_header {
u8 hw_info[4];
u8 pid[8];
u8 vid[2];
} __packed;
static u16 goodix_firmware_checksum(const u8 *data, int size)
{
u16 checksum = 0;
int i;
for (i = 0; i < size; i += 2)
checksum += (data[i] << 8) + data[i + 1];
return checksum;
}
static int goodix_firmware_verify(struct device *dev, const struct firmware *fw)
{
const struct goodix_fw_header *fw_header;
size_t expected_size;
const u8 *data;
u16 checksum;
char buf[9];
expected_size = GOODIX_FW_HEADER_LENGTH + 4 * GOODIX_FW_SECTION_LENGTH +
GOODIX_FW_DSP_LENGTH;
if (fw->size != expected_size) {
dev_err(dev, "Firmware has wrong size, expected %zu got %zu\n",
expected_size, fw->size);
return -EINVAL;
}
data = fw->data + GOODIX_FW_HEADER_LENGTH;
checksum = goodix_firmware_checksum(data, 4 * GOODIX_FW_SECTION_LENGTH);
if (checksum) {
dev_err(dev, "Main firmware checksum error\n");
return -EINVAL;
}
data += 4 * GOODIX_FW_SECTION_LENGTH;
checksum = goodix_firmware_checksum(data, GOODIX_FW_DSP_LENGTH);
if (checksum) {
dev_err(dev, "DSP firmware checksum error\n");
return -EINVAL;
}
fw_header = (const struct goodix_fw_header *)fw->data;
dev_info(dev, "Firmware hardware info %02x%02x%02x%02x\n",
fw_header->hw_info[0], fw_header->hw_info[1],
fw_header->hw_info[2], fw_header->hw_info[3]);
/* pid is a 8 byte buffer containing a string, weird I know */
memcpy(buf, fw_header->pid, 8);
buf[8] = 0;
dev_info(dev, "Firmware PID: %s VID: %02x%02x\n", buf,
fw_header->vid[0], fw_header->vid[1]);
return 0;
}
static int goodix_enter_upload_mode(struct i2c_client *client)
{
int tries, error;
u8 val;
tries = 200;
do {
error = goodix_i2c_write_u8(client,
GOODIX_REG_MISCTL_SWRST, 0x0c);
if (error)
return error;
error = goodix_i2c_read(client,
GOODIX_REG_MISCTL_SWRST, &val, 1);
if (error)
return error;
if (val == 0x0c)
break;
} while (--tries);
if (!tries) {
dev_err(&client->dev, "Error could not hold ss51 & dsp\n");
return -EIO;
}
/* DSP_CK and DSP_ALU_CK PowerOn */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_DSP_CTL, 0x00);
if (error)
return error;
/* Disable watchdog */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_TMR0_EN, 0x00);
if (error)
return error;
/* Clear cache enable */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_CACHE_EN, 0x00);
if (error)
return error;
/* Set boot from SRAM */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x02);
if (error)
return error;
/* Software reboot */
error = goodix_i2c_write_u8(client,
GOODIX_REG_MISCTL_CPU_SWRST_PULSE, 0x01);
if (error)
return error;
/* Clear control flag */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x00);
if (error)
return error;
/* Set scramble */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOT_OPT, 0x00);
if (error)
return error;
/* Enable accessing code */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_MEM_CD_EN, 0x01);
if (error)
return error;
return 0;
}
static int goodix_start_firmware(struct i2c_client *client)
{
int error;
u8 val;
/* Init software watchdog */
error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa);
if (error)
return error;
/* Release SS51 & DSP */
error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_SWRST, 0x00);
if (error)
return error;
error = goodix_i2c_read(client, GOODIX_REG_SW_WDT, &val, 1);
if (error)
return error;
/* The value we've written to SW_WDT should have been cleared now */
if (val == 0xaa) {
dev_err(&client->dev, "Error SW_WDT reg not cleared on fw startup\n");
return -EIO;
}
/* Re-init software watchdog */
error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa);
if (error)
return error;
return 0;
}
static int goodix_firmware_upload(struct goodix_ts_data *ts)
{
const struct firmware *fw;
char fw_name[64];
const u8 *data;
int error;
snprintf(fw_name, sizeof(fw_name), "goodix/%s", ts->firmware_name);
error = request_firmware(&fw, fw_name, &ts->client->dev);
if (error) {
dev_err(&ts->client->dev, "Firmware request error %d\n", error);
return error;
}
error = goodix_firmware_verify(&ts->client->dev, fw);
if (error)
goto release;
error = goodix_reset_no_int_sync(ts);
if (error)
return error;
error = goodix_enter_upload_mode(ts->client);
if (error)
goto release;
/* Select SRAM bank 0 and upload section 1 & 2 */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x00);
if (error)
goto release;
data = fw->data + GOODIX_FW_HEADER_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, 2 * GOODIX_FW_SECTION_LENGTH);
if (error)
goto release;
/* Select SRAM bank 1 and upload section 3 & 4 */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x01);
if (error)
goto release;
data += 2 * GOODIX_FW_SECTION_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, 2 * GOODIX_FW_SECTION_LENGTH);
if (error)
goto release;
/* Select SRAM bank 2 and upload the DSP firmware */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x02);
if (error)
goto release;
data += 2 * GOODIX_FW_SECTION_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, GOODIX_FW_DSP_LENGTH);
if (error)
goto release;
error = goodix_start_firmware(ts->client);
if (error)
goto release;
error = goodix_int_sync(ts);
release:
release_firmware(fw);
return error;
}
static int goodix_prepare_bak_ref(struct goodix_ts_data *ts)
{
u8 have_key, driver_num, sensor_num;
if (ts->bak_ref)
return 0; /* Already done */
have_key = (ts->config[GOODIX_CFG_LOC_HAVE_KEY] & 0x01);
driver_num = (ts->config[GOODIX_CFG_LOC_DRVA_NUM] & 0x1f) +
(ts->config[GOODIX_CFG_LOC_DRVB_NUM] & 0x1f);
if (have_key)
driver_num--;
sensor_num = (ts->config[GOODIX_CFG_LOC_SENS_NUM] & 0x0f) +
((ts->config[GOODIX_CFG_LOC_SENS_NUM] >> 4) & 0x0f);
dev_dbg(&ts->client->dev, "Drv %d Sen %d Key %d\n",
driver_num, sensor_num, have_key);
ts->bak_ref_len = (driver_num * (sensor_num - 2) + 2) * 2;
ts->bak_ref = devm_kzalloc(&ts->client->dev,
ts->bak_ref_len, GFP_KERNEL);
if (!ts->bak_ref)
return -ENOMEM;
/*
* The bak_ref array contains the backup of an array of (self/auto)
* calibration related values which the Android version of the driver
* stores on the filesystem so that it can be restored after reboot.
* The mainline kernel never writes directly to the filesystem like
* this, we always start will all the values which give a correction
* factor in approx. the -20 - +20 range (in 2s complement) set to 0.
*
* Note the touchscreen works fine without restoring the reference
* values after a reboot / power-cycle.
*
* The last 2 bytes are a 16 bits unsigned checksum which is expected
* to make the addition al all 16 bit unsigned values in the array add
* up to 1 (rather then the usual 0), so we must set the last byte to 1.
*/
ts->bak_ref[ts->bak_ref_len - 1] = 1;
return 0;
}
static int goodix_send_main_clock(struct goodix_ts_data *ts)
{
u32 main_clk = 54; /* Default main clock */
u8 checksum = 0;
int i;
device_property_read_u32(&ts->client->dev,
"goodix,main-clk", &main_clk);
for (i = 0; i < (GOODIX_MAIN_CLK_LEN - 1); i++) {
ts->main_clk[i] = main_clk;
checksum += main_clk;
}
/* The value of all bytes combines must be 0 */
ts->main_clk[GOODIX_MAIN_CLK_LEN - 1] = 256 - checksum;
return goodix_i2c_write(ts->client, GOODIX_REG_MAIN_CLK,
ts->main_clk, GOODIX_MAIN_CLK_LEN);
}
int goodix_firmware_check(struct goodix_ts_data *ts)
{
device_property_read_string(&ts->client->dev,
"firmware-name", &ts->firmware_name);
if (!ts->firmware_name)
return 0;
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
dev_err(&ts->client->dev, "Error no IRQ-pin access method, cannot upload fw.\n");
return -EINVAL;
}
dev_info(&ts->client->dev, "Touchscreen controller needs fw-upload\n");
ts->load_cfg_from_disk = true;
return goodix_firmware_upload(ts);
}
bool goodix_handle_fw_request(struct goodix_ts_data *ts)
{
int error;
u8 val;
error = goodix_i2c_read(ts->client, GOODIX_REG_REQUEST, &val, 1);
if (error)
return false;
switch (val) {
case GOODIX_RQST_RESPONDED:
/*
* If we read back our own last ack the IRQ was not for
* a request.
*/
return false;
case GOODIX_RQST_CONFIG:
error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
if (error)
return false;
break;
case GOODIX_RQST_BAK_REF:
error = goodix_prepare_bak_ref(ts);
if (error)
return false;
error = goodix_i2c_write(ts->client, GOODIX_REG_BAK_REF,
ts->bak_ref, ts->bak_ref_len);
if (error)
return false;
break;
case GOODIX_RQST_RESET:
error = goodix_firmware_upload(ts);
if (error)
return false;
break;
case GOODIX_RQST_MAIN_CLOCK:
error = goodix_send_main_clock(ts);
if (error)
return false;
break;
case GOODIX_RQST_UNKNOWN:
case GOODIX_RQST_IDLE:
break;
default:
dev_err_ratelimited(&ts->client->dev, "Unknown Request: 0x%02x\n", val);
}
/* Ack the request */
goodix_i2c_write_u8(ts->client,
GOODIX_REG_REQUEST, GOODIX_RQST_RESPONDED);
return true;
}
void goodix_save_bak_ref(struct goodix_ts_data *ts)
{
int error;
u8 val;
if (!ts->firmware_name)
return;
error = goodix_i2c_read(ts->client, GOODIX_REG_STATUS, &val, 1);
if (error)
return;
if (!(val & 0x80))
return;
error = goodix_i2c_read(ts->client, GOODIX_REG_BAK_REF,
ts->bak_ref, ts->bak_ref_len);
if (error) {
memset(ts->bak_ref, 0, ts->bak_ref_len);
ts->bak_ref[ts->bak_ref_len - 1] = 1;
}
}

View File

@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/ihex.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
@ -12,7 +14,7 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#define ILI2XXX_POLL_PERIOD 20
#define ILI2XXX_POLL_PERIOD 15
#define ILI210X_DATA_SIZE 64
#define ILI211X_DATA_SIZE 43
@ -22,8 +24,23 @@
/* Touchscreen commands */
#define REG_TOUCHDATA 0x10
#define REG_PANEL_INFO 0x20
#define REG_FIRMWARE_VERSION 0x40
#define REG_PROTOCOL_VERSION 0x42
#define REG_KERNEL_VERSION 0x61
#define REG_IC_BUSY 0x80
#define REG_IC_BUSY_NOT_BUSY 0x50
#define REG_GET_MODE 0xc0
#define REG_GET_MODE_AP 0x5a
#define REG_GET_MODE_BL 0x55
#define REG_SET_MODE_AP 0xc1
#define REG_SET_MODE_BL 0xc2
#define REG_WRITE_DATA 0xc3
#define REG_WRITE_ENABLE 0xc4
#define REG_READ_DATA_CRC 0xc7
#define REG_CALIBRATE 0xcc
#define ILI251X_FW_FILENAME "ilitek/ili251x.bin"
struct ili2xxx_chip {
int (*read_reg)(struct i2c_client *client, u8 reg,
void *buf, size_t len);
@ -35,6 +52,7 @@ struct ili2xxx_chip {
unsigned int max_touches;
unsigned int resolution;
bool has_calibrate_reg;
bool has_firmware_proto;
bool has_pressure_reg;
};
@ -44,6 +62,10 @@ struct ili210x {
struct gpio_desc *reset_gpio;
struct touchscreen_properties prop;
const struct ili2xxx_chip *chip;
u8 version_firmware[8];
u8 version_kernel[5];
u8 version_proto[2];
u8 ic_mode[2];
bool stop;
};
@ -202,15 +224,17 @@ static const struct ili2xxx_chip ili212x_chip = {
.has_calibrate_reg = true,
};
static int ili251x_read_reg(struct i2c_client *client,
u8 reg, void *buf, size_t len)
static int ili251x_read_reg_common(struct i2c_client *client,
u8 reg, void *buf, size_t len,
unsigned int delay)
{
int error;
int ret;
ret = i2c_master_send(client, &reg, 1);
if (ret == 1) {
usleep_range(5000, 5500);
if (delay)
usleep_range(delay, delay + 500);
ret = i2c_master_recv(client, buf, len);
if (ret == len)
@ -222,12 +246,18 @@ static int ili251x_read_reg(struct i2c_client *client,
return ret;
}
static int ili251x_read_reg(struct i2c_client *client,
u8 reg, void *buf, size_t len)
{
return ili251x_read_reg_common(client, reg, buf, len, 5000);
}
static int ili251x_read_touch_data(struct i2c_client *client, u8 *data)
{
int error;
error = ili251x_read_reg(client, REG_TOUCHDATA,
data, ILI251X_DATA_SIZE1);
error = ili251x_read_reg_common(client, REG_TOUCHDATA,
data, ILI251X_DATA_SIZE1, 0);
if (!error && data[0] == 2) {
error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1,
ILI251X_DATA_SIZE2);
@ -268,6 +298,7 @@ static const struct ili2xxx_chip ili251x_chip = {
.continue_polling = ili251x_check_continue_polling,
.max_touches = 10,
.has_calibrate_reg = true,
.has_firmware_proto = true,
.has_pressure_reg = true,
};
@ -303,10 +334,13 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
const struct ili2xxx_chip *chip = priv->chip;
u8 touchdata[ILI210X_DATA_SIZE] = { 0 };
bool keep_polling;
ktime_t time_next;
s64 time_delta;
bool touch;
int error;
do {
time_next = ktime_add_ms(ktime_get(), ILI2XXX_POLL_PERIOD);
error = chip->get_touch_data(client, touchdata);
if (error) {
dev_err(&client->dev,
@ -316,13 +350,201 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
touch = ili210x_report_events(priv, touchdata);
keep_polling = chip->continue_polling(touchdata, touch);
if (keep_polling)
msleep(ILI2XXX_POLL_PERIOD);
if (keep_polling) {
time_delta = ktime_us_delta(time_next, ktime_get());
if (time_delta > 0)
usleep_range(time_delta, time_delta + 1000);
}
} while (!priv->stop && keep_polling);
return IRQ_HANDLED;
}
static int ili251x_firmware_update_resolution(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u16 resx, resy;
u8 rs[10];
int error;
/* The firmware update blob might have changed the resolution. */
error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs));
if (error)
return error;
resx = le16_to_cpup((__le16 *)rs);
resy = le16_to_cpup((__le16 *)(rs + 2));
/* The value reported by the firmware is invalid. */
if (!resx || resx == 0xffff || !resy || resy == 0xffff)
return -EINVAL;
input_abs_set_max(priv->input, ABS_X, resx - 1);
input_abs_set_max(priv->input, ABS_Y, resy - 1);
input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1);
input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1);
return 0;
}
static ssize_t ili251x_firmware_update_firmware_version(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 fw[8];
/* Get firmware version */
error = priv->chip->read_reg(client, REG_FIRMWARE_VERSION,
&fw, sizeof(fw));
if (!error)
memcpy(priv->version_firmware, fw, sizeof(fw));
return error;
}
static ssize_t ili251x_firmware_update_kernel_version(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 kv[5];
/* Get kernel version */
error = priv->chip->read_reg(client, REG_KERNEL_VERSION,
&kv, sizeof(kv));
if (!error)
memcpy(priv->version_kernel, kv, sizeof(kv));
return error;
}
static ssize_t ili251x_firmware_update_protocol_version(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 pv[2];
/* Get protocol version */
error = priv->chip->read_reg(client, REG_PROTOCOL_VERSION,
&pv, sizeof(pv));
if (!error)
memcpy(priv->version_proto, pv, sizeof(pv));
return error;
}
static ssize_t ili251x_firmware_update_ic_mode(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
u8 md[2];
/* Get chip boot mode */
error = priv->chip->read_reg(client, REG_GET_MODE, &md, sizeof(md));
if (!error)
memcpy(priv->ic_mode, md, sizeof(md));
return error;
}
static int ili251x_firmware_update_cached_state(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
int error;
if (!priv->chip->has_firmware_proto)
return 0;
/* Wait for firmware to boot and stabilize itself. */
msleep(200);
/* Firmware does report valid information. */
error = ili251x_firmware_update_resolution(dev);
if (error)
return error;
error = ili251x_firmware_update_firmware_version(dev);
if (error)
return error;
error = ili251x_firmware_update_kernel_version(dev);
if (error)
return error;
error = ili251x_firmware_update_protocol_version(dev);
if (error)
return error;
error = ili251x_firmware_update_ic_mode(dev);
if (error)
return error;
return 0;
}
static ssize_t ili251x_firmware_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *fw = priv->version_firmware;
return sysfs_emit(buf, "%02x%02x.%02x%02x.%02x%02x.%02x%02x\n",
fw[0], fw[1], fw[2], fw[3],
fw[4], fw[5], fw[6], fw[7]);
}
static DEVICE_ATTR(firmware_version, 0444, ili251x_firmware_version_show, NULL);
static ssize_t ili251x_kernel_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *kv = priv->version_kernel;
return sysfs_emit(buf, "%02x.%02x.%02x.%02x.%02x\n",
kv[0], kv[1], kv[2], kv[3], kv[4]);
}
static DEVICE_ATTR(kernel_version, 0444, ili251x_kernel_version_show, NULL);
static ssize_t ili251x_protocol_version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *pv = priv->version_proto;
return sysfs_emit(buf, "%02x.%02x\n", pv[0], pv[1]);
}
static DEVICE_ATTR(protocol_version, 0444, ili251x_protocol_version_show, NULL);
static ssize_t ili251x_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 *md = priv->ic_mode;
char *mode = "AP";
if (md[0] == REG_GET_MODE_AP) /* Application Mode */
mode = "AP";
else if (md[0] == REG_GET_MODE_BL) /* BootLoader Mode */
mode = "BL";
else /* Unknown Mode */
mode = "??";
return sysfs_emit(buf, "%02x.%02x:%s\n", md[0], md[1], mode);
}
static DEVICE_ATTR(mode, 0444, ili251x_mode_show, NULL);
static ssize_t ili210x_calibrate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@ -349,24 +571,333 @@ static ssize_t ili210x_calibrate(struct device *dev,
}
static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
static int ili251x_firmware_to_buffer(const struct firmware *fw,
u8 **buf, u16 *ac_end, u16 *df_end)
{
const struct ihex_binrec *rec;
u32 fw_addr, fw_last_addr = 0;
u16 fw_len;
u8 *fw_buf;
int error;
/*
* The firmware ihex blob can never be bigger than 64 kiB, so make this
* simple -- allocate a 64 kiB buffer, iterate over the ihex blob records
* once, copy them all into this buffer at the right locations, and then
* do all operations on this linear buffer.
*/
fw_buf = kzalloc(SZ_64K, GFP_KERNEL);
if (!fw_buf)
return -ENOMEM;
rec = (const struct ihex_binrec *)fw->data;
while (rec) {
fw_addr = be32_to_cpu(rec->addr);
fw_len = be16_to_cpu(rec->len);
/* The last 32 Byte firmware block can be 0xffe0 */
if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32) {
error = -EFBIG;
goto err_big;
}
/* Find the last address before DF start address, that is AC end */
if (fw_addr == 0xf000)
*ac_end = fw_last_addr;
fw_last_addr = fw_addr + fw_len;
memcpy(fw_buf + fw_addr, rec->data, fw_len);
rec = ihex_next_binrec(rec);
}
/* DF end address is the last address in the firmware blob */
*df_end = fw_addr + fw_len;
*buf = fw_buf;
return 0;
err_big:
kfree(fw_buf);
return error;
}
/* Switch mode between Application and BootLoader */
static int ili251x_switch_ic_mode(struct i2c_client *client, u8 cmd_mode)
{
struct ili210x *priv = i2c_get_clientdata(client);
u8 cmd_wren[3] = { REG_WRITE_ENABLE, 0x5a, 0xa5 };
u8 md[2];
int error;
error = priv->chip->read_reg(client, REG_GET_MODE, md, sizeof(md));
if (error)
return error;
/* Mode already set */
if ((cmd_mode == REG_SET_MODE_AP && md[0] == REG_GET_MODE_AP) ||
(cmd_mode == REG_SET_MODE_BL && md[0] == REG_GET_MODE_BL))
return 0;
/* Unlock writes */
error = i2c_master_send(client, cmd_wren, sizeof(cmd_wren));
if (error != sizeof(cmd_wren))
return -EINVAL;
mdelay(20);
/* Select mode (BootLoader or Application) */
error = i2c_master_send(client, &cmd_mode, 1);
if (error != 1)
return -EINVAL;
mdelay(200); /* Reboot into bootloader takes a lot of time ... */
/* Read back mode */
error = priv->chip->read_reg(client, REG_GET_MODE, md, sizeof(md));
if (error)
return error;
/* Check if mode is correct now. */
if ((cmd_mode == REG_SET_MODE_AP && md[0] == REG_GET_MODE_AP) ||
(cmd_mode == REG_SET_MODE_BL && md[0] == REG_GET_MODE_BL))
return 0;
return -EINVAL;
}
static int ili251x_firmware_busy(struct i2c_client *client)
{
struct ili210x *priv = i2c_get_clientdata(client);
int error, i = 0;
u8 data;
do {
/* The read_reg already contains suitable delay */
error = priv->chip->read_reg(client, REG_IC_BUSY, &data, 1);
if (error)
return error;
if (i++ == 100000)
return -ETIMEDOUT;
} while (data != REG_IC_BUSY_NOT_BUSY);
return 0;
}
static int ili251x_firmware_write_to_ic(struct device *dev, u8 *fwbuf,
u16 start, u16 end, u8 dataflash)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
u8 cmd_crc = REG_READ_DATA_CRC;
u8 crcrb[4] = { 0 };
u8 fw_data[33];
u16 fw_addr;
int error;
/*
* The DF (dataflash) needs 2 bytes offset for unknown reasons,
* the AC (application) has 2 bytes CRC16-CCITT at the end.
*/
u16 crc = crc_ccitt(0, fwbuf + start + (dataflash ? 2 : 0),
end - start - 2);
/* Unlock write to either AC (application) or DF (dataflash) area */
u8 cmd_wr[10] = {
REG_WRITE_ENABLE, 0x5a, 0xa5, dataflash,
(end >> 16) & 0xff, (end >> 8) & 0xff, end & 0xff,
(crc >> 16) & 0xff, (crc >> 8) & 0xff, crc & 0xff
};
error = i2c_master_send(client, cmd_wr, sizeof(cmd_wr));
if (error != sizeof(cmd_wr))
return -EINVAL;
error = ili251x_firmware_busy(client);
if (error)
return error;
for (fw_addr = start; fw_addr < end; fw_addr += 32) {
fw_data[0] = REG_WRITE_DATA;
memcpy(&(fw_data[1]), fwbuf + fw_addr, 32);
error = i2c_master_send(client, fw_data, 33);
if (error != sizeof(fw_data))
return error;
error = ili251x_firmware_busy(client);
if (error)
return error;
}
error = i2c_master_send(client, &cmd_crc, 1);
if (error != 1)
return -EINVAL;
error = ili251x_firmware_busy(client);
if (error)
return error;
error = priv->chip->read_reg(client, REG_READ_DATA_CRC,
&crcrb, sizeof(crcrb));
if (error)
return error;
/* Check CRC readback */
if ((crcrb[0] != (crc & 0xff)) || crcrb[1] != ((crc >> 8) & 0xff))
return -EINVAL;
return 0;
}
static int ili251x_firmware_reset(struct i2c_client *client)
{
u8 cmd_reset[2] = { 0xf2, 0x01 };
int error;
error = i2c_master_send(client, cmd_reset, sizeof(cmd_reset));
if (error != sizeof(cmd_reset))
return -EINVAL;
return ili251x_firmware_busy(client);
}
static void ili251x_hardware_reset(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
/* Reset the controller */
gpiod_set_value_cansleep(priv->reset_gpio, 1);
usleep_range(10000, 15000);
gpiod_set_value_cansleep(priv->reset_gpio, 0);
msleep(300);
}
static ssize_t ili210x_firmware_update_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
const char *fwname = ILI251X_FW_FILENAME;
const struct firmware *fw;
u16 ac_end, df_end;
u8 *fwbuf;
int error;
int i;
error = request_ihex_firmware(&fw, fwname, dev);
if (error) {
dev_err(dev, "Failed to request firmware %s, error=%d\n",
fwname, error);
return error;
}
error = ili251x_firmware_to_buffer(fw, &fwbuf, &ac_end, &df_end);
release_firmware(fw);
if (error)
return error;
/*
* Disable touchscreen IRQ, so that we would not get spurious touch
* interrupt during firmware update, and so that the IRQ handler won't
* trigger and interfere with the firmware update. There is no bit in
* the touch controller to disable the IRQs during update, so we have
* to do it this way here.
*/
disable_irq(client->irq);
dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
ili251x_hardware_reset(dev);
error = ili251x_firmware_reset(client);
if (error)
goto exit;
/* This may not succeed on first try, so re-try a few times. */
for (i = 0; i < 5; i++) {
error = ili251x_switch_ic_mode(client, REG_SET_MODE_BL);
if (!error)
break;
}
if (error)
goto exit;
dev_dbg(dev, "IC is now in BootLoader mode\n");
msleep(200); /* The bootloader seems to need some time too. */
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0xf000, df_end, 1);
if (error) {
dev_err(dev, "DF firmware update failed, error=%d\n", error);
goto exit;
}
dev_dbg(dev, "DataFlash firmware written\n");
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0x2000, ac_end, 0);
if (error) {
dev_err(dev, "AC firmware update failed, error=%d\n", error);
goto exit;
}
dev_dbg(dev, "Application firmware written\n");
/* This may not succeed on first try, so re-try a few times. */
for (i = 0; i < 5; i++) {
error = ili251x_switch_ic_mode(client, REG_SET_MODE_AP);
if (!error)
break;
}
if (error)
goto exit;
dev_dbg(dev, "IC is now in Application mode\n");
error = ili251x_firmware_update_cached_state(dev);
if (error)
goto exit;
error = count;
exit:
ili251x_hardware_reset(dev);
dev_dbg(dev, "Firmware update ended, error=%i\n", error);
enable_irq(client->irq);
kfree(fwbuf);
return error;
}
static DEVICE_ATTR(firmware_update, 0200, NULL, ili210x_firmware_update_store);
static struct attribute *ili210x_attributes[] = {
&dev_attr_calibrate.attr,
&dev_attr_firmware_update.attr,
&dev_attr_firmware_version.attr,
&dev_attr_kernel_version.attr,
&dev_attr_protocol_version.attr,
&dev_attr_mode.attr,
NULL,
};
static umode_t ili210x_calibrate_visible(struct kobject *kobj,
static umode_t ili210x_attributes_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = kobj_to_dev(kobj);
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
return priv->chip->has_calibrate_reg ? attr->mode : 0;
/* Calibrate is present on all ILI2xxx which have calibrate register */
if (attr == &dev_attr_calibrate.attr)
return priv->chip->has_calibrate_reg ? attr->mode : 0;
/* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
if (!priv->chip->has_firmware_proto)
return 0;
return attr->mode;
}
static const struct attribute_group ili210x_attr_group = {
.attrs = ili210x_attributes,
.is_visible = ili210x_calibrate_visible,
.is_visible = ili210x_attributes_visible,
};
static void ili210x_power_down(void *data)
@ -449,6 +980,12 @@ static int ili210x_i2c_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0);
if (priv->chip->has_pressure_reg)
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0);
error = ili251x_firmware_update_cached_state(dev);
if (error) {
dev_err(dev, "Unable to cache firmware information, err: %d\n",
error);
return error;
}
touchscreen_parse_properties(input, true, &priv->prop);
error = input_mt_init_slots(input, priv->chip->max_touches,

View File

@ -37,6 +37,7 @@
#define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/
#define RM_BOOT_RDY 0xFF /* bl data ready */
#define RM_BOOT_CMD_READHWID 0x0E /* read hwid */
/* I2C main commands */
#define RM_CMD_QUERY_BANK 0x2B
@ -290,6 +291,44 @@ static int raydium_i2c_sw_reset(struct i2c_client *client)
return 0;
}
static int raydium_i2c_query_ts_bootloader_info(struct raydium_data *ts)
{
struct i2c_client *client = ts->client;
static const u8 get_hwid[] = { RM_BOOT_CMD_READHWID,
0x10, 0xc0, 0x01, 0x00, 0x04, 0x00 };
u8 rbuf[5] = { 0 };
u32 hw_ver;
int error;
error = raydium_i2c_send(client, RM_CMD_BOOT_WRT,
get_hwid, sizeof(get_hwid));
if (error) {
dev_err(&client->dev, "WRT HWID command failed: %d\n", error);
return error;
}
error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, rbuf, 1);
if (error) {
dev_err(&client->dev, "Ack HWID command failed: %d\n", error);
return error;
}
error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, rbuf, sizeof(rbuf));
if (error) {
dev_err(&client->dev, "Read HWID command failed: %d (%4ph)\n",
error, rbuf + 1);
hw_ver = 0xffffffffUL;
} else {
hw_ver = get_unaligned_be32(rbuf + 1);
}
ts->info.hw_ver = cpu_to_le32(hw_ver);
ts->info.main_ver = 0xff;
ts->info.sub_ver = 0xff;
return error;
}
static int raydium_i2c_query_ts_info(struct raydium_data *ts)
{
struct i2c_client *client = ts->client;
@ -388,13 +427,10 @@ static int raydium_i2c_initialize(struct raydium_data *ts)
if (error)
ts->boot_mode = RAYDIUM_TS_BLDR;
if (ts->boot_mode == RAYDIUM_TS_BLDR) {
ts->info.hw_ver = cpu_to_le32(0xffffffffUL);
ts->info.main_ver = 0xff;
ts->info.sub_ver = 0xff;
} else {
if (ts->boot_mode == RAYDIUM_TS_BLDR)
raydium_i2c_query_ts_bootloader_info(ts);
else
raydium_i2c_query_ts_info(ts);
}
return error;
}
@ -1082,11 +1118,11 @@ static int raydium_i2c_probe(struct i2c_client *client,
if (error)
return error;
error = devm_add_action(&client->dev, raydium_i2c_power_off, ts);
error = devm_add_action_or_reset(&client->dev,
raydium_i2c_power_off, ts);
if (error) {
dev_err(&client->dev,
"failed to install power off action: %d\n", error);
raydium_i2c_power_off(ts);
return error;
}
@ -1218,7 +1254,7 @@ static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
raydium_i2c_suspend, raydium_i2c_resume);
static const struct i2c_device_id raydium_i2c_id[] = {
{ "raydium_i2c" , 0 },
{ "raydium_i2c", 0 },
{ "rm32380", 0 },
{ /* sentinel */ }
};

View File

@ -92,7 +92,7 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
unsigned int retries;
int error;
for (retries = 10; retries; retries--) {
for (retries = 100; retries; retries--) {
error = st1232_ts_read_data(ts, REG_STATUS, 1);
if (!error) {
switch (ts->read_buf[0]) {
@ -389,6 +389,7 @@ static struct i2c_driver st1232_ts_driver = {
.driver = {
.name = ST1232_TS_NAME,
.of_match_table = st1232_ts_dt_ids,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &st1232_ts_pm_ops,
},
};

View File

@ -45,7 +45,9 @@ static int tsc2004_probe(struct i2c_client *i2c,
static int tsc2004_remove(struct i2c_client *i2c)
{
return tsc200x_remove(&i2c->dev);
tsc200x_remove(&i2c->dev);
return 0;
}
static const struct i2c_device_id tsc2004_idtable[] = {

View File

@ -66,7 +66,9 @@ static int tsc2005_probe(struct spi_device *spi)
static int tsc2005_remove(struct spi_device *spi)
{
return tsc200x_remove(&spi->dev);
tsc200x_remove(&spi->dev);
return 0;
}
#ifdef CONFIG_OF

View File

@ -577,15 +577,13 @@ disable_regulator:
}
EXPORT_SYMBOL_GPL(tsc200x_probe);
int tsc200x_remove(struct device *dev)
void tsc200x_remove(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
sysfs_remove_group(&dev->kobj, &tsc200x_attr_group);
regulator_disable(ts->vio);
return 0;
}
EXPORT_SYMBOL_GPL(tsc200x_remove);

View File

@ -74,6 +74,6 @@ extern const struct dev_pm_ops tsc200x_pm_ops;
int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
struct regmap *regmap,
int (*tsc200x_cmd)(struct device *dev, u8 cmd));
int tsc200x_remove(struct device *dev);
void tsc200x_remove(struct device *dev);
#endif

View File

@ -6,6 +6,7 @@
* <tobita.tatsunosuke@wacom.co.jp>
*/
#include <linux/bits.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/i2c.h>
@ -14,6 +15,15 @@
#include <linux/interrupt.h>
#include <asm/unaligned.h>
/* Bitmasks (for data[3]) */
#define WACOM_TIP_SWITCH BIT(0)
#define WACOM_BARREL_SWITCH BIT(1)
#define WACOM_ERASER BIT(2)
#define WACOM_INVERT BIT(3)
#define WACOM_BARREL_SWITCH_2 BIT(4)
#define WACOM_IN_PROXIMITY BIT(5)
/* Registers */
#define WACOM_CMD_QUERY0 0x04
#define WACOM_CMD_QUERY1 0x00
#define WACOM_CMD_QUERY2 0x33
@ -99,19 +109,19 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
if (error < 0)
goto out;
tsw = data[3] & 0x01;
ers = data[3] & 0x04;
f1 = data[3] & 0x02;
f2 = data[3] & 0x10;
tsw = data[3] & WACOM_TIP_SWITCH;
ers = data[3] & WACOM_ERASER;
f1 = data[3] & WACOM_BARREL_SWITCH;
f2 = data[3] & WACOM_BARREL_SWITCH_2;
x = le16_to_cpup((__le16 *)&data[4]);
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);
if (!wac_i2c->prox)
wac_i2c->tool = (data[3] & 0x0c) ?
wac_i2c->tool = (data[3] & (WACOM_ERASER | WACOM_INVERT)) ?
BTN_TOOL_RUBBER : BTN_TOOL_PEN;
wac_i2c->prox = data[3] & 0x20;
wac_i2c->prox = data[3] & WACOM_IN_PROXIMITY;
input_report_key(input, BTN_TOUCH, tsw || ers);
input_report_key(input, wac_i2c->tool, wac_i2c->prox);

View File

@ -1,10 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CY8CTMG110_PDATA_H
#define _LINUX_CY8CTMG110_PDATA_H
struct cy8ctmg110_pdata
{
int reset_pin; /* Reset pin is wired to this GPIO (optional) */
};
#endif

View File

@ -1,17 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* linux/spi/ads7846.h */
/* Touchscreen characteristics vary between boards and models. The
* platform_data for the device's "struct device" holds this information.
*
* It's OK if the min/max values are zero.
*/
enum ads7846_filter {
ADS7846_FILTER_OK,
ADS7846_FILTER_REPEAT,
ADS7846_FILTER_IGNORE,
};
struct ads7846_platform_data {
u16 model; /* 7843, 7845, 7846, 7873. */
u16 vref_delay_usecs; /* 0 for external vref; etc */
@ -51,10 +40,6 @@ struct ads7846_platform_data {
int gpio_pendown_debounce; /* platform specific debounce time for
* the gpio_pendown */
int (*get_pendown_state)(void);
int (*filter_init) (const struct ads7846_platform_data *pdata,
void **filter_data);
int (*filter) (void *filter_data, int data_idx, int *val);
void (*filter_cleanup)(void *filter_data);
void (*wait_for_sync)(void);
bool wakeup;
unsigned long irq_flags;

View File

@ -33,6 +33,7 @@ EXPORT_SYMBOL(cad_pid);
#define DEFAULT_REBOOT_MODE
#endif
enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
EXPORT_SYMBOL_GPL(reboot_mode);
enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED;
/*