Commit df04fbe8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull HID updates from Jiri Kosina:

 - patch series that ensures that hid-multitouch driver disables touch
   and button-press reporting on hid-mt devices during suspend when the
   device is not configured as a wakeup-source, from Hans de Goede

 - support for ISH DMA on Intel EHL platform, from Even Xu

 - support for Renoir and Cezanne SoCs, Ambient Light Sensor and Human
   Presence Detection sensor for amd-sfh driver, from Basavaraj Natikar

 - other assorted code cleanups and device-specific fixes/quirks

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (45 commits)
  HID: thrustmaster: Switch to kmemdup() when allocate change_request
  HID: multitouch: Disable event reporting on suspend when the device is not a wakeup-source
  HID: logitech-dj: Implement may_wakeup ll-driver callback
  HID: usbhid: Implement may_wakeup ll-driver callback
  HID: core: Add hid_hw_may_wakeup() function
  HID: input: Add support for Programmable Buttons
  HID: wacom: Correct base usage for capacitive ExpressKey status bits
  HID: amd_sfh: Add initial support for HPD sensor
  HID: amd_sfh: Extend ALS support for newer AMD platform
  HID: amd_sfh: Extend driver capabilities for multi-generation support
  HID: surface-hid: Fix get-report request
  HID: sony: fix freeze when inserting ghlive ps3/wii dongles
  HID: usbkbd: Avoid GFP_ATOMIC when GFP_KERNEL is possible
  HID: amd_sfh: change in maintainer
  HID: intel-ish-hid: ipc: Specify that EHL no cache snooping
  HID: intel-ish-hid: ishtp: Add dma_no_cache_snooping() callback
  HID: intel-ish-hid: Set ISH driver depends on x86
  HID: hid-input: add Surface Go battery quirk
  HID: intel-ish-hid: Fix minor typos in comments
  HID: usbmouse: Avoid GFP_ATOMIC when GFP_KERNEL is possible
  ...
parents 4b5e35ce b3e29642
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -973,7 +973,7 @@ F: drivers/net/ethernet/amd/xgbe/
AMD SENSOR FUSION HUB DRIVER
M:	Nehal Shah <nehal-bakulchandra.shah@amd.com>
M:	Sandeep Singh <sandeep.singh@amd.com>
M:	Basavaraj Natikar <basavaraj.natikar@amd.com>
L:	linux-input@vger.kernel.org
S:	Maintained
F:	Documentation/hid/amd-sfh*
+20 −23
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
static void amd_sfh_work(struct work_struct *work)
{
	struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
	struct amd_input_data *in_data = cli_data->in_data;
	struct request_list *req_node;
	u8 current_index, sensor_index;
	u8 report_id, node_type;
@@ -101,13 +102,11 @@ static void amd_sfh_work(struct work_struct *work)
			pr_err("AMDSFH: Invalid report size\n");

	} else if (node_type == HID_INPUT_REPORT) {
		report_size = get_input_report(sensor_index, report_id,
					       cli_data->input_report[current_index],
					       cli_data->sensor_virt_addr[current_index]);
		report_size = get_input_report(current_index, sensor_index, report_id, in_data);
		if (report_size)
			hid_input_report(cli_data->hid_sensor_hubs[current_index],
					 cli_data->report_type[current_index],
					 cli_data->input_report[current_index], report_size, 0);
					 in_data->input_report[current_index], report_size, 0);
		else
			pr_err("AMDSFH: Invalid report size\n");
	}
@@ -119,21 +118,22 @@ static void amd_sfh_work(struct work_struct *work)
static void amd_sfh_work_buffer(struct work_struct *work)
{
	struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
	struct amd_input_data *in_data = cli_data->in_data;
	u8 report_size;
	int i;

	for (i = 0; i < cli_data->num_hid_devices; i++) {
		report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i],
					       cli_data->input_report[i],
					       cli_data->sensor_virt_addr[i]);
		report_size = get_input_report(i, cli_data->sensor_idx[i], cli_data->report_id[i],
					       in_data);
		hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
				 cli_data->input_report[i], report_size, 0);
				 in_data->input_report[i], report_size, 0);
	}
	schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
}

int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
{
	struct amd_input_data *in_data = &privdata->in_data;
	struct amdtp_cl_data *cl_data = privdata->cl_data;
	struct amd_mp2_sensor_info info;
	struct device *dev;
@@ -143,18 +143,16 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
	int rc, i;

	dev = &privdata->pdev->dev;
	cl_data = devm_kzalloc(dev, sizeof(*cl_data), GFP_KERNEL);
	if (!cl_data)
		return -ENOMEM;

	cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);

	INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
	INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
	INIT_LIST_HEAD(&req_list.list);
	cl_data->in_data = in_data;

	for (i = 0; i < cl_data->num_hid_devices; i++) {
		cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
		in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
								  &cl_data->sensor_dma_addr[i],
								  GFP_KERNEL);
		cl_data->sensor_sts[i] = 0;
