forked from mirrors/linux
		
	hwmon: (oxp-sensors) Add tt_toggle attribute on supported boards
OneXPlayer boards from the last generation (both for OneXPlayer and AOK ZOE brands) have a toggle in the EC to switch the "Turbo/Silent" button into a different keyboard event. Add a means to use that "Turbo button takeover" function and expose it to userspace in a custom sysfs `tt_toggle` attribute. It can be read to take the current state. Write 1|0 to activate the function. The specific keycode is dependent on the board but can be checked by running `evtest` utility. Newer BIOS on the OneXPlayer added this function aside from string changes. Add a board enum to differentiate it from the old OneXplayer Mini AMD BIOS. Currently known supported boards: - AOK ZOE A1 - OneXPlayer Mini AMD (only newer BIOS version supported) - OneXPlayer Mini Pro Signed-off-by: Joaquín Ignacio Aramendía <samsagax@gmail.com> Link: https://lore.kernel.org/r/20230611143332.40590-2-samsagax@gmail.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
		
							parent
							
								
									fbb5a7fee0
								
							
						
					
					
						commit
						be144ee491
					
				
					 2 changed files with 150 additions and 1 deletions
				
			
		|  | @ -19,6 +19,11 @@ out the EC registers and values to write to since the EC layout and model is | ||||||
| different. Aya Neo devices preceding the AIR may not be supportable as the EC | different. Aya Neo devices preceding the AIR may not be supportable as the EC | ||||||
| model is different and do not appear to have manual control capabilities. | model is different and do not appear to have manual control capabilities. | ||||||
| 
 | 
 | ||||||
|  | Some models have a toggle for changing the behaviour of the "Turbo/Silent" | ||||||
|  | button of the device. It will change the key event that it triggers with | ||||||
|  | a flip of the `tt_toggle` attribute. See below for boards that support this | ||||||
|  | function. | ||||||
|  | 
 | ||||||
| Supported devices | Supported devices | ||||||
| ----------------- | ----------------- | ||||||
| 
 | 
 | ||||||
|  | @ -33,6 +38,11 @@ Currently the driver supports the following handhelds: | ||||||
|  - OneXPlayer mini AMD |  - OneXPlayer mini AMD | ||||||
|  - OneXPlayer mini AMD PRO |  - OneXPlayer mini AMD PRO | ||||||
| 
 | 
 | ||||||
|  | "Turbo/Silent" button behaviour toggle is only supported on: | ||||||
|  |  - AOK ZOE A1 | ||||||
|  |  - OneXPlayer mini AMD (only with updated alpha BIOS) | ||||||
|  |  - OneXPlayer mini AMD PRO | ||||||
|  | 
 | ||||||
| Sysfs entries | Sysfs entries | ||||||
| ------------- | ------------- | ||||||
| 
 | 
 | ||||||
|  | @ -49,3 +59,10 @@ pwm1 | ||||||
|   Read Write. Read this attribute to see current duty cycle in the range [0-255]. |   Read Write. Read this attribute to see current duty cycle in the range [0-255]. | ||||||
|   When pwm1_enable is set to "1" (manual) write any value in the range [0-255] |   When pwm1_enable is set to "1" (manual) write any value in the range [0-255] | ||||||
|   to set fan speed. |   to set fan speed. | ||||||
|  | 
 | ||||||
