Skip to content

Commit

Permalink
Merge tag 'hid-for-linus-2024031301' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

 - support for the following Bluetooth devices from Samsung: Samsung
   wireless {Keyboard, GamePad, Action Mouse, Book Cover, Universal
   Keyboard, HOGP Keyboard} (Sandeep C S)

 - second version of code for applying proper quirk depending on
   firmware version for lenovo/cptkbd (Mikhail Khvainitski)

 - lenovo/cptkbd firmware-dependent quirk (Mikhail Khvainitski)

 - assorted fixes and optimizations for amd-sfh (Basavaraj Natikar)

 - dead code and dead data structures removal (Jiri Slaby, Jiapeng
   Chong)

* tag 'hid-for-linus-2024031301' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (25 commits)
  HID: amd_sfh: Set the AMD SFH driver to depend on x86
  HID: input: avoid polling stylus battery on Chromebook Pompom
  HID: amd_sfh: Extend MP2 register access to SFH
  HID: amd_sfh: Improve boot time when SFH is available
  HID: amd_sfh: Avoid disabling the interrupt
  HID: amd_sfh: Update HPD sensor structure elements
  HID: amd_sfh: Increase sensor command timeout
  HID: intel-ish-hid: ipc: Add Arrow Lake PCI device ID
  HID: nintendo: Remove some unused functions
  HID: hid-prodikeys: remove struct pk_device
  HID: hid-prodikeys: remove unused struct pcmidi_snd members
  HID: hid-multitouch: remove unused mt_application::dev_time
  HID: hid-lg3ff: remove unused struct lg3ff_device
  HID: protect hid_device::bpf by CONFIG_HID_BPF
  HID: wacom: remove unused hid_data::pressure
  HID: apple: remove unused members from struct apple_sc_backlight
  HID: wacom: Clean up use of struct->wacom_wac
  HID: samsung: Add Samsung wireless bookcover and universal keyboard support
  HID: samsung: Add Samsung wireless action mouse support
  HID: samsung: Add Samsung wireless gamepad support
  ...
  • Loading branch information
Linus Torvalds committed Mar 14, 2024
2 parents b345ff6 + 0db18cd commit 3e78a6c
Show file tree
Hide file tree
Showing 21 changed files with 623 additions and 196 deletions.
1 change: 1 addition & 0 deletions drivers/hid/amd-sfh-hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ menu "AMD SFH HID Support"
config AMD_SFH_HID
tristate "AMD Sensor Fusion Hub"
depends on HID
depends on X86
help
If you say yes to this option, support will be included for the
AMD Sensor Fusion Hub.
Expand Down
16 changes: 16 additions & 0 deletions drivers/hid/amd-sfh-hid/amd_sfh_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4))

#define AMD_C2P_MSG_V1(regno) (0x10900 + ((regno) * 4))
#define AMD_P2C_MSG_V1(regno) (0x10500 + ((regno) * 4))

#define SENSOR_ENABLED 4
#define SENSOR_DISABLED 5

Expand Down Expand Up @@ -53,6 +56,9 @@ struct amd_mp2_dev {
/* mp2 active control status */
u32 mp2_acs;
struct sfh_dev_status dev_en;
struct work_struct work;
u8 init_done;
u8 rver;
};

struct amd_mp2_ops {
Expand All @@ -79,4 +85,14 @@ void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata);
int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata);
void amd_sfh_clear_intr(struct amd_mp2_dev *privdata);
int amd_sfh_irq_init(struct amd_mp2_dev *privdata);

static inline u64 amd_get_c2p_val(struct amd_mp2_dev *mp2, u32 idx)
{
return mp2->rver == 1 ? AMD_C2P_MSG_V1(idx) : AMD_C2P_MSG(idx);
}

static inline u64 amd_get_p2c_val(struct amd_mp2_dev *mp2, u32 idx)
{
return mp2->rver == 1 ? AMD_P2C_MSG_V1(idx) : AMD_P2C_MSG(idx);
}
#endif
118 changes: 97 additions & 21 deletions drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/devm-helpers.h>
#include <linux/dma-mapping.h>
#include <linux/dmi.h>
#include <linux/interrupt.h>
Expand All @@ -35,15 +36,17 @@ static int sensor_mask_override = -1;
module_param_named(sensor_mask, sensor_mask_override, int, 0444);
MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");

static bool intr_disable = true;

static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
{
union cmd_response cmd_resp;

/* Get response with status within a max of 1600 ms timeout */
/* Get response with status within a max of 10 seconds timeout */
if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
(cmd_resp.response_v2.response == sensor_sts &&
cmd_resp.response_v2.status == 0 && (sid == 0xff ||
cmd_resp.response_v2.sensor_id == sid)), 500, 1600000))
cmd_resp.response_v2.sensor_id == sid)), 500, 10000000))
return cmd_resp.response_v2.response;

return SENSOR_DISABLED;
Expand All @@ -55,7 +58,7 @@ static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sen

cmd_base.ul = 0;
cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
cmd_base.cmd_v2.intr_disable = 1;
cmd_base.cmd_v2.intr_disable = intr_disable;
cmd_base.cmd_v2.period = info.period;
cmd_base.cmd_v2.sensor_id = info.sensor_idx;
cmd_base.cmd_v2.length = 16;
Expand All @@ -73,7 +76,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)

cmd_base.ul = 0;
cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
cmd_base.cmd_v2.intr_disable = 1;
cmd_base.cmd_v2.intr_disable = intr_disable;
cmd_base.cmd_v2.period = 0;
cmd_base.cmd_v2.sensor_id = sensor_idx;
cmd_base.cmd_v2.length = 16;
Expand All @@ -87,7 +90,7 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
union sfh_cmd_base cmd_base;

cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
cmd_base.cmd_v2.intr_disable = 1;
cmd_base.cmd_v2.intr_disable = intr_disable;
cmd_base.cmd_v2.period = 0;
cmd_base.cmd_v2.sensor_id = 0;

Expand All @@ -96,9 +99,9 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)

void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata)
{
if (readl(privdata->mmio + AMD_P2C_MSG(4))) {
writel(0, privdata->mmio + AMD_P2C_MSG(4));
writel(0xf, privdata->mmio + AMD_P2C_MSG(5));
if (readl(privdata->mmio + amd_get_p2c_val(privdata, 4))) {
writel(0, privdata->mmio + amd_get_p2c_val(privdata, 4));
writel(0xf, privdata->mmio + amd_get_p2c_val(privdata, 5));
}
}

Expand Down Expand Up @@ -292,6 +295,26 @@ int amd_sfh_irq_init(struct amd_mp2_dev *privdata)
return 0;
}

static int mp2_disable_intr(const struct dmi_system_id *id)
{
intr_disable = false;
return 0;
}

static const struct dmi_system_id dmi_sfh_table[] = {
{
/*
* https://bugzilla.kernel.org/show_bug.cgi?id=218104
*/
.callback = mp2_disable_intr,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook x360 435 G7"),
},
},
{}
};

static const struct dmi_system_id dmi_nodevs[] = {
{
/*
Expand All @@ -307,6 +330,48 @@ static const struct dmi_system_id dmi_nodevs[] = {
{ }
};

static void sfh1_1_init_work(struct work_struct *work)
{
struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
struct pci_dev *pdev = mp2->pdev;
int rc;

rc = mp2->sfh1_1_ops->init(mp2);
if (rc) {
dev_err(&pdev->dev, "sfh1_1_init failed err %d\n", rc);
return;
}

amd_sfh_clear_intr(mp2);
mp2->init_done = 1;
}

static void sfh_init_work(struct work_struct *work)
{
struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
struct pci_dev *pdev = mp2->pdev;
int rc;

rc = amd_sfh_hid_client_init(mp2);
if (rc) {
amd_sfh_clear_intr(mp2);
dev_err(&pdev->dev, "amd_sfh_hid_client_init failed err %d\n", rc);
return;
}

amd_sfh_clear_intr(mp2);
mp2->init_done = 1;
}

static void amd_sfh_remove(struct pci_dev *pdev)
{
struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);

flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->remove(mp2);
}

static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct amd_mp2_dev *privdata;
Expand All @@ -315,6 +380,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
if (dmi_first_match(dmi_nodevs))
return -ENODEV;

dmi_check_system(dmi_sfh_table);

privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
if (!privdata)
return -ENOMEM;
Expand Down Expand Up @@ -343,10 +410,15 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i

privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data;
if (privdata->sfh1_1_ops) {
rc = privdata->sfh1_1_ops->init(privdata);
if (boot_cpu_data.x86 >= 0x1A)
privdata->rver = 1;

rc = devm_work_autocancel(&pdev->dev, &privdata->work, sfh1_1_init_work);
if (rc)
return rc;
goto init_done;

schedule_work(&privdata->work);
return 0;
}

mp2_select_ops(privdata);
Expand All @@ -357,33 +429,34 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
return rc;
}

rc = amd_sfh_hid_client_init(privdata);
rc = devm_work_autocancel(&pdev->dev, &privdata->work, sfh_init_work);
if (rc) {
amd_sfh_clear_intr(privdata);
if (rc != -EOPNOTSUPP)
dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
return rc;
}

init_done:
amd_sfh_clear_intr(privdata);

return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata);
schedule_work(&privdata->work);
return 0;
}

static void amd_sfh_shutdown(struct pci_dev *pdev)
{
struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);

if (mp2 && mp2->mp2_ops)
mp2->mp2_ops->stop_all(mp2);
if (mp2) {
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->stop_all(mp2);
}
}

static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
{
struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);

mp2->mp2_ops->resume(mp2);
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->resume(mp2);

return 0;
}
Expand All @@ -392,7 +465,9 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
{
struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);

mp2->mp2_ops->suspend(mp2);
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->suspend(mp2);

return 0;
}
Expand All @@ -414,6 +489,7 @@ static struct pci_driver amd_mp2_pci_driver = {
.probe = amd_mp2_pci_probe,
.driver.pm = &amd_mp2_pm_ops,
.shutdown = amd_sfh_shutdown,
.remove = amd_sfh_remove,
};
module_pci_driver(amd_mp2_pci_driver);

Expand Down
6 changes: 3 additions & 3 deletions drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ enum mem_use_type {
struct hpd_status {
union {
struct {
u32 human_presence_report : 4;
u32 human_presence_actual : 4;
u32 probablity : 8;
u32 object_distance : 16;
u32 probablity : 8;
u32 human_presence_actual : 4;
u32 human_presence_report : 4;
} shpd;
u32 val;
};
Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
break;
case HPD_IDX:
get_common_inputs(&hpd_input.common_property, report_id);
hpdstatus.val = readl(mp2->mmio + AMD_C2P_MSG(4));
hpdstatus.val = readl(mp2->mmio + amd_get_c2p_val(mp2, 4));
hpd_input.human_presence = hpdstatus.shpd.presence;
report_size = sizeof(hpd_input);
memcpy(input_report, &hpd_input, sizeof(hpd_input));
Expand Down
4 changes: 2 additions & 2 deletions drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
if (rc)
goto cleanup;

writel(0, privdata->mmio + AMD_P2C_MSG(0));
writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
mp2_ops->start(privdata, info);
status = amd_sfh_wait_for_response
(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);
Expand Down Expand Up @@ -298,7 +298,7 @@ static void amd_sfh_set_ops(struct amd_mp2_dev *mp2)

int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
{
u32 phy_base = readl(mp2->mmio + AMD_C2P_MSG(22));
u32 phy_base = readl(mp2->mmio + amd_get_c2p_val(mp2, 22));
struct device *dev = &mp2->pdev->dev;
struct sfh_base_info binfo;
int rc;
Expand Down
10 changes: 5 additions & 5 deletions drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
struct sfh_cmd_response cmd_resp;

/* Get response with status within a max of 10000 ms timeout */
if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
if (!readl_poll_timeout(mp2->mmio + amd_get_p2c_val(mp2, 0), cmd_resp.resp,
(cmd_resp.response.response == 0 &&
cmd_resp.response.cmd_id == cmd_id && (sid == 0xff ||
cmd_resp.response.sensor_id == sid)), 500, 10000000))
Expand All @@ -39,7 +39,7 @@ static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor
cmd_base.cmd.sub_cmd_value = 1;
cmd_base.cmd.sensor_id = info.sensor_idx;

writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0));
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
}

static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
Expand All @@ -52,8 +52,8 @@ static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
cmd_base.cmd.sub_cmd_value = 1;
cmd_base.cmd.sensor_id = sensor_idx;

writeq(0x0, privdata->mmio + AMD_C2P_MSG(1));
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0));
writeq(0x0, privdata->mmio + amd_get_c2p_val(privdata, 1));
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
}

static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
Expand All @@ -66,7 +66,7 @@ static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
/* 0xf indicates all sensors */
cmd_base.cmd.sensor_id = 0xf;

writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0));
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
}

static struct amd_mp2_ops amd_sfh_ops = {
Expand Down
1 change: 0 additions & 1 deletion drivers/hid/hid-apple.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ struct apple_non_apple_keyboard {
struct apple_sc_backlight {
struct led_classdev cdev;
struct hid_device *hdev;
unsigned short backlight_off, backlight_on_min, backlight_on_max;
};

struct apple_sc {
Expand Down
8 changes: 8 additions & 0 deletions drivers/hid/hid-ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@
#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1 0x2BED
#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2 0x2BEE
#define I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG 0x2D02
#define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM 0x2F81

#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
Expand Down Expand Up @@ -1146,8 +1147,15 @@
#define USB_DEVICE_ID_SAITEK_X65 0x0b6a

#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_VENDOR_ID_SAMSUNG_ELECTRONICS 0x04e8
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD 0x7021
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_GAMEPAD 0xa000
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_ACTIONMOUSE 0xa004
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_BOOKCOVER 0xa005
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD 0xa006
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_MULTI_HOGP_KBD 0xa064

#define USB_VENDOR_ID_SEMICO 0x1a2c
#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023
Expand Down
2 changes: 2 additions & 0 deletions drivers/hid/hid-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG),
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
HID_BATTERY_QUIRK_AVOID_QUERY },
{}
};

Expand Down
Loading

0 comments on commit 3e78a6c

Please sign in to comment.