@@ -181,8 +179,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
			rc = -ENOMEM;
			goto cleanup;
		}
		cl_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
		if (!cl_data->input_report[i]) {
		in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
		if (!in_data->input_report[i]) {
			rc = -ENOMEM;
			goto cleanup;
		}
@@ -202,44 +200,43 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
		rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
		if (rc)
			return rc;
		amd_start_sensor(privdata, info);
		privdata->mp2_ops->start(privdata, info);
		cl_data->sensor_sts[i] = 1;
	}
	privdata->cl_data = cl_data;
	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
	return 0;

cleanup:
	for (i = 0; i < cl_data->num_hid_devices; i++) {
		if (cl_data->sensor_virt_addr[i]) {
		if (in_data->sensor_virt_addr[i]) {
			dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
					  cl_data->sensor_virt_addr[i],
					  in_data->sensor_virt_addr[i],
					  cl_data->sensor_dma_addr[i]);
		}
		devm_kfree(dev, cl_data->feature_report[i]);
		devm_kfree(dev, cl_data->input_report[i]);
		devm_kfree(dev, in_data->input_report[i]);
		devm_kfree(dev, cl_data->report_descr[i]);
	}
	devm_kfree(dev, cl_data);
	return rc;
}

int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
{
	struct amdtp_cl_data *cl_data = privdata->cl_data;
	struct amd_input_data *in_data = cl_data->in_data;
	int i;

	for (i = 0; i < cl_data->num_hid_devices; i++)
		amd_stop_sensor(privdata, i);
		privdata->mp2_ops->stop(privdata, i);

	cancel_delayed_work_sync(&cl_data->work);
	cancel_delayed_work_sync(&cl_data->work_buffer);
	amdtp_hid_remove(cl_data);

	for (i = 0; i < cl_data->num_hid_devices; i++) {
		if (cl_data->sensor_virt_addr[i]) {
		if (in_data->sensor_virt_addr[i]) {
			dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
					  cl_data->sensor_virt_addr[i],
					  in_data->sensor_virt_addr[i],
					  cl_data->sensor_dma_addr[i]);
		}
	}
+9 −3
Original line number Diff line number Diff line
@@ -9,11 +9,16 @@
#ifndef AMDSFH_HID_H
#define AMDSFH_HID_H

#define MAX_HID_DEVICES		4
#define MAX_HID_DEVICES		5
#define BUS_AMD_AMDTP		0x20
#define AMD_SFH_HID_VENDOR	0x1022
#define AMD_SFH_HID_PRODUCT	0x0001

struct amd_input_data {
	u32 *sensor_virt_addr[MAX_HID_DEVICES];
	u8 *input_report[MAX_HID_DEVICES];
};

struct amdtp_cl_data {
	u8 init_done;
	u32 cur_hid_dev;
@@ -26,7 +31,6 @@ struct amdtp_cl_data {
	u8 *hid_descr[MAX_HID_DEVICES];
	int hid_descr_size[MAX_HID_DEVICES];
	phys_addr_t phys_addr_base;
	u32 *sensor_virt_addr[MAX_HID_DEVICES];
	dma_addr_t sensor_dma_addr[MAX_HID_DEVICES];
	u32 sensor_sts[MAX_HID_DEVICES];
	u32 sensor_requested_cnt[MAX_HID_DEVICES];
@@ -34,8 +38,8 @@ struct amdtp_cl_data {
	u8 report_id[MAX_HID_DEVICES];
	u8 sensor_idx[MAX_HID_DEVICES];
	u8 *feature_report[MAX_HID_DEVICES];
	u8 *input_report[MAX_HID_DEVICES];
	u8 request_done[MAX_HID_DEVICES];
	struct amd_input_data *in_data;
	struct delayed_work work;
	struct delayed_work work_buffer;
};
@@ -64,4 +68,6 @@ void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
void amdtp_hid_wakeup(struct hid_device *hid);
u8 get_input_report(u8 current_index, int sensor_idx, int report_id,
		    struct amd_input_data *in_data);
#endif
+85 −4
Original line number Diff line number Diff line
@@ -24,12 +24,55 @@
#define ACEL_EN		BIT(0)
#define GYRO_EN		BIT(1)
#define MAGNO_EN	BIT(2)
#define HPD_EN		BIT(16)
#define ALS_EN		BIT(19)

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 void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
{
	union sfh_cmd_base cmd_base;

	cmd_base.ul = 0;
	cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
	cmd_base.cmd_v2.period = info.period;
	cmd_base.cmd_v2.sensor_id = info.sensor_idx;
	cmd_base.cmd_v2.length = 16;

	if (info.sensor_idx == als_idx)
		cmd_base.cmd_v2.mem_type = USE_C2P_REG;

	writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG1);
	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
}

static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
{
	union sfh_cmd_base cmd_base;

	cmd_base.ul = 0;
	cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
	cmd_base.cmd_v2.period = 0;
	cmd_base.cmd_v2.sensor_id = sensor_idx;
	cmd_base.cmd_v2.length  = 16;

	writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
}

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.period = 0;
	cmd_base.cmd_v2.sensor_id = 0;

	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
}

void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
{
	union sfh_cmd_param cmd_param;
@@ -98,7 +141,6 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
{
	int activestatus, num_of_sensors = 0;
	const struct dmi_system_id *dmi_id;
	u32 activecontrolstatus;

	if (sensor_mask_override == -1) {
		dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
@@ -109,8 +151,7 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
	if (sensor_mask_override >= 0) {
		activestatus = sensor_mask_override;
	} else {
		activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3);
		activestatus = activecontrolstatus >> 4;
		activestatus = privdata->mp2_acs >> 4;
	}

	if (ACEL_EN  & activestatus)
@@ -125,13 +166,46 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
	if (ALS_EN & activestatus)
		sensor_id[num_of_sensors++] = als_idx;

	if (HPD_EN & activestatus)
		sensor_id[num_of_sensors++] = HPD_IDX;

	return num_of_sensors;
}

static void amd_mp2_pci_remove(void *privdata)
{
	struct amd_mp2_dev *mp2 = privdata;
	amd_sfh_hid_client_deinit(privdata);
	amd_stop_all_sensors(privdata);
	mp2->mp2_ops->stop_all(mp2);
}

static const struct amd_mp2_ops amd_sfh_ops_v2 = {
	.start = amd_start_sensor_v2,
	.stop = amd_stop_sensor_v2,
	.stop_all = amd_stop_all_sensor_v2,
};

static const struct amd_mp2_ops amd_sfh_ops = {
	.start = amd_start_sensor,
	.stop = amd_stop_sensor,
	.stop_all = amd_stop_all_sensors,
};

static void mp2_select_ops(struct amd_mp2_dev *privdata)
{
	u8 acs;

	privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
	acs = privdata->mp2_acs & GENMASK(3, 0);

	switch (acs) {
	case V2_STATUS:
		privdata->mp2_ops = &amd_sfh_ops_v2;
		break;
	default:
		privdata->mp2_ops = &amd_sfh_ops;
		break;
	}
}

static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -160,10 +234,17 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
		return rc;
	}

	privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
	if (!privdata->cl_data)
		return -ENOMEM;

	rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
	if (rc)
		return rc;

	mp2_select_ops(privdata);

	return amd_sfh_hid_client_init(privdata);
}