|  | tt_toggle | ||||||
|  |   Read Write. Read this attribute to check the status of the turbo/silent | ||||||
|  |   button behaviour function. Write "1" to activate the switch and "0" to | ||||||
|  |   deactivate it. The specific keycodes and behaviour is specific to the device | ||||||
|  |   both with this function on and off. This attribute is attached to the platform | ||||||
|  |   driver and not to the hwmon driver (/sys/devices/platform/oxp-platform/tt_toggle) | ||||||
|  |  | ||||||
|  | @ -47,15 +47,29 @@ enum oxp_board { | ||||||
| 	aya_neo_air_pro, | 	aya_neo_air_pro, | ||||||
| 	aya_neo_geek, | 	aya_neo_geek, | ||||||
| 	oxp_mini_amd, | 	oxp_mini_amd, | ||||||
|  | 	oxp_mini_amd_a07, | ||||||
| 	oxp_mini_amd_pro, | 	oxp_mini_amd_pro, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static enum oxp_board board; | static enum oxp_board board; | ||||||
| 
 | 
 | ||||||
|  | /* Fan reading and PWM */ | ||||||
| #define OXP_SENSOR_FAN_REG		0x76 /* Fan reading is 2 registers long */ | #define OXP_SENSOR_FAN_REG		0x76 /* Fan reading is 2 registers long */ | ||||||
| #define OXP_SENSOR_PWM_ENABLE_REG	0x4A /* PWM enable is 1 register long */ | #define OXP_SENSOR_PWM_ENABLE_REG	0x4A /* PWM enable is 1 register long */ | ||||||
| #define OXP_SENSOR_PWM_REG		0x4B /* PWM reading is 1 register long */ | #define OXP_SENSOR_PWM_REG		0x4B /* PWM reading is 1 register long */ | ||||||
| 
 | 
 | ||||||
|  | /* Turbo button takeover function
 | ||||||
|  |  * Older boards have different values and EC registers | ||||||
|  |  * for the same function | ||||||
|  |  */ | ||||||
|  | #define OXP_OLD_TURBO_SWITCH_REG	0x1E | ||||||
|  | #define OXP_OLD_TURBO_TAKE_VAL		0x01 | ||||||
|  | #define OXP_OLD_TURBO_RETURN_VAL	0x00 | ||||||
|  | 
 | ||||||
|  | #define OXP_TURBO_SWITCH_REG		0xF1 | ||||||
|  | #define OXP_TURBO_TAKE_VAL		0x40 | ||||||
|  | #define OXP_TURBO_RETURN_VAL		0x00 | ||||||
|  | 
 | ||||||
| static const struct dmi_system_id dmi_table[] = { | static const struct dmi_system_id dmi_table[] = { | ||||||
| 	{ | 	{ | ||||||
| 		.matches = { | 		.matches = { | ||||||
|  | @ -104,7 +118,7 @@ static const struct dmi_system_id dmi_table[] = { | ||||||
| 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), | 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), | ||||||
| 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), | 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), | ||||||
| 		}, | 		}, | ||||||
| 		.driver_data = (void *)oxp_mini_amd, | 		.driver_data = (void *)oxp_mini_amd_a07, | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		.matches = { | 		.matches = { | ||||||
|  | @ -156,6 +170,102 @@ static int write_to_ec(u8 reg, u8 value) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Turbo button toggle functions */ | ||||||
|  | static int tt_toggle_enable(void) | ||||||
|  | { | ||||||
|  | 	u8 reg; | ||||||
|  | 	u8 val; | ||||||
|  | 
 | ||||||
|  | 	switch (board) { | ||||||
|  | 	case oxp_mini_amd_a07: | ||||||
|  | 		reg = OXP_OLD_TURBO_SWITCH_REG; | ||||||
|  | 		val = OXP_OLD_TURBO_TAKE_VAL; | ||||||
|  | 		break; | ||||||
|  | 	case oxp_mini_amd_pro: | ||||||
|  | 	case aok_zoe_a1: | ||||||
|  | 		reg = OXP_TURBO_SWITCH_REG; | ||||||
|  | 		val = OXP_TURBO_TAKE_VAL; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	return write_to_ec(reg, val); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tt_toggle_disable(void) | ||||||
|  | { | ||||||
|  | 	u8 reg; | ||||||
|  | 	u8 val; | ||||||
|  | 
 | ||||||
|  | 	switch (board) { | ||||||
|  | 	case oxp_mini_amd_a07: | ||||||
|  | 		reg = OXP_OLD_TURBO_SWITCH_REG; | ||||||
|  | 		val = OXP_OLD_TURBO_RETURN_VAL; | ||||||
|  | 		break; | ||||||
|  | 	case oxp_mini_amd_pro: | ||||||
|  | 	case aok_zoe_a1: | ||||||
|  | 		reg = OXP_TURBO_SWITCH_REG; | ||||||
|  | 		val = OXP_TURBO_RETURN_VAL; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	return write_to_ec(reg, val); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Callbacks for turbo toggle attribute */ | ||||||
|  | static ssize_t tt_toggle_store(struct device *dev, | ||||||
|  | 			       struct device_attribute *attr, const char *buf, | ||||||
|  | 			       size_t count) | ||||||
|  | { | ||||||
|  | 	int rval; | ||||||
|  | 	bool value; | ||||||
|  | 
 | ||||||
|  | 	rval = kstrtobool(buf, &value); | ||||||
|  | 	if (rval) | ||||||
|  | 		return rval; | ||||||
|  | 
 | ||||||
|  | 	if (value) { | ||||||
|  | 		rval = tt_toggle_enable(); | ||||||
|  | 		if (rval) | ||||||
|  | 			return rval; | ||||||
|  | 	} else { | ||||||
|  | 		rval = tt_toggle_disable(); | ||||||
|  | 		if (rval) | ||||||
|  | 			return rval; | ||||||
|  | 	} | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t tt_toggle_show(struct device *dev, | ||||||
|  | 			      struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	int retval; | ||||||
|  | 	u8 reg; | ||||||
|  | 	long val; | ||||||
|  | 
 | ||||||
|  | 	switch (board) { | ||||||
|  | 	case oxp_mini_amd_a07: | ||||||
|  | 		reg = OXP_OLD_TURBO_SWITCH_REG; | ||||||
|  | 		break; | ||||||
|  | 	case oxp_mini_amd_pro: | ||||||
|  | 	case aok_zoe_a1: | ||||||
|  | 		reg = OXP_TURBO_SWITCH_REG; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	retval = read_from_ec(reg, 1, &val); | ||||||
|  | 	if (retval) | ||||||
|  | 		return retval; | ||||||
|  | 
 | ||||||
|  | 	return sysfs_emit(buf, "%d\n", !!val); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DEVICE_ATTR_RW(tt_toggle); | ||||||
|  | 
 | ||||||
|  | /* PWM enable/disable functions */ | ||||||
| static int oxp_pwm_enable(void) | static int oxp_pwm_enable(void) | ||||||
| { | { | ||||||
| 	return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01); | 	return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01); | ||||||
|  | @ -206,6 +316,7 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, | ||||||
| 			case aya_neo_air_pro: | 			case aya_neo_air_pro: | ||||||
| 			case aya_neo_geek: | 			case aya_neo_geek: | ||||||
| 			case oxp_mini_amd: | 			case oxp_mini_amd: | ||||||
|  | 			case oxp_mini_amd_a07: | ||||||
| 				*val = (*val * 255) / 100; | 				*val = (*val * 255) / 100; | ||||||
| 				break; | 				break; | ||||||
| 			case oxp_mini_amd_pro: | 			case oxp_mini_amd_pro: | ||||||
|  | @ -247,6 +358,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, | ||||||
| 			case aya_neo_air_pro: | 			case aya_neo_air_pro: | ||||||
| 			case aya_neo_geek: | 			case aya_neo_geek: | ||||||
| 			case oxp_mini_amd: | 			case oxp_mini_amd: | ||||||
|  | 			case oxp_mini_amd_a07: | ||||||
| 				val = (val * 100) / 255; | 				val = (val * 100) / 255; | ||||||
| 				break; | 				break; | ||||||
| 			case aok_zoe_a1: | 			case aok_zoe_a1: | ||||||
|  | @ -274,6 +386,13 @@ static const struct hwmon_channel_info * const oxp_platform_sensors[] = { | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct attribute *oxp_ec_attrs[] = { | ||||||
|  | 	&dev_attr_tt_toggle.attr, | ||||||
|  | 	NULL | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ATTRIBUTE_GROUPS(oxp_ec); | ||||||
|  | 
 | ||||||
| static const struct hwmon_ops oxp_ec_hwmon_ops = { | static const struct hwmon_ops oxp_ec_hwmon_ops = { | ||||||
| 	.is_visible = oxp_ec_hwmon_is_visible, | 	.is_visible = oxp_ec_hwmon_is_visible, | ||||||
| 	.read = oxp_platform_read, | 	.read = oxp_platform_read, | ||||||
|  | @ -291,6 +410,7 @@ static int oxp_platform_probe(struct platform_device *pdev) | ||||||
| 	const struct dmi_system_id *dmi_entry; | 	const struct dmi_system_id *dmi_entry; | ||||||
| 	struct device *dev = &pdev->dev; | 	struct device *dev = &pdev->dev; | ||||||
| 	struct device *hwdev; | 	struct device *hwdev; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Have to check for AMD processor here because DMI strings are the | 	 * Have to check for AMD processor here because DMI strings are the | ||||||
|  | @ -305,6 +425,18 @@ static int oxp_platform_probe(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; | 	board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; | ||||||
| 
 | 
 | ||||||
|  | 	switch (board) { | ||||||
|  | 	case aok_zoe_a1: | ||||||
|  | 	case oxp_mini_amd_a07: | ||||||
|  | 	case oxp_mini_amd_pro: | ||||||
|  | 		ret = devm_device_add_groups(dev, oxp_ec_groups); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, | 	hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, | ||||||
| 						     &oxp_ec_chip_info, NULL); | 						     &oxp_ec_chip_info, NULL); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Joaquín Ignacio Aramendía
						Joaquín Ignacio Aramendía