brintos

brintos / linux-shallow public Read only

0
0
Text · 14.2 KiB · 1ee5239 Raw
588 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Supports for the power IC on the Surface 3 tablet.4 *5 * (C) Copyright 2016-2018 Red Hat, Inc6 * (C) Copyright 2016-2018 Benjamin Tissoires <benjamin.tissoires@gmail.com>7 * (C) Copyright 2016 Stephen Just <stephenjust@gmail.com>8 *9 * This driver has been reverse-engineered by parsing the DSDT of the Surface 310 * and looking at the registers of the chips.11 *12 * The DSDT allowed to find out that:13 * - the driver is required for the ACPI BAT0 device to communicate to the chip14 *   through an operation region.15 * - the various defines for the operation region functions to communicate with16 *   this driver17 * - the DSM 3f99e367-6220-4955-8b0f-06ef2ae79412 allows to trigger ACPI18 *   events to BAT0 (the code is all available in the DSDT).19 *20 * Further findings regarding the 2 chips declared in the MSHW0011 are:21 * - there are 2 chips declared:22 *   . 0x22 seems to control the ADP1 line status (and probably the charger)23 *   . 0x55 controls the battery directly24 * - the battery chip uses a SMBus protocol (using plain SMBus allows non25 *   destructive commands):26 *   . the commands/registers used are in the range 0x00..0x7F27 *   . if bit 8 (0x80) is set in the SMBus command, the returned value is the28 *     same as when it is not set. There is a high chance this bit is the29 *     read/write30 *   . the various registers semantic as been deduced by observing the register31 *     dumps.32 */33 34#include <linux/acpi.h>35#include <linux/bits.h>36#include <linux/freezer.h>37#include <linux/i2c.h>38#include <linux/kernel.h>39#include <linux/kthread.h>40#include <linux/slab.h>41#include <linux/types.h>42#include <linux/uuid.h>43#include <linux/unaligned.h>44 45#define SURFACE_3_POLL_INTERVAL		(2 * HZ)46#define SURFACE_3_STRLEN		1047 48struct mshw0011_data {49	struct i2c_client	*adp1;50	struct i2c_client	*bat0;51	unsigned short		notify_mask;52	struct task_struct	*poll_task;53	bool			kthread_running;54 55	bool			charging;56	bool			bat_charging;57	u8			trip_point;58	s32			full_capacity;59};60 61struct mshw0011_handler_data {62	struct acpi_connection_info	info;63	struct i2c_client		*client;64};65 66struct bix {67	u32	revision;68	u32	power_unit;69	u32	design_capacity;70	u32	last_full_charg_capacity;71	u32	battery_technology;72	u32	design_voltage;73	u32	design_capacity_of_warning;74	u32	design_capacity_of_low;75	u32	cycle_count;76	u32	measurement_accuracy;77	u32	max_sampling_time;78	u32	min_sampling_time;79	u32	max_average_interval;80	u32	min_average_interval;81	u32	battery_capacity_granularity_1;82	u32	battery_capacity_granularity_2;83	char	model[SURFACE_3_STRLEN];84	char	serial[SURFACE_3_STRLEN];85	char	type[SURFACE_3_STRLEN];86	char	OEM[SURFACE_3_STRLEN];87} __packed;88 89struct bst {90	u32	battery_state;91	s32	battery_present_rate;92	u32	battery_remaining_capacity;93	u32	battery_present_voltage;94} __packed;95 96struct gsb_command {97	u8	arg0;98	u8	arg1;99	u8	arg2;100} __packed;101 102struct gsb_buffer {103	u8	status;104	u8	len;105	u8	ret;106	union {107		struct gsb_command	cmd;108		struct bst		bst;109		struct bix		bix;110	} __packed;111} __packed;112 113#define ACPI_BATTERY_STATE_DISCHARGING	BIT(0)114#define ACPI_BATTERY_STATE_CHARGING	BIT(1)115#define ACPI_BATTERY_STATE_CRITICAL	BIT(2)116 117#define MSHW0011_CMD_DEST_BAT0		0x01118#define MSHW0011_CMD_DEST_ADP1		0x03119 120#define MSHW0011_CMD_BAT0_STA		0x01121#define MSHW0011_CMD_BAT0_BIX		0x02122#define MSHW0011_CMD_BAT0_BCT		0x03123#define MSHW0011_CMD_BAT0_BTM		0x04124#define MSHW0011_CMD_BAT0_BST		0x05125#define MSHW0011_CMD_BAT0_BTP		0x06126#define MSHW0011_CMD_ADP1_PSR		0x07127#define MSHW0011_CMD_BAT0_PSOC		0x09128#define MSHW0011_CMD_BAT0_PMAX		0x0a129#define MSHW0011_CMD_BAT0_PSRC		0x0b130#define MSHW0011_CMD_BAT0_CHGI		0x0c131#define MSHW0011_CMD_BAT0_ARTG		0x0d132 133#define MSHW0011_NOTIFY_GET_VERSION	0x00134#define MSHW0011_NOTIFY_ADP1		0x01135#define MSHW0011_NOTIFY_BAT0_BST	0x02136#define MSHW0011_NOTIFY_BAT0_BIX	0x05137 138#define MSHW0011_ADP1_REG_PSR		0x04139 140#define MSHW0011_BAT0_REG_CAPACITY		0x0c141#define MSHW0011_BAT0_REG_FULL_CHG_CAPACITY	0x0e142#define MSHW0011_BAT0_REG_DESIGN_CAPACITY	0x40143#define MSHW0011_BAT0_REG_VOLTAGE	0x08144#define MSHW0011_BAT0_REG_RATE		0x14145#define MSHW0011_BAT0_REG_OEM		0x45146#define MSHW0011_BAT0_REG_TYPE		0x4e147#define MSHW0011_BAT0_REG_SERIAL_NO	0x56148#define MSHW0011_BAT0_REG_CYCLE_CNT	0x6e149 150#define MSHW0011_EV_2_5_MASK		GENMASK(8, 0)151 152/* 3f99e367-6220-4955-8b0f-06ef2ae79412 */153static const guid_t mshw0011_guid =154	GUID_INIT(0x3F99E367, 0x6220, 0x4955, 0x8B, 0x0F, 0x06, 0xEF,155		  0x2A, 0xE7, 0x94, 0x12);156 157static int158mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2,159		unsigned int *ret_value)160{161	union acpi_object *obj;162	acpi_handle handle;163	unsigned int i;164 165	handle = ACPI_HANDLE(&cdata->adp1->dev);166	if (!handle)167		return -ENODEV;168 169	obj = acpi_evaluate_dsm_typed(handle, &mshw0011_guid, arg1, arg2, NULL,170				      ACPI_TYPE_BUFFER);171	if (!obj) {172		dev_err(&cdata->adp1->dev, "device _DSM execution failed\n");173		return -ENODEV;174	}175 176	*ret_value = 0;177	for (i = 0; i < obj->buffer.length; i++)178		*ret_value |= obj->buffer.pointer[i] << (i * 8);179 180	ACPI_FREE(obj);181	return 0;182}183 184static const struct bix default_bix = {185	.revision = 0x00,186	.power_unit = 0x01,187	.design_capacity = 0x1dca,188	.last_full_charg_capacity = 0x1dca,189	.battery_technology = 0x01,190	.design_voltage = 0x10df,191	.design_capacity_of_warning = 0x8f,192	.design_capacity_of_low = 0x47,193	.cycle_count = 0xffffffff,194	.measurement_accuracy = 0x00015f90,195	.max_sampling_time = 0x03e8,196	.min_sampling_time = 0x03e8,197	.max_average_interval = 0x03e8,198	.min_average_interval = 0x03e8,199	.battery_capacity_granularity_1 = 0x45,200	.battery_capacity_granularity_2 = 0x11,201	.model = "P11G8M",202	.serial = "",203	.type = "LION",204	.OEM = "",205};206 207static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)208{209	struct i2c_client *client = cdata->bat0;210	char buf[SURFACE_3_STRLEN];211	int ret;212 213	*bix = default_bix;214 215	/* get design capacity */216	ret = i2c_smbus_read_word_data(client,217				       MSHW0011_BAT0_REG_DESIGN_CAPACITY);218	if (ret < 0) {219		dev_err(&client->dev, "Error reading design capacity: %d\n",220			ret);221		return ret;222	}223	bix->design_capacity = ret;224 225	/* get last full charge capacity */226	ret = i2c_smbus_read_word_data(client,227				       MSHW0011_BAT0_REG_FULL_CHG_CAPACITY);228	if (ret < 0) {229		dev_err(&client->dev,230			"Error reading last full charge capacity: %d\n", ret);231		return ret;232	}233	bix->last_full_charg_capacity = ret;234 235	/*236	 * Get serial number, on some devices (with unofficial replacement237	 * battery?) reading any of the serial number range addresses gets238	 * nacked in this case just leave the serial number empty.239	 */240	ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_SERIAL_NO,241					    sizeof(buf), buf);242	if (ret == -EREMOTEIO) {243		/* no serial number available */244	} else if (ret != sizeof(buf)) {245		dev_err(&client->dev, "Error reading serial no: %d\n", ret);246		return ret;247	} else {248		snprintf(bix->serial, ARRAY_SIZE(bix->serial), "%3pE%6pE", buf + 7, buf);249	}250 251	/* get cycle count */252	ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CYCLE_CNT);253	if (ret < 0) {254		dev_err(&client->dev, "Error reading cycle count: %d\n", ret);255		return ret;256	}257	bix->cycle_count = ret;258 259	/* get OEM name */260	ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_OEM,261					    4, buf);262	if (ret != 4) {263		dev_err(&client->dev, "Error reading cycle count: %d\n", ret);264		return ret;265	}266	snprintf(bix->OEM, ARRAY_SIZE(bix->OEM), "%3pE", buf);267 268	return 0;269}270 271static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)272{273	struct i2c_client *client = cdata->bat0;274	int rate, capacity, voltage, state;275	s16 tmp;276 277	rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);278	if (rate < 0)279		return rate;280 281	capacity = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CAPACITY);282	if (capacity < 0)283		return capacity;284 285	voltage = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_VOLTAGE);286	if (voltage < 0)287		return voltage;288 289	tmp = rate;290	bst->battery_present_rate = abs((s32)tmp);291 292	state = 0;293	if ((s32) tmp > 0)294		state |= ACPI_BATTERY_STATE_CHARGING;295	else if ((s32) tmp < 0)296		state |= ACPI_BATTERY_STATE_DISCHARGING;297	bst->battery_state = state;298 299	bst->battery_remaining_capacity = capacity;300	bst->battery_present_voltage = voltage;301 302	return 0;303}304 305static int mshw0011_adp_psr(struct mshw0011_data *cdata)306{307	return i2c_smbus_read_byte_data(cdata->adp1, MSHW0011_ADP1_REG_PSR);308}309 310static int mshw0011_isr(struct mshw0011_data *cdata)311{312	struct bst bst;313	struct bix bix;314	int ret;315	bool status, bat_status;316 317	ret = mshw0011_adp_psr(cdata);318	if (ret < 0)319		return ret;320 321	status = ret;322	if (status != cdata->charging)323		mshw0011_notify(cdata, cdata->notify_mask,324				MSHW0011_NOTIFY_ADP1, &ret);325 326	cdata->charging = status;327 328	ret = mshw0011_bst(cdata, &bst);329	if (ret < 0)330		return ret;331 332	bat_status = bst.battery_state;333	if (bat_status != cdata->bat_charging)334		mshw0011_notify(cdata, cdata->notify_mask,335				MSHW0011_NOTIFY_BAT0_BST, &ret);336 337	cdata->bat_charging = bat_status;338 339	ret = mshw0011_bix(cdata, &bix);340	if (ret < 0)341		return ret;342 343	if (bix.last_full_charg_capacity != cdata->full_capacity)344		mshw0011_notify(cdata, cdata->notify_mask,345				MSHW0011_NOTIFY_BAT0_BIX, &ret);346 347	cdata->full_capacity = bix.last_full_charg_capacity;348 349	return 0;350}351 352static int mshw0011_poll_task(void *data)353{354	struct mshw0011_data *cdata = data;355	int ret = 0;356 357	cdata->kthread_running = true;358 359	set_freezable();360 361	while (!kthread_should_stop()) {362		schedule_timeout_interruptible(SURFACE_3_POLL_INTERVAL);363		try_to_freeze();364		ret = mshw0011_isr(data);365		if (ret)366			break;367	}368 369	cdata->kthread_running = false;370	return ret;371}372 373static acpi_status374mshw0011_space_handler(u32 function, acpi_physical_address command,375			u32 bits, u64 *value64,376			void *handler_context, void *region_context)377{378	struct gsb_buffer *gsb = (struct gsb_buffer *)value64;379	struct mshw0011_handler_data *data = handler_context;380	struct acpi_connection_info *info = &data->info;381	struct acpi_resource_i2c_serialbus *sb;382	struct i2c_client *client = data->client;383	struct mshw0011_data *cdata = i2c_get_clientdata(client);384	struct acpi_resource *ares;385	u32 accessor_type = function >> 16;386	acpi_status ret;387	int status = 1;388 389	ret = acpi_buffer_to_resource(info->connection, info->length, &ares);390	if (ACPI_FAILURE(ret))391		return ret;392 393	if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) {394		ret = AE_BAD_PARAMETER;395		goto err;396	}397 398	if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {399		ret = AE_BAD_PARAMETER;400		goto err;401	}402 403	if (gsb->cmd.arg0 == MSHW0011_CMD_DEST_ADP1 &&404	    gsb->cmd.arg1 == MSHW0011_CMD_ADP1_PSR) {405		status = mshw0011_adp_psr(cdata);406		if (status >= 0) {407			ret = AE_OK;408			goto out;409		} else {410			ret = AE_ERROR;411			goto err;412		}413	}414 415	if (gsb->cmd.arg0 != MSHW0011_CMD_DEST_BAT0) {416		ret = AE_BAD_PARAMETER;417		goto err;418	}419 420	switch (gsb->cmd.arg1) {421	case MSHW0011_CMD_BAT0_STA:422		break;423	case MSHW0011_CMD_BAT0_BIX:424		ret = mshw0011_bix(cdata, &gsb->bix);425		break;426	case MSHW0011_CMD_BAT0_BTP:427		cdata->trip_point = gsb->cmd.arg2;428		break;429	case MSHW0011_CMD_BAT0_BST:430		ret = mshw0011_bst(cdata, &gsb->bst);431		break;432	default:433		dev_info(&cdata->bat0->dev, "command(0x%02x) is not supported.\n", gsb->cmd.arg1);434		ret = AE_BAD_PARAMETER;435		goto err;436	}437 438 out:439	gsb->ret = status;440	gsb->status = 0;441 442 err:443	ACPI_FREE(ares);444	return ret;445}446 447static int mshw0011_install_space_handler(struct i2c_client *client)448{449	struct acpi_device *adev;450	struct mshw0011_handler_data *data;451	acpi_status status;452 453	adev = ACPI_COMPANION(&client->dev);454	if (!adev)455		return -ENODEV;456 457	data = kzalloc(sizeof(struct mshw0011_handler_data),458			    GFP_KERNEL);459	if (!data)460		return -ENOMEM;461 462	data->client = client;463	status = acpi_bus_attach_private_data(adev->handle, (void *)data);464	if (ACPI_FAILURE(status)) {465		kfree(data);466		return -ENOMEM;467	}468 469	status = acpi_install_address_space_handler(adev->handle,470						    ACPI_ADR_SPACE_GSBUS,471						    &mshw0011_space_handler,472						    NULL,473						    data);474	if (ACPI_FAILURE(status)) {475		dev_err(&client->dev, "Error installing i2c space handler\n");476		acpi_bus_detach_private_data(adev->handle);477		kfree(data);478		return -ENOMEM;479	}480 481	acpi_dev_clear_dependencies(adev);482	return 0;483}484 485static void mshw0011_remove_space_handler(struct i2c_client *client)486{487	struct mshw0011_handler_data *data;488	acpi_handle handle;489	acpi_status status;490 491	handle = ACPI_HANDLE(&client->dev);492	if (!handle)493		return;494 495	acpi_remove_address_space_handler(handle,496				ACPI_ADR_SPACE_GSBUS,497				&mshw0011_space_handler);498 499	status = acpi_bus_get_private_data(handle, (void **)&data);500	if (ACPI_SUCCESS(status))501		kfree(data);502 503	acpi_bus_detach_private_data(handle);504}505 506static int mshw0011_probe(struct i2c_client *client)507{508	struct i2c_board_info board_info;509	struct device *dev = &client->dev;510	struct i2c_client *bat0;511	struct mshw0011_data *data;512	int error, mask;513 514	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);515	if (!data)516		return -ENOMEM;517 518	data->adp1 = client;519	i2c_set_clientdata(client, data);520 521	memset(&board_info, 0, sizeof(board_info));522	strscpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE);523 524	bat0 = i2c_acpi_new_device(dev, 1, &board_info);525	if (IS_ERR(bat0))526		return PTR_ERR(bat0);527 528	data->bat0 = bat0;529	i2c_set_clientdata(bat0, data);530 531	error = mshw0011_notify(data, 1, MSHW0011_NOTIFY_GET_VERSION, &mask);532	if (error)533		goto out_err;534 535	data->notify_mask = mask == MSHW0011_EV_2_5_MASK;536 537	data->poll_task = kthread_run(mshw0011_poll_task, data, "mshw0011_adp");538	if (IS_ERR(data->poll_task)) {539		error = PTR_ERR(data->poll_task);540		dev_err(&client->dev, "Unable to run kthread err %d\n", error);541		goto out_err;542	}543 544	error = mshw0011_install_space_handler(client);545	if (error)546		goto out_err;547 548	return 0;549 550out_err:551	if (data->kthread_running)552		kthread_stop(data->poll_task);553	i2c_unregister_device(data->bat0);554	return error;555}556 557static void mshw0011_remove(struct i2c_client *client)558{559	struct mshw0011_data *cdata = i2c_get_clientdata(client);560 561	mshw0011_remove_space_handler(client);562 563	if (cdata->kthread_running)564		kthread_stop(cdata->poll_task);565 566	i2c_unregister_device(cdata->bat0);567}568 569static const struct acpi_device_id mshw0011_acpi_match[] = {570	{ "MSHW0011", 0 },571	{ }572};573MODULE_DEVICE_TABLE(acpi, mshw0011_acpi_match);574 575static struct i2c_driver mshw0011_driver = {576	.probe = mshw0011_probe,577	.remove = mshw0011_remove,578	.driver = {579		.name = "mshw0011",580		.acpi_match_table = mshw0011_acpi_match,581	},582};583module_i2c_driver(mshw0011_driver);584 585MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");586MODULE_DESCRIPTION("mshw0011 driver");587MODULE_LICENSE("GPL v2");588