brintos

brintos / linux-shallow public Read only

0
0
Text · 31.0 KiB · ff9078a Raw
1135 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.  All rights reserved.4 *5 *  HID driver for NVIDIA SHIELD peripherals.6 */7 8#include <linux/hid.h>9#include <linux/idr.h>10#include <linux/input-event-codes.h>11#include <linux/input.h>12#include <linux/jiffies.h>13#include <linux/leds.h>14#include <linux/module.h>15#include <linux/power_supply.h>16#include <linux/spinlock.h>17#include <linux/timer.h>18#include <linux/workqueue.h>19 20#include "hid-ids.h"21 22#define NOT_INIT_STR "NOT INITIALIZED"23#define android_map_key(c) hid_map_usage(hi, usage, bit, max, EV_KEY, (c))24 25enum {26	HID_USAGE_ANDROID_PLAYPAUSE_BTN = 0xcd, /* Double-tap volume slider */27	HID_USAGE_ANDROID_VOLUMEUP_BTN = 0xe9,28	HID_USAGE_ANDROID_VOLUMEDOWN_BTN = 0xea,29	HID_USAGE_ANDROID_SEARCH_BTN = 0x221, /* NVIDIA btn on Thunderstrike */30	HID_USAGE_ANDROID_HOME_BTN = 0x223,31	HID_USAGE_ANDROID_BACK_BTN = 0x224,32};33 34enum {35	SHIELD_FW_VERSION_INITIALIZED = 0,36	SHIELD_BOARD_INFO_INITIALIZED,37	SHIELD_BATTERY_STATS_INITIALIZED,38	SHIELD_CHARGER_STATE_INITIALIZED,39};40 41enum {42	THUNDERSTRIKE_FW_VERSION_UPDATE = 0,43	THUNDERSTRIKE_BOARD_INFO_UPDATE,44	THUNDERSTRIKE_HAPTICS_UPDATE,45	THUNDERSTRIKE_LED_UPDATE,46	THUNDERSTRIKE_POWER_SUPPLY_STATS_UPDATE,47};48 49enum {50	THUNDERSTRIKE_HOSTCMD_REPORT_SIZE = 33,51	THUNDERSTRIKE_HOSTCMD_REQ_REPORT_ID = 0x4,52	THUNDERSTRIKE_HOSTCMD_RESP_REPORT_ID = 0x3,53};54 55enum {56	THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION = 1,57	THUNDERSTRIKE_HOSTCMD_ID_LED = 6,58	THUNDERSTRIKE_HOSTCMD_ID_BATTERY,59	THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO = 16,60	THUNDERSTRIKE_HOSTCMD_ID_USB_INIT = 53,61	THUNDERSTRIKE_HOSTCMD_ID_HAPTICS = 57,62	THUNDERSTRIKE_HOSTCMD_ID_CHARGER,63};64 65struct power_supply_dev {66	struct power_supply *psy;67	struct power_supply_desc desc;68};69 70struct thunderstrike_psy_prop_values {71	int voltage_min;72	int voltage_now;73	int voltage_avg;74	int voltage_boot;75	int capacity;76	int status;77	int charge_type;78	int temp;79};80 81static const enum power_supply_property thunderstrike_battery_props[] = {82	POWER_SUPPLY_PROP_STATUS,83	POWER_SUPPLY_PROP_CHARGE_TYPE,84	POWER_SUPPLY_PROP_PRESENT,85	POWER_SUPPLY_PROP_VOLTAGE_MIN,86	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,87	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,88	POWER_SUPPLY_PROP_VOLTAGE_NOW,89	POWER_SUPPLY_PROP_VOLTAGE_AVG,90	POWER_SUPPLY_PROP_VOLTAGE_BOOT,91	POWER_SUPPLY_PROP_CAPACITY,92	POWER_SUPPLY_PROP_SCOPE,93	POWER_SUPPLY_PROP_TEMP,94	POWER_SUPPLY_PROP_TEMP_MIN,95	POWER_SUPPLY_PROP_TEMP_MAX,96	POWER_SUPPLY_PROP_TEMP_ALERT_MIN,97	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,98};99 100enum thunderstrike_led_state {101	THUNDERSTRIKE_LED_OFF = 1,102	THUNDERSTRIKE_LED_ON = 8,103} __packed;104static_assert(sizeof(enum thunderstrike_led_state) == 1);105 106struct thunderstrike_hostcmd_battery {107	__le16 voltage_avg;108	u8 reserved_at_10;109	__le16 thermistor;110	__le16 voltage_min;111	__le16 voltage_boot;112	__le16 voltage_now;113	u8 capacity;114} __packed;115 116enum thunderstrike_charger_type {117	THUNDERSTRIKE_CHARGER_TYPE_NONE = 0,118	THUNDERSTRIKE_CHARGER_TYPE_TRICKLE,119	THUNDERSTRIKE_CHARGER_TYPE_NORMAL,120} __packed;121static_assert(sizeof(enum thunderstrike_charger_type) == 1);122 123enum thunderstrike_charger_state {124	THUNDERSTRIKE_CHARGER_STATE_UNKNOWN = 0,125	THUNDERSTRIKE_CHARGER_STATE_DISABLED,126	THUNDERSTRIKE_CHARGER_STATE_CHARGING,127	THUNDERSTRIKE_CHARGER_STATE_FULL,128	THUNDERSTRIKE_CHARGER_STATE_FAILED = 8,129} __packed;130static_assert(sizeof(enum thunderstrike_charger_state) == 1);131 132struct thunderstrike_hostcmd_charger {133	u8 connected;134	enum thunderstrike_charger_type type;135	enum thunderstrike_charger_state state;136} __packed;137 138struct thunderstrike_hostcmd_board_info {139	__le16 revision;140	__le16 serial[7];141} __packed;142 143struct thunderstrike_hostcmd_haptics {144	u8 motor_left;145	u8 motor_right;146} __packed;147 148struct thunderstrike_hostcmd_resp_report {149	u8 report_id; /* THUNDERSTRIKE_HOSTCMD_RESP_REPORT_ID */150	u8 cmd_id;151	u8 reserved_at_10;152 153	union {154		struct thunderstrike_hostcmd_board_info board_info;155		struct thunderstrike_hostcmd_haptics motors;156		__le16 fw_version;157		enum thunderstrike_led_state led_state;158		struct thunderstrike_hostcmd_battery battery;159		struct thunderstrike_hostcmd_charger charger;160		u8 payload[30];161	} __packed;162} __packed;163static_assert(sizeof(struct thunderstrike_hostcmd_resp_report) ==164	      THUNDERSTRIKE_HOSTCMD_REPORT_SIZE);165 166struct thunderstrike_hostcmd_req_report {167	u8 report_id; /* THUNDERSTRIKE_HOSTCMD_REQ_REPORT_ID */168	u8 cmd_id;169	u8 reserved_at_10;170 171	union {172		struct __packed {173			u8 update;174			enum thunderstrike_led_state state;175		} led;176		struct __packed {177			u8 update;178			struct thunderstrike_hostcmd_haptics motors;179		} haptics;180	} __packed;181	u8 reserved_at_30[27];182} __packed;183static_assert(sizeof(struct thunderstrike_hostcmd_req_report) ==184	      THUNDERSTRIKE_HOSTCMD_REPORT_SIZE);185 186/* Common struct for shield accessories. */187struct shield_device {188	struct hid_device *hdev;189	struct power_supply_dev battery_dev;190 191	unsigned long initialized_flags;192	const char *codename;193	u16 fw_version;194	struct {195		u16 revision;196		char serial_number[15];197	} board_info;198};199 200/*201 * Non-trivial to uniquely identify Thunderstrike controllers at initialization202 * time. Use an ID allocator to help with this.203 */204static DEFINE_IDA(thunderstrike_ida);205 206struct thunderstrike {207	struct shield_device base;208 209	int id;210 211	/* Sub-devices */212	struct input_dev *haptics_dev;213	struct led_classdev led_dev;214 215	/* Resources */216	void *req_report_dmabuf;217	unsigned long update_flags;218	struct thunderstrike_hostcmd_haptics haptics_val;219	spinlock_t haptics_update_lock;220	u8 led_state : 1;221	enum thunderstrike_led_state led_value;222	struct thunderstrike_psy_prop_values psy_stats;223	spinlock_t psy_stats_lock;224	struct timer_list psy_stats_timer;225	struct work_struct hostcmd_req_work;226};227 228static inline void thunderstrike_hostcmd_req_report_init(229	struct thunderstrike_hostcmd_req_report *report, u8 cmd_id)230{231	memset(report, 0, sizeof(*report));232	report->report_id = THUNDERSTRIKE_HOSTCMD_REQ_REPORT_ID;233	report->cmd_id = cmd_id;234}235 236static inline void shield_strrev(char *dest, size_t len, u16 rev)237{238	dest[0] = ('A' - 1) + (rev >> 8);239	snprintf(&dest[1], len - 1, "%02X", 0xff & rev);240}241 242static struct input_dev *shield_allocate_input_dev(struct hid_device *hdev,243						   const char *name_suffix)244{245	struct input_dev *idev;246 247	idev = input_allocate_device();248	if (!idev)249		goto err_device;250 251	idev->id.bustype = hdev->bus;252	idev->id.vendor = hdev->vendor;253	idev->id.product = hdev->product;254	idev->id.version = hdev->version;255	idev->uniq = hdev->uniq;256	idev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name,257				    name_suffix);258	if (!idev->name)259		goto err_name;260 261	input_set_drvdata(idev, hdev);262 263	return idev;264 265err_name:266	input_free_device(idev);267err_device:268	return ERR_PTR(-ENOMEM);269}270 271static struct input_dev *shield_haptics_create(272	struct shield_device *dev,273	int (*play_effect)(struct input_dev *, void *, struct ff_effect *))274{275	struct input_dev *haptics;276	int ret;277 278	if (!IS_ENABLED(CONFIG_NVIDIA_SHIELD_FF))279		return NULL;280 281	haptics = shield_allocate_input_dev(dev->hdev, "Haptics");282	if (IS_ERR(haptics))283		return haptics;284 285	input_set_capability(haptics, EV_FF, FF_RUMBLE);286	ret = input_ff_create_memless(haptics, NULL, play_effect);287	if (ret)288		goto err;289 290	ret = input_register_device(haptics);291	if (ret)292		goto err;293 294	return haptics;295 296err:297	input_free_device(haptics);298	return ERR_PTR(ret);299}300 301static inline void thunderstrike_send_hostcmd_request(struct thunderstrike *ts)302{303	struct thunderstrike_hostcmd_req_report *report = ts->req_report_dmabuf;304	struct shield_device *shield_dev = &ts->base;305	int ret;306 307	ret = hid_hw_raw_request(shield_dev->hdev, report->report_id,308				 ts->req_report_dmabuf,309				 THUNDERSTRIKE_HOSTCMD_REPORT_SIZE,310				 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);311 312	if (ret < 0) {313		hid_err(shield_dev->hdev,314			"Failed to output Thunderstrike HOSTCMD request HID report due to %pe\n",315			ERR_PTR(ret));316	}317}318 319static void thunderstrike_hostcmd_req_work_handler(struct work_struct *work)320{321	struct thunderstrike *ts =322		container_of(work, struct thunderstrike, hostcmd_req_work);323	struct thunderstrike_hostcmd_req_report *report;324	unsigned long flags;325 326	report = ts->req_report_dmabuf;327 328	if (test_and_clear_bit(THUNDERSTRIKE_FW_VERSION_UPDATE, &ts->update_flags)) {329		thunderstrike_hostcmd_req_report_init(330			report, THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION);331		thunderstrike_send_hostcmd_request(ts);332	}333 334	if (test_and_clear_bit(THUNDERSTRIKE_LED_UPDATE, &ts->update_flags)) {335		thunderstrike_hostcmd_req_report_init(report, THUNDERSTRIKE_HOSTCMD_ID_LED);336		report->led.update = 1;337		report->led.state = ts->led_value;338		thunderstrike_send_hostcmd_request(ts);339	}340 341	if (test_and_clear_bit(THUNDERSTRIKE_POWER_SUPPLY_STATS_UPDATE, &ts->update_flags)) {342		thunderstrike_hostcmd_req_report_init(343			report, THUNDERSTRIKE_HOSTCMD_ID_BATTERY);344		thunderstrike_send_hostcmd_request(ts);345 346		thunderstrike_hostcmd_req_report_init(347			report, THUNDERSTRIKE_HOSTCMD_ID_CHARGER);348		thunderstrike_send_hostcmd_request(ts);349	}350 351	if (test_and_clear_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags)) {352		thunderstrike_hostcmd_req_report_init(353			report, THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO);354		thunderstrike_send_hostcmd_request(ts);355	}356 357	if (test_and_clear_bit(THUNDERSTRIKE_HAPTICS_UPDATE, &ts->update_flags)) {358		thunderstrike_hostcmd_req_report_init(359			report, THUNDERSTRIKE_HOSTCMD_ID_HAPTICS);360 361		report->haptics.update = 1;362		spin_lock_irqsave(&ts->haptics_update_lock, flags);363		report->haptics.motors = ts->haptics_val;364		spin_unlock_irqrestore(&ts->haptics_update_lock, flags);365 366		thunderstrike_send_hostcmd_request(ts);367	}368}369 370static inline void thunderstrike_request_firmware_version(struct thunderstrike *ts)371{372	set_bit(THUNDERSTRIKE_FW_VERSION_UPDATE, &ts->update_flags);373	schedule_work(&ts->hostcmd_req_work);374}375 376static inline void thunderstrike_request_board_info(struct thunderstrike *ts)377{378	set_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags);379	schedule_work(&ts->hostcmd_req_work);380}381 382static inline int383thunderstrike_update_haptics(struct thunderstrike *ts,384			     struct thunderstrike_hostcmd_haptics *motors)385{386	unsigned long flags;387 388	spin_lock_irqsave(&ts->haptics_update_lock, flags);389	ts->haptics_val = *motors;390	spin_unlock_irqrestore(&ts->haptics_update_lock, flags);391 392	set_bit(THUNDERSTRIKE_HAPTICS_UPDATE, &ts->update_flags);393	schedule_work(&ts->hostcmd_req_work);394 395	return 0;396}397 398static int thunderstrike_play_effect(struct input_dev *idev, void *data,399				     struct ff_effect *effect)400{401	struct hid_device *hdev = input_get_drvdata(idev);402	struct thunderstrike_hostcmd_haptics motors;403	struct shield_device *shield_dev;404	struct thunderstrike *ts;405 406	if (effect->type != FF_RUMBLE)407		return 0;408 409	shield_dev = hid_get_drvdata(hdev);410	ts = container_of(shield_dev, struct thunderstrike, base);411 412	/* Thunderstrike motor values range from 0 to 32 inclusively */413	motors.motor_left = effect->u.rumble.strong_magnitude / 2047;414	motors.motor_right = effect->u.rumble.weak_magnitude / 2047;415 416	hid_dbg(hdev, "Thunderstrike FF_RUMBLE request, left: %u right: %u\n",417		motors.motor_left, motors.motor_right);418 419	return thunderstrike_update_haptics(ts, &motors);420}421 422static enum led_brightness423thunderstrike_led_get_brightness(struct led_classdev *led)424{425	struct hid_device *hdev = to_hid_device(led->dev->parent);426	struct shield_device *shield_dev = hid_get_drvdata(hdev);427	struct thunderstrike *ts;428 429	ts = container_of(shield_dev, struct thunderstrike, base);430 431	return ts->led_state;432}433 434static void thunderstrike_led_set_brightness(struct led_classdev *led,435					    enum led_brightness value)436{437	struct hid_device *hdev = to_hid_device(led->dev->parent);438	struct shield_device *shield_dev = hid_get_drvdata(hdev);439	struct thunderstrike *ts;440 441	ts = container_of(shield_dev, struct thunderstrike, base);442 443	switch (value) {444	case LED_OFF:445		ts->led_value = THUNDERSTRIKE_LED_OFF;446		break;447	default:448		ts->led_value = THUNDERSTRIKE_LED_ON;449		break;450	}451 452	set_bit(THUNDERSTRIKE_LED_UPDATE, &ts->update_flags);453	schedule_work(&ts->hostcmd_req_work);454}455 456static int thunderstrike_battery_get_property(struct power_supply *psy,457					      enum power_supply_property psp,458					      union power_supply_propval *val)459{460	struct shield_device *shield_dev = power_supply_get_drvdata(psy);461	struct thunderstrike_psy_prop_values prop_values;462	struct thunderstrike *ts;463	int ret = 0;464 465	ts = container_of(shield_dev, struct thunderstrike, base);466	spin_lock(&ts->psy_stats_lock);467	prop_values = ts->psy_stats;468	spin_unlock(&ts->psy_stats_lock);469 470	switch (psp) {471	case POWER_SUPPLY_PROP_STATUS:472		val->intval = prop_values.status;473		break;474	case POWER_SUPPLY_PROP_CHARGE_TYPE:475		val->intval = prop_values.charge_type;476		break;477	case POWER_SUPPLY_PROP_PRESENT:478		val->intval = 1;479		break;480	case POWER_SUPPLY_PROP_VOLTAGE_MIN:481		val->intval = prop_values.voltage_min;482		break;483	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:484		val->intval = 2900000; /* 2.9 V */485		break;486	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:487		val->intval = 2200000; /* 2.2 V */488		break;489	case POWER_SUPPLY_PROP_VOLTAGE_NOW:490		val->intval = prop_values.voltage_now;491		break;492	case POWER_SUPPLY_PROP_VOLTAGE_AVG:493		val->intval = prop_values.voltage_avg;494		break;495	case POWER_SUPPLY_PROP_VOLTAGE_BOOT:496		val->intval = prop_values.voltage_boot;497		break;498	case POWER_SUPPLY_PROP_CAPACITY:499		val->intval = prop_values.capacity;500		break;501	case POWER_SUPPLY_PROP_SCOPE:502		val->intval = POWER_SUPPLY_SCOPE_DEVICE;503		break;504	case POWER_SUPPLY_PROP_TEMP:505		val->intval = prop_values.temp;506		break;507	case POWER_SUPPLY_PROP_TEMP_MIN:508		val->intval = 0; /* 0 C */509		break;510	case POWER_SUPPLY_PROP_TEMP_MAX:511		val->intval = 400; /* 40 C */512		break;513	case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:514		val->intval = 15; /* 1.5 C */515		break;516	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:517		val->intval = 380; /* 38 C */518		break;519	default:520		ret = -EINVAL;521		break;522	}523 524	return ret;525}526 527static inline void thunderstrike_request_psy_stats(struct thunderstrike *ts)528{529	set_bit(THUNDERSTRIKE_POWER_SUPPLY_STATS_UPDATE, &ts->update_flags);530	schedule_work(&ts->hostcmd_req_work);531}532 533static void thunderstrike_psy_stats_timer_handler(struct timer_list *timer)534{535	struct thunderstrike *ts =536		container_of(timer, struct thunderstrike, psy_stats_timer);537 538	thunderstrike_request_psy_stats(ts);539	/* Query battery statistics from device every five minutes */540	mod_timer(timer, jiffies + 300 * HZ);541}542 543static void544thunderstrike_parse_fw_version_payload(struct shield_device *shield_dev,545				       __le16 fw_version)546{547	shield_dev->fw_version = le16_to_cpu(fw_version);548 549	set_bit(SHIELD_FW_VERSION_INITIALIZED, &shield_dev->initialized_flags);550 551	hid_dbg(shield_dev->hdev, "Thunderstrike firmware version 0x%04X\n",552		shield_dev->fw_version);553}554 555static void556thunderstrike_parse_board_info_payload(struct shield_device *shield_dev,557				       struct thunderstrike_hostcmd_board_info *board_info)558{559	char board_revision_str[4];560	int i;561 562	shield_dev->board_info.revision = le16_to_cpu(board_info->revision);563	for (i = 0; i < 7; ++i) {564		u16 val = le16_to_cpu(board_info->serial[i]);565 566		shield_dev->board_info.serial_number[2 * i] = val & 0xFF;567		shield_dev->board_info.serial_number[2 * i + 1] = val >> 8;568	}569	shield_dev->board_info.serial_number[14] = '\0';570 571	set_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags);572 573	shield_strrev(board_revision_str, 4, shield_dev->board_info.revision);574	hid_dbg(shield_dev->hdev,575		"Thunderstrike BOARD_REVISION_%s (0x%04X) S/N: %s\n",576		board_revision_str, shield_dev->board_info.revision,577		shield_dev->board_info.serial_number);578}579 580static inline void581thunderstrike_parse_haptics_payload(struct shield_device *shield_dev,582				    struct thunderstrike_hostcmd_haptics *haptics)583{584	hid_dbg(shield_dev->hdev,585		"Thunderstrike haptics HOSTCMD response, left: %u right: %u\n",586		haptics->motor_left, haptics->motor_right);587}588 589static void590thunderstrike_parse_led_payload(struct shield_device *shield_dev,591				enum thunderstrike_led_state led_state)592{593	struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base);594 595	switch (led_state) {596	case THUNDERSTRIKE_LED_OFF:597		ts->led_state = 0;598		break;599	case THUNDERSTRIKE_LED_ON:600		ts->led_state = 1;601		break;602	}603 604	hid_dbg(shield_dev->hdev, "Thunderstrike led HOSTCMD response, 0x%02X\n", led_state);605}606 607static void thunderstrike_parse_battery_payload(608	struct shield_device *shield_dev,609	struct thunderstrike_hostcmd_battery *battery)610{611	struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base);612	u16 hostcmd_voltage_boot = le16_to_cpu(battery->voltage_boot);613	u16 hostcmd_voltage_avg = le16_to_cpu(battery->voltage_avg);614	u16 hostcmd_voltage_min = le16_to_cpu(battery->voltage_min);615	u16 hostcmd_voltage_now = le16_to_cpu(battery->voltage_now);616	u16 hostcmd_thermistor = le16_to_cpu(battery->thermistor);617	int voltage_boot, voltage_avg, voltage_min, voltage_now;618	struct hid_device *hdev = shield_dev->hdev;619	u8 capacity = battery->capacity;620	int temp;621 622	/* Convert thunderstrike device values to µV and tenths of degree Celsius */623	voltage_boot = hostcmd_voltage_boot * 1000;624	voltage_avg = hostcmd_voltage_avg * 1000;625	voltage_min = hostcmd_voltage_min * 1000;626	voltage_now = hostcmd_voltage_now * 1000;627	temp = (1378 - (int)hostcmd_thermistor) * 10 / 19;628 629	/* Copy converted values */630	spin_lock(&ts->psy_stats_lock);631	ts->psy_stats.voltage_boot = voltage_boot;632	ts->psy_stats.voltage_avg = voltage_avg;633	ts->psy_stats.voltage_min = voltage_min;634	ts->psy_stats.voltage_now = voltage_now;635	ts->psy_stats.capacity = capacity;636	ts->psy_stats.temp = temp;637	spin_unlock(&ts->psy_stats_lock);638 639	set_bit(SHIELD_BATTERY_STATS_INITIALIZED, &shield_dev->initialized_flags);640 641	hid_dbg(hdev,642		"Thunderstrike battery HOSTCMD response, voltage_avg: %u voltage_now: %u\n",643		hostcmd_voltage_avg, hostcmd_voltage_now);644	hid_dbg(hdev,645		"Thunderstrike battery HOSTCMD response, voltage_boot: %u voltage_min: %u\n",646		hostcmd_voltage_boot, hostcmd_voltage_min);647	hid_dbg(hdev,648		"Thunderstrike battery HOSTCMD response, thermistor: %u\n",649		hostcmd_thermistor);650	hid_dbg(hdev,651		"Thunderstrike battery HOSTCMD response, capacity: %u%%\n",652		capacity);653}654 655static void thunderstrike_parse_charger_payload(656	struct shield_device *shield_dev,657	struct thunderstrike_hostcmd_charger *charger)658{659	struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base);660	int charge_type = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;661	struct hid_device *hdev = shield_dev->hdev;662	int status = POWER_SUPPLY_STATUS_UNKNOWN;663 664	switch (charger->type) {665	case THUNDERSTRIKE_CHARGER_TYPE_NONE:666		charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE;667		break;668	case THUNDERSTRIKE_CHARGER_TYPE_TRICKLE:669		charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;670		break;671	case THUNDERSTRIKE_CHARGER_TYPE_NORMAL:672		charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD;673		break;674	default:675		hid_warn(hdev, "Unhandled Thunderstrike charger HOSTCMD type, %u\n",676			 charger->type);677		break;678	}679 680	switch (charger->state) {681	case THUNDERSTRIKE_CHARGER_STATE_UNKNOWN:682		status = POWER_SUPPLY_STATUS_UNKNOWN;683		break;684	case THUNDERSTRIKE_CHARGER_STATE_DISABLED:685		/* Indicates charger is disconnected */686		break;687	case THUNDERSTRIKE_CHARGER_STATE_CHARGING:688		status = POWER_SUPPLY_STATUS_CHARGING;689		break;690	case THUNDERSTRIKE_CHARGER_STATE_FULL:691		status = POWER_SUPPLY_STATUS_FULL;692		break;693	case THUNDERSTRIKE_CHARGER_STATE_FAILED:694		status = POWER_SUPPLY_STATUS_NOT_CHARGING;695		hid_err(hdev, "Thunderstrike device failed to charge\n");696		break;697	default:698		hid_warn(hdev, "Unhandled Thunderstrike charger HOSTCMD state, %u\n",699			 charger->state);700		break;701	}702 703	if (!charger->connected)704		status = POWER_SUPPLY_STATUS_DISCHARGING;705 706	spin_lock(&ts->psy_stats_lock);707	ts->psy_stats.charge_type = charge_type;708	ts->psy_stats.status = status;709	spin_unlock(&ts->psy_stats_lock);710 711	set_bit(SHIELD_CHARGER_STATE_INITIALIZED, &shield_dev->initialized_flags);712 713	hid_dbg(hdev,714		"Thunderstrike charger HOSTCMD response, connected: %u, type: %u, state: %u\n",715		charger->connected, charger->type, charger->state);716}717 718static inline void thunderstrike_device_init_info(struct shield_device *shield_dev)719{720	struct thunderstrike *ts =721		container_of(shield_dev, struct thunderstrike, base);722 723	if (!test_bit(SHIELD_FW_VERSION_INITIALIZED, &shield_dev->initialized_flags))724		thunderstrike_request_firmware_version(ts);725 726	if (!test_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags))727		thunderstrike_request_board_info(ts);728 729	if (!test_bit(SHIELD_BATTERY_STATS_INITIALIZED, &shield_dev->initialized_flags) ||730	    !test_bit(SHIELD_CHARGER_STATE_INITIALIZED, &shield_dev->initialized_flags))731		thunderstrike_psy_stats_timer_handler(&ts->psy_stats_timer);732}733 734static int thunderstrike_parse_report(struct shield_device *shield_dev,735				      struct hid_report *report, u8 *data,736				      int size)737{738	struct thunderstrike_hostcmd_resp_report *hostcmd_resp_report;739	struct hid_device *hdev = shield_dev->hdev;740 741	switch (report->id) {742	case THUNDERSTRIKE_HOSTCMD_RESP_REPORT_ID:743		if (size != THUNDERSTRIKE_HOSTCMD_REPORT_SIZE) {744			hid_err(hdev,745				"Encountered Thunderstrike HOSTCMD HID report with unexpected size %d\n",746				size);747			return -EINVAL;748		}749 750		hostcmd_resp_report =751			(struct thunderstrike_hostcmd_resp_report *)data;752 753		switch (hostcmd_resp_report->cmd_id) {754		case THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION:755			thunderstrike_parse_fw_version_payload(756				shield_dev, hostcmd_resp_report->fw_version);757			break;758		case THUNDERSTRIKE_HOSTCMD_ID_LED:759			thunderstrike_parse_led_payload(shield_dev, hostcmd_resp_report->led_state);760			break;761		case THUNDERSTRIKE_HOSTCMD_ID_BATTERY:762			thunderstrike_parse_battery_payload(shield_dev,763							    &hostcmd_resp_report->battery);764			break;765		case THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO:766			thunderstrike_parse_board_info_payload(767				shield_dev, &hostcmd_resp_report->board_info);768			break;769		case THUNDERSTRIKE_HOSTCMD_ID_HAPTICS:770			thunderstrike_parse_haptics_payload(771				shield_dev, &hostcmd_resp_report->motors);772			break;773		case THUNDERSTRIKE_HOSTCMD_ID_USB_INIT:774			/* May block HOSTCMD requests till received initially */775			thunderstrike_device_init_info(shield_dev);776			break;777		case THUNDERSTRIKE_HOSTCMD_ID_CHARGER:778			/* May block HOSTCMD requests till received initially */779			thunderstrike_device_init_info(shield_dev);780 781			thunderstrike_parse_charger_payload(782				shield_dev, &hostcmd_resp_report->charger);783			break;784		default:785			hid_warn(hdev,786				 "Unhandled Thunderstrike HOSTCMD id %d\n",787				 hostcmd_resp_report->cmd_id);788			return -ENOENT;789		}790 791		break;792	default:793		return 0;794	}795 796	return 0;797}798 799static inline int thunderstrike_led_create(struct thunderstrike *ts)800{801	struct led_classdev *led = &ts->led_dev;802 803	led->name = devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,804				   "thunderstrike%d:blue:led", ts->id);805	if (!led->name)806		return -ENOMEM;807	led->max_brightness = 1;808	led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;809	led->brightness_get = &thunderstrike_led_get_brightness;810	led->brightness_set = &thunderstrike_led_set_brightness;811 812	return led_classdev_register(&ts->base.hdev->dev, led);813}814 815static inline int thunderstrike_psy_create(struct shield_device *shield_dev)816{817	struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base);818	struct power_supply_config psy_cfg = { .drv_data = shield_dev, };819	struct hid_device *hdev = shield_dev->hdev;820	int ret;821 822	/*823	 * Set an initial capacity and temperature value to avoid prematurely824	 * triggering alerts. Will be replaced by values queried from initial825	 * HOSTCMD requests.826	 */827	ts->psy_stats.capacity = 100;828	ts->psy_stats.temp = 182;829 830	shield_dev->battery_dev.desc.properties = thunderstrike_battery_props;831	shield_dev->battery_dev.desc.num_properties =832		ARRAY_SIZE(thunderstrike_battery_props);833	shield_dev->battery_dev.desc.get_property = thunderstrike_battery_get_property;834	shield_dev->battery_dev.desc.type = POWER_SUPPLY_TYPE_BATTERY;835	shield_dev->battery_dev.desc.name =836		devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,837			       "thunderstrike_%d", ts->id);838	if (!shield_dev->battery_dev.desc.name)839		return -ENOMEM;840 841	shield_dev->battery_dev.psy = power_supply_register(842		&hdev->dev, &shield_dev->battery_dev.desc, &psy_cfg);843	if (IS_ERR(shield_dev->battery_dev.psy)) {844		hid_err(hdev, "Failed to register Thunderstrike battery device\n");845		return PTR_ERR(shield_dev->battery_dev.psy);846	}847 848	ret = power_supply_powers(shield_dev->battery_dev.psy, &hdev->dev);849	if (ret) {850		hid_err(hdev, "Failed to associate battery device to Thunderstrike\n");851		goto err;852	}853 854	return 0;855 856err:857	power_supply_unregister(shield_dev->battery_dev.psy);858	return ret;859}860 861static struct shield_device *thunderstrike_create(struct hid_device *hdev)862{863	struct shield_device *shield_dev;864	struct thunderstrike *ts;865	int ret;866 867	ts = devm_kzalloc(&hdev->dev, sizeof(*ts), GFP_KERNEL);868	if (!ts)869		return ERR_PTR(-ENOMEM);870 871	ts->req_report_dmabuf = devm_kzalloc(872		&hdev->dev, THUNDERSTRIKE_HOSTCMD_REPORT_SIZE, GFP_KERNEL);873	if (!ts->req_report_dmabuf)874		return ERR_PTR(-ENOMEM);875 876	shield_dev = &ts->base;877	shield_dev->hdev = hdev;878	shield_dev->codename = "Thunderstrike";879 880	spin_lock_init(&ts->haptics_update_lock);881	spin_lock_init(&ts->psy_stats_lock);882	INIT_WORK(&ts->hostcmd_req_work, thunderstrike_hostcmd_req_work_handler);883 884	hid_set_drvdata(hdev, shield_dev);885 886	ts->id = ida_alloc(&thunderstrike_ida, GFP_KERNEL);887	if (ts->id < 0)888		return ERR_PTR(ts->id);889 890	ts->haptics_dev = shield_haptics_create(shield_dev, thunderstrike_play_effect);891	if (IS_ERR(ts->haptics_dev)) {892		hid_err(hdev, "Failed to create Thunderstrike haptics instance\n");893		ret = PTR_ERR(ts->haptics_dev);894		goto err_id;895	}896 897	ret = thunderstrike_psy_create(shield_dev);898	if (ret) {899		hid_err(hdev, "Failed to create Thunderstrike power supply instance\n");900		goto err_haptics;901	}902 903	ret = thunderstrike_led_create(ts);904	if (ret) {905		hid_err(hdev, "Failed to create Thunderstrike LED instance\n");906		goto err_psy;907	}908 909	timer_setup(&ts->psy_stats_timer, thunderstrike_psy_stats_timer_handler, 0);910 911	hid_info(hdev, "Registered Thunderstrike controller\n");912	return shield_dev;913 914err_psy:915	power_supply_unregister(shield_dev->battery_dev.psy);916err_haptics:917	if (ts->haptics_dev)918		input_unregister_device(ts->haptics_dev);919err_id:920	ida_free(&thunderstrike_ida, ts->id);921	return ERR_PTR(ret);922}923 924static void thunderstrike_destroy(struct thunderstrike *ts)925{926	led_classdev_unregister(&ts->led_dev);927	power_supply_unregister(ts->base.battery_dev.psy);928	if (ts->haptics_dev)929		input_unregister_device(ts->haptics_dev);930	ida_free(&thunderstrike_ida, ts->id);931}932 933static int android_input_mapping(struct hid_device *hdev, struct hid_input *hi,934				 struct hid_field *field,935				 struct hid_usage *usage, unsigned long **bit,936				 int *max)937{938	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)939		return 0;940 941	switch (usage->hid & HID_USAGE) {942	case HID_USAGE_ANDROID_PLAYPAUSE_BTN:943		android_map_key(KEY_PLAYPAUSE);944		break;945	case HID_USAGE_ANDROID_VOLUMEUP_BTN:946		android_map_key(KEY_VOLUMEUP);947		break;948	case HID_USAGE_ANDROID_VOLUMEDOWN_BTN:949		android_map_key(KEY_VOLUMEDOWN);950		break;951	case HID_USAGE_ANDROID_SEARCH_BTN:952		android_map_key(BTN_Z);953		break;954	case HID_USAGE_ANDROID_HOME_BTN:955		android_map_key(BTN_MODE);956		break;957	case HID_USAGE_ANDROID_BACK_BTN:958		android_map_key(BTN_SELECT);959		break;960	default:961		return 0;962	}963 964	return 1;965}966 967static ssize_t firmware_version_show(struct device *dev,968				     struct device_attribute *attr, char *buf)969{970	struct hid_device *hdev = to_hid_device(dev);971	struct shield_device *shield_dev;972	int ret;973 974	shield_dev = hid_get_drvdata(hdev);975 976	if (test_bit(SHIELD_FW_VERSION_INITIALIZED, &shield_dev->initialized_flags))977		ret = sysfs_emit(buf, "0x%04X\n", shield_dev->fw_version);978	else979		ret = sysfs_emit(buf, NOT_INIT_STR "\n");980 981	return ret;982}983 984static DEVICE_ATTR_RO(firmware_version);985 986static ssize_t hardware_version_show(struct device *dev,987				     struct device_attribute *attr, char *buf)988{989	struct hid_device *hdev = to_hid_device(dev);990	struct shield_device *shield_dev;991	char board_revision_str[4];992	int ret;993 994	shield_dev = hid_get_drvdata(hdev);995 996	if (test_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags)) {997		shield_strrev(board_revision_str, 4, shield_dev->board_info.revision);998		ret = sysfs_emit(buf, "%s BOARD_REVISION_%s (0x%04X)\n",999				 shield_dev->codename, board_revision_str,1000				 shield_dev->board_info.revision);1001	} else1002		ret = sysfs_emit(buf, NOT_INIT_STR "\n");1003 1004	return ret;1005}1006 1007static DEVICE_ATTR_RO(hardware_version);1008 1009static ssize_t serial_number_show(struct device *dev,1010				  struct device_attribute *attr, char *buf)1011{1012	struct hid_device *hdev = to_hid_device(dev);1013	struct shield_device *shield_dev;1014	int ret;1015 1016	shield_dev = hid_get_drvdata(hdev);1017 1018	if (test_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags))1019		ret = sysfs_emit(buf, "%s\n", shield_dev->board_info.serial_number);1020	else1021		ret = sysfs_emit(buf, NOT_INIT_STR "\n");1022 1023	return ret;1024}1025 1026static DEVICE_ATTR_RO(serial_number);1027 1028static struct attribute *shield_device_attrs[] = {1029	&dev_attr_firmware_version.attr,1030	&dev_attr_hardware_version.attr,1031	&dev_attr_serial_number.attr,1032	NULL,1033};1034ATTRIBUTE_GROUPS(shield_device);1035 1036static int shield_raw_event(struct hid_device *hdev, struct hid_report *report,1037			    u8 *data, int size)1038{1039	struct shield_device *dev = hid_get_drvdata(hdev);1040 1041	return thunderstrike_parse_report(dev, report, data, size);1042}1043 1044static int shield_probe(struct hid_device *hdev, const struct hid_device_id *id)1045{1046	struct shield_device *shield_dev = NULL;1047	struct thunderstrike *ts;1048	int ret;1049 1050	ret = hid_parse(hdev);1051	if (ret) {1052		hid_err(hdev, "Parse failed\n");1053		return ret;1054	}1055 1056	switch (id->product) {1057	case USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER:1058		shield_dev = thunderstrike_create(hdev);1059		break;1060	}1061 1062	if (unlikely(!shield_dev)) {1063		hid_err(hdev, "Failed to identify SHIELD device\n");1064		return -ENODEV;1065	}1066	if (IS_ERR(shield_dev)) {1067		hid_err(hdev, "Failed to create SHIELD device\n");1068		return PTR_ERR(shield_dev);1069	}1070 1071	ts = container_of(shield_dev, struct thunderstrike, base);1072 1073	ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT);1074	if (ret) {1075		hid_err(hdev, "Failed to start HID device\n");1076		goto err_ts_create;1077	}1078 1079	ret = hid_hw_open(hdev);1080	if (ret) {1081		hid_err(hdev, "Failed to open HID device\n");1082		goto err_stop;1083	}1084 1085	thunderstrike_device_init_info(shield_dev);1086 1087	return ret;1088 1089err_stop:1090	hid_hw_stop(hdev);1091err_ts_create:1092	thunderstrike_destroy(ts);1093	return ret;1094}1095 1096static void shield_remove(struct hid_device *hdev)1097{1098	struct shield_device *dev = hid_get_drvdata(hdev);1099	struct thunderstrike *ts;1100 1101	ts = container_of(dev, struct thunderstrike, base);1102 1103	hid_hw_close(hdev);1104	thunderstrike_destroy(ts);1105	del_timer_sync(&ts->psy_stats_timer);1106	cancel_work_sync(&ts->hostcmd_req_work);1107	hid_hw_stop(hdev);1108}1109 1110static const struct hid_device_id shield_devices[] = {1111	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NVIDIA,1112			       USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER) },1113	{ HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA,1114			 USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER) },1115	{ }1116};1117MODULE_DEVICE_TABLE(hid, shield_devices);1118 1119static struct hid_driver shield_driver = {1120	.name          = "shield",1121	.id_table      = shield_devices,1122	.input_mapping = android_input_mapping,1123	.probe         = shield_probe,1124	.remove        = shield_remove,1125	.raw_event     = shield_raw_event,1126	.driver = {1127		.dev_groups = shield_device_groups,1128	},1129};1130module_hid_driver(shield_driver);1131 1132MODULE_AUTHOR("Rahul Rameshbabu <rrameshbabu@nvidia.com>");1133MODULE_DESCRIPTION("HID Driver for NVIDIA SHIELD peripherals.");1134MODULE_LICENSE("GPL");1135