+43 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#define PCIE_MP2_AMD_H

#include <linux/pci.h>
#include "amd_sfh_hid.h"

#define PCI_DEVICE_ID_AMD_MP2	0x15E4

@@ -22,9 +23,15 @@
#define AMD_C2P_MSG1	0x10504
#define AMD_C2P_MSG2	0x10508

#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))

/* MP2 P2C Message Registers */
#define AMD_P2C_MSG3	0x1068C /* Supported Sensors info */

#define V2_STATUS	0x2

#define HPD_IDX		16

/* SFH Command register */
union sfh_cmd_base {
	u32 ul;
@@ -33,6 +40,15 @@ union sfh_cmd_base {
		u32 sensor_id : 8;
		u32 period : 16;
	} s;
	struct {
		u32 cmd_id : 4;
		u32 intr_enable : 1;
		u32 rsvd1 : 3;
		u32 length : 7;
		u32 mem_type : 1;
		u32 sensor_id : 8;
		u32 period : 8;
	} cmd_v2;
};

union sfh_cmd_param {
@@ -61,6 +77,10 @@ struct amd_mp2_dev {
	struct pci_dev *pdev;
	struct amdtp_cl_data *cl_data;
	void __iomem *mmio;
	const struct amd_mp2_ops *mp2_ops;
	struct amd_input_data in_data;
	/* mp2 active control status */
	u32 mp2_acs;
};

struct amd_mp2_sensor_info {
@@ -69,10 +89,33 @@ struct amd_mp2_sensor_info {
	dma_addr_t dma_address;
};

enum mem_use_type {
	USE_DRAM,
	USE_C2P_REG,
};

struct hpd_status {
	union {
		struct {
			u32 human_presence_report : 4;
			u32 human_presence_actual : 4;
			u32 probablity		  : 8;
			u32 object_distance       : 16;
		} shpd;
		u32 val;
	};
};

void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);

struct amd_mp2_ops {
	 void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
	 void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx);
	 void (*stop_all)(struct amd_mp2_dev *privdata);
};
#endif
Loading