brintos

brintos / linux-shallow public Read only

0
0
Text · 26.4 KiB · ee01761 Raw
1080 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Azoteq IQS620A/621/622/624/625 Multi-Function Sensors4 *5 * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>6 *7 * These devices rely on application-specific register settings and calibration8 * data developed in and exported from a suite of GUIs offered by the vendor. A9 * separate tool converts the GUIs' ASCII-based output into a standard firmware10 * file parsed by the driver.11 *12 * Link to datasheets and GUIs: https://www.azoteq.com/13 *14 * Link to conversion tool: https://github.com/jlabundy/iqs62x-h2bin.git15 */16 17#include <linux/completion.h>18#include <linux/delay.h>19#include <linux/device.h>20#include <linux/err.h>21#include <linux/firmware.h>22#include <linux/i2c.h>23#include <linux/interrupt.h>24#include <linux/kernel.h>25#include <linux/list.h>26#include <linux/mfd/core.h>27#include <linux/mfd/iqs62x.h>28#include <linux/module.h>29#include <linux/notifier.h>30#include <linux/of.h>31#include <linux/property.h>32#include <linux/regmap.h>33#include <linux/slab.h>34#include <linux/unaligned.h>35 36#define IQS62X_PROD_NUM				0x0037 38#define IQS62X_SYS_FLAGS			0x1039 40#define IQS620_HALL_FLAGS			0x1641#define IQS621_HALL_FLAGS			0x1942#define IQS622_HALL_FLAGS			IQS621_HALL_FLAGS43 44#define IQS624_INTERVAL_NUM			0x1845#define IQS625_INTERVAL_NUM			0x1246 47#define IQS622_PROX_SETTINGS_4			0x4848#define IQS620_PROX_SETTINGS_4			0x5049#define IQS620_PROX_SETTINGS_4_SAR_EN		BIT(7)50 51#define IQS621_ALS_CAL_DIV_LUX			0x8252#define IQS621_ALS_CAL_DIV_IR			0x8353 54#define IQS620_TEMP_CAL_MULT			0xC255#define IQS620_TEMP_CAL_DIV			0xC356#define IQS620_TEMP_CAL_OFFS			0xC457 58#define IQS62X_SYS_SETTINGS			0xD059#define IQS62X_SYS_SETTINGS_ACK_RESET		BIT(6)60#define IQS62X_SYS_SETTINGS_EVENT_MODE		BIT(5)61#define IQS62X_SYS_SETTINGS_CLK_DIV		BIT(4)62#define IQS62X_SYS_SETTINGS_COMM_ATI		BIT(3)63#define IQS62X_SYS_SETTINGS_REDO_ATI		BIT(1)64 65#define IQS62X_PWR_SETTINGS			0xD266#define IQS62X_PWR_SETTINGS_DIS_AUTO		BIT(5)67#define IQS62X_PWR_SETTINGS_PWR_MODE_MASK	(BIT(4) | BIT(3))68#define IQS62X_PWR_SETTINGS_PWR_MODE_HALT	(BIT(4) | BIT(3))69#define IQS62X_PWR_SETTINGS_PWR_MODE_NORM	070 71#define IQS62X_OTP_CMD				0xF072#define IQS62X_OTP_CMD_FG3			0x1373#define IQS62X_OTP_DATA				0xF174#define IQS62X_MAX_REG				0xFF75 76#define IQS62X_HALL_CAL_MASK			GENMASK(3, 0)77 78#define IQS62X_FW_REC_TYPE_INFO			079#define IQS62X_FW_REC_TYPE_PROD			180#define IQS62X_FW_REC_TYPE_HALL			281#define IQS62X_FW_REC_TYPE_MASK			382#define IQS62X_FW_REC_TYPE_DATA			483 84#define IQS62X_ATI_STARTUP_MS			35085#define IQS62X_FILT_SETTLE_MS			25086 87struct iqs62x_fw_rec {88	u8 type;89	u8 addr;90	u8 len;91	u8 data;92} __packed;93 94struct iqs62x_fw_blk {95	struct list_head list;96	u8 addr;97	u8 mask;98	u8 len;99	u8 data[] __counted_by(len);100};101 102struct iqs62x_info {103	u8 prod_num;104	u8 sw_num;105	u8 hw_num;106} __packed;107 108static int iqs62x_dev_init(struct iqs62x_core *iqs62x)109{110	struct iqs62x_fw_blk *fw_blk;111	unsigned int val;112	int ret;113 114	list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {115		/*116		 * In case ATI is in progress, wait for it to complete before117		 * lowering the core clock frequency.118		 */119		if (fw_blk->addr == IQS62X_SYS_SETTINGS &&120		    *fw_blk->data & IQS62X_SYS_SETTINGS_CLK_DIV)121			msleep(IQS62X_ATI_STARTUP_MS);122 123		if (fw_blk->mask)124			ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr,125						 fw_blk->mask, *fw_blk->data);126		else127			ret = regmap_raw_write(iqs62x->regmap, fw_blk->addr,128					       fw_blk->data, fw_blk->len);129		if (ret)130			return ret;131	}132 133	switch (iqs62x->dev_desc->prod_num) {134	case IQS620_PROD_NUM:135	case IQS622_PROD_NUM:136		ret = regmap_read(iqs62x->regmap,137				  iqs62x->dev_desc->prox_settings, &val);138		if (ret)139			return ret;140 141		if (val & IQS620_PROX_SETTINGS_4_SAR_EN)142			iqs62x->ui_sel = IQS62X_UI_SAR1;143		fallthrough;144 145	case IQS621_PROD_NUM:146		ret = regmap_write(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,147				   IQS620_GLBL_EVENT_MASK_PMU |148				   iqs62x->dev_desc->prox_mask |149				   iqs62x->dev_desc->sar_mask |150				   iqs62x->dev_desc->hall_mask |151				   iqs62x->dev_desc->hyst_mask |152				   iqs62x->dev_desc->temp_mask |153				   iqs62x->dev_desc->als_mask |154				   iqs62x->dev_desc->ir_mask);155		if (ret)156			return ret;157		break;158 159	default:160		ret = regmap_write(iqs62x->regmap, IQS624_HALL_UI,161				   IQS624_HALL_UI_WHL_EVENT |162				   IQS624_HALL_UI_INT_EVENT |163				   IQS624_HALL_UI_AUTO_CAL);164		if (ret)165			return ret;166 167		/*168		 * The IQS625 default interval divider is below the minimum169		 * permissible value, and the datasheet mandates that it is170		 * corrected during initialization (unless an updated value171		 * has already been provided by firmware).172		 *173		 * To protect against an unacceptably low user-entered value174		 * stored in the firmware, the same check is extended to the175		 * IQS624 as well.176		 */177		ret = regmap_read(iqs62x->regmap, IQS624_INTERVAL_DIV, &val);178		if (ret)179			return ret;180 181		if (val >= iqs62x->dev_desc->interval_div)182			break;183 184		ret = regmap_write(iqs62x->regmap, IQS624_INTERVAL_DIV,185				   iqs62x->dev_desc->interval_div);186		if (ret)187			return ret;188	}189 190	/*191	 * Place the device in streaming mode at first so as not to miss the192	 * limited number of interrupts that would otherwise occur after ATI193	 * completes. The device is subsequently placed in event mode by the194	 * interrupt handler.195	 *196	 * In the meantime, mask interrupts during ATI to prevent the device197	 * from soliciting I2C traffic until the noise-sensitive ATI process198	 * is complete.199	 */200	ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,201				 IQS62X_SYS_SETTINGS_ACK_RESET |202				 IQS62X_SYS_SETTINGS_EVENT_MODE |203				 IQS62X_SYS_SETTINGS_COMM_ATI |204				 IQS62X_SYS_SETTINGS_REDO_ATI,205				 IQS62X_SYS_SETTINGS_ACK_RESET |206				 IQS62X_SYS_SETTINGS_REDO_ATI);207	if (ret)208		return ret;209 210	/*211	 * The following delay gives the device time to deassert its RDY output212	 * in case a communication window was open while the REDO_ATI field was213	 * written. This prevents an interrupt from being serviced prematurely.214	 */215	usleep_range(5000, 5100);216 217	return 0;218}219 220static int iqs62x_firmware_parse(struct iqs62x_core *iqs62x,221				 const struct firmware *fw)222{223	struct i2c_client *client = iqs62x->client;224	struct iqs62x_fw_rec *fw_rec;225	struct iqs62x_fw_blk *fw_blk;226	unsigned int val;227	size_t pos = 0;228	int ret = 0;229	u8 mask, len, *data;230	u8 hall_cal_index = 0;231 232	while (pos < fw->size) {233		if (pos + sizeof(*fw_rec) > fw->size) {234			ret = -EINVAL;235			break;236		}237		fw_rec = (struct iqs62x_fw_rec *)(fw->data + pos);238		pos += sizeof(*fw_rec);239 240		if (pos + fw_rec->len - 1 > fw->size) {241			ret = -EINVAL;242			break;243		}244		pos += fw_rec->len - 1;245 246		switch (fw_rec->type) {247		case IQS62X_FW_REC_TYPE_INFO:248			continue;249 250		case IQS62X_FW_REC_TYPE_PROD:251			if (fw_rec->data == iqs62x->dev_desc->prod_num)252				continue;253 254			dev_err(&client->dev,255				"Incompatible product number: 0x%02X\n",256				fw_rec->data);257			ret = -EINVAL;258			break;259 260		case IQS62X_FW_REC_TYPE_HALL:261			if (!hall_cal_index) {262				ret = regmap_write(iqs62x->regmap,263						   IQS62X_OTP_CMD,264						   IQS62X_OTP_CMD_FG3);265				if (ret)266					break;267 268				ret = regmap_read(iqs62x->regmap,269						  IQS62X_OTP_DATA, &val);270				if (ret)271					break;272 273				hall_cal_index = val & IQS62X_HALL_CAL_MASK;274				if (!hall_cal_index) {275					dev_err(&client->dev,276						"Uncalibrated device\n");277					ret = -ENODATA;278					break;279				}280			}281 282			if (hall_cal_index > fw_rec->len) {283				ret = -EINVAL;284				break;285			}286 287			mask = 0;288			data = &fw_rec->data + hall_cal_index - 1;289			len = sizeof(*data);290			break;291 292		case IQS62X_FW_REC_TYPE_MASK:293			if (fw_rec->len < (sizeof(mask) + sizeof(*data))) {294				ret = -EINVAL;295				break;296			}297 298			mask = fw_rec->data;299			data = &fw_rec->data + sizeof(mask);300			len = sizeof(*data);301			break;302 303		case IQS62X_FW_REC_TYPE_DATA:304			mask = 0;305			data = &fw_rec->data;306			len = fw_rec->len;307			break;308 309		default:310			dev_err(&client->dev,311				"Unrecognized record type: 0x%02X\n",312				fw_rec->type);313			ret = -EINVAL;314		}315 316		if (ret)317			break;318 319		fw_blk = devm_kzalloc(&client->dev,320				      struct_size(fw_blk, data, len),321				      GFP_KERNEL);322		if (!fw_blk) {323			ret = -ENOMEM;324			break;325		}326 327		fw_blk->addr = fw_rec->addr;328		fw_blk->mask = mask;329		fw_blk->len = len;330		memcpy(fw_blk->data, data, len);331 332		list_add(&fw_blk->list, &iqs62x->fw_blk_head);333	}334 335	release_firmware(fw);336 337	return ret;338}339 340const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = {341	[IQS62X_EVENT_PROX_CH0_T] = {342		.reg	= IQS62X_EVENT_PROX,343		.mask	= BIT(4),344		.val	= BIT(4),345	},346	[IQS62X_EVENT_PROX_CH0_P] = {347		.reg	= IQS62X_EVENT_PROX,348		.mask	= BIT(0),349		.val	= BIT(0),350	},351	[IQS62X_EVENT_PROX_CH1_T] = {352		.reg	= IQS62X_EVENT_PROX,353		.mask	= BIT(5),354		.val	= BIT(5),355	},356	[IQS62X_EVENT_PROX_CH1_P] = {357		.reg	= IQS62X_EVENT_PROX,358		.mask	= BIT(1),359		.val	= BIT(1),360	},361	[IQS62X_EVENT_PROX_CH2_T] = {362		.reg	= IQS62X_EVENT_PROX,363		.mask	= BIT(6),364		.val	= BIT(6),365	},366	[IQS62X_EVENT_PROX_CH2_P] = {367		.reg	= IQS62X_EVENT_PROX,368		.mask	= BIT(2),369		.val	= BIT(2),370	},371	[IQS62X_EVENT_HYST_POS_T] = {372		.reg	= IQS62X_EVENT_HYST,373		.mask	= BIT(6) | BIT(7),374		.val	= BIT(6),375	},376	[IQS62X_EVENT_HYST_POS_P] = {377		.reg	= IQS62X_EVENT_HYST,378		.mask	= BIT(5) | BIT(7),379		.val	= BIT(5),380	},381	[IQS62X_EVENT_HYST_NEG_T] = {382		.reg	= IQS62X_EVENT_HYST,383		.mask	= BIT(6) | BIT(7),384		.val	= BIT(6) | BIT(7),385	},386	[IQS62X_EVENT_HYST_NEG_P] = {387		.reg	= IQS62X_EVENT_HYST,388		.mask	= BIT(5) | BIT(7),389		.val	= BIT(5) | BIT(7),390	},391	[IQS62X_EVENT_SAR1_ACT] = {392		.reg	= IQS62X_EVENT_HYST,393		.mask	= BIT(4),394		.val	= BIT(4),395	},396	[IQS62X_EVENT_SAR1_QRD] = {397		.reg	= IQS62X_EVENT_HYST,398		.mask	= BIT(2),399		.val	= BIT(2),400	},401	[IQS62X_EVENT_SAR1_MOVE] = {402		.reg	= IQS62X_EVENT_HYST,403		.mask	= BIT(1),404		.val	= BIT(1),405	},406	[IQS62X_EVENT_SAR1_HALT] = {407		.reg	= IQS62X_EVENT_HYST,408		.mask	= BIT(0),409		.val	= BIT(0),410	},411	[IQS62X_EVENT_WHEEL_UP] = {412		.reg	= IQS62X_EVENT_WHEEL,413		.mask	= BIT(7) | BIT(6),414		.val	= BIT(7),415	},416	[IQS62X_EVENT_WHEEL_DN] = {417		.reg	= IQS62X_EVENT_WHEEL,418		.mask	= BIT(7) | BIT(6),419		.val	= BIT(7) | BIT(6),420	},421	[IQS62X_EVENT_HALL_N_T] = {422		.reg	= IQS62X_EVENT_HALL,423		.mask	= BIT(2) | BIT(0),424		.val	= BIT(2),425	},426	[IQS62X_EVENT_HALL_N_P] = {427		.reg	= IQS62X_EVENT_HALL,428		.mask	= BIT(1) | BIT(0),429		.val	= BIT(1),430	},431	[IQS62X_EVENT_HALL_S_T] = {432		.reg	= IQS62X_EVENT_HALL,433		.mask	= BIT(2) | BIT(0),434		.val	= BIT(2) | BIT(0),435	},436	[IQS62X_EVENT_HALL_S_P] = {437		.reg	= IQS62X_EVENT_HALL,438		.mask	= BIT(1) | BIT(0),439		.val	= BIT(1) | BIT(0),440	},441	[IQS62X_EVENT_SYS_RESET] = {442		.reg	= IQS62X_EVENT_SYS,443		.mask	= BIT(7),444		.val	= BIT(7),445	},446	[IQS62X_EVENT_SYS_ATI] = {447		.reg	= IQS62X_EVENT_SYS,448		.mask	= BIT(2),449		.val	= BIT(2),450	},451};452EXPORT_SYMBOL_GPL(iqs62x_events);453 454static irqreturn_t iqs62x_irq(int irq, void *context)455{456	struct iqs62x_core *iqs62x = context;457	struct i2c_client *client = iqs62x->client;458	struct iqs62x_event_data event_data;459	struct iqs62x_event_desc event_desc;460	enum iqs62x_event_reg event_reg;461	unsigned long event_flags = 0;462	int ret, i, j;463	u8 event_map[IQS62X_EVENT_SIZE];464 465	/*466	 * The device asserts the RDY output to signal the beginning of a467	 * communication window, which is closed by an I2C stop condition.468	 * As such, all interrupt status is captured in a single read and469	 * broadcast to any interested sub-device drivers.470	 */471	ret = regmap_raw_read(iqs62x->regmap, IQS62X_SYS_FLAGS, event_map,472			      sizeof(event_map));473	if (ret) {474		dev_err(&client->dev, "Failed to read device status: %d\n",475			ret);476		return IRQ_NONE;477	}478 479	for (i = 0; i < sizeof(event_map); i++) {480		event_reg = iqs62x->dev_desc->event_regs[iqs62x->ui_sel][i];481 482		switch (event_reg) {483		case IQS62X_EVENT_UI_LO:484			event_data.ui_data = get_unaligned_le16(&event_map[i]);485			fallthrough;486 487		case IQS62X_EVENT_UI_HI:488		case IQS62X_EVENT_NONE:489			continue;490 491		case IQS62X_EVENT_ALS:492			event_data.als_flags = event_map[i];493			continue;494 495		case IQS62X_EVENT_IR:496			event_data.ir_flags = event_map[i];497			continue;498 499		case IQS62X_EVENT_INTER:500			event_data.interval = event_map[i];501			continue;502 503		case IQS62X_EVENT_HYST:504			event_map[i] <<= iqs62x->dev_desc->hyst_shift;505			fallthrough;506 507		case IQS62X_EVENT_WHEEL:508		case IQS62X_EVENT_HALL:509		case IQS62X_EVENT_PROX:510		case IQS62X_EVENT_SYS:511			break;512		}513 514		for (j = 0; j < IQS62X_NUM_EVENTS; j++) {515			event_desc = iqs62x_events[j];516 517			if (event_desc.reg != event_reg)518				continue;519 520			if ((event_map[i] & event_desc.mask) == event_desc.val)521				event_flags |= BIT(j);522		}523	}524 525	/*526	 * The device resets itself in response to the I2C master stalling527	 * communication past a fixed timeout. In this case, all registers528	 * are restored and any interested sub-device drivers are notified.529	 */530	if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {531		dev_err(&client->dev, "Unexpected device reset\n");532 533		ret = iqs62x_dev_init(iqs62x);534		if (ret) {535			dev_err(&client->dev,536				"Failed to re-initialize device: %d\n", ret);537			return IRQ_NONE;538		}539 540		iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_RESET);541		reinit_completion(&iqs62x->ati_done);542	} else if (event_flags & BIT(IQS62X_EVENT_SYS_ATI)) {543		iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_ATI);544		reinit_completion(&iqs62x->ati_done);545	} else if (!completion_done(&iqs62x->ati_done)) {546		ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,547					 IQS62X_SYS_SETTINGS_EVENT_MODE, 0xFF);548		if (ret) {549			dev_err(&client->dev,550				"Failed to enable event mode: %d\n", ret);551			return IRQ_NONE;552		}553 554		msleep(IQS62X_FILT_SETTLE_MS);555		complete_all(&iqs62x->ati_done);556	}557 558	/*559	 * Reset and ATI events are not broadcast to the sub-device drivers560	 * until ATI has completed. Any other events that may have occurred561	 * during ATI are ignored.562	 */563	if (completion_done(&iqs62x->ati_done)) {564		event_flags |= iqs62x->event_cache;565		ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,566						   &event_data);567		if (ret & NOTIFY_STOP_MASK)568			return IRQ_NONE;569 570		iqs62x->event_cache = 0;571	}572 573	/*574	 * Once the communication window is closed, a small delay is added to575	 * ensure the device's RDY output has been deasserted by the time the576	 * interrupt handler returns.577	 */578	usleep_range(150, 200);579 580	return IRQ_HANDLED;581}582 583static void iqs62x_firmware_load(const struct firmware *fw, void *context)584{585	struct iqs62x_core *iqs62x = context;586	struct i2c_client *client = iqs62x->client;587	int ret;588 589	if (fw) {590		ret = iqs62x_firmware_parse(iqs62x, fw);591		if (ret) {592			dev_err(&client->dev, "Failed to parse firmware: %d\n",593				ret);594			goto err_out;595		}596	}597 598	ret = iqs62x_dev_init(iqs62x);599	if (ret) {600		dev_err(&client->dev, "Failed to initialize device: %d\n", ret);601		goto err_out;602	}603 604	ret = devm_request_threaded_irq(&client->dev, client->irq,605					NULL, iqs62x_irq, IRQF_ONESHOT,606					client->name, iqs62x);607	if (ret) {608		dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);609		goto err_out;610	}611 612	if (!wait_for_completion_timeout(&iqs62x->ati_done,613					 msecs_to_jiffies(2000))) {614		dev_err(&client->dev, "Failed to complete ATI\n");615		goto err_out;616	}617 618	ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,619				   iqs62x->dev_desc->sub_devs,620				   iqs62x->dev_desc->num_sub_devs,621				   NULL, 0, NULL);622	if (ret)623		dev_err(&client->dev, "Failed to add sub-devices: %d\n", ret);624 625err_out:626	complete_all(&iqs62x->fw_done);627}628 629static const struct mfd_cell iqs620at_sub_devs[] = {630	{631		.name = "iqs62x-keys",632		.of_compatible = "azoteq,iqs620a-keys",633	},634	{635		.name = "iqs620a-pwm",636		.of_compatible = "azoteq,iqs620a-pwm",637	},638	{ .name = "iqs620at-temp", },639};640 641static const struct mfd_cell iqs620a_sub_devs[] = {642	{643		.name = "iqs62x-keys",644		.of_compatible = "azoteq,iqs620a-keys",645	},646	{647		.name = "iqs620a-pwm",648		.of_compatible = "azoteq,iqs620a-pwm",649	},650};651 652static const struct mfd_cell iqs621_sub_devs[] = {653	{654		.name = "iqs62x-keys",655		.of_compatible = "azoteq,iqs621-keys",656	},657	{ .name = "iqs621-als", },658};659 660static const struct mfd_cell iqs622_sub_devs[] = {661	{662		.name = "iqs62x-keys",663		.of_compatible = "azoteq,iqs622-keys",664	},665	{ .name = "iqs621-als", },666};667 668static const struct mfd_cell iqs624_sub_devs[] = {669	{670		.name = "iqs62x-keys",671		.of_compatible = "azoteq,iqs624-keys",672	},673	{ .name = "iqs624-pos", },674};675 676static const struct mfd_cell iqs625_sub_devs[] = {677	{678		.name = "iqs62x-keys",679		.of_compatible = "azoteq,iqs625-keys",680	},681	{ .name = "iqs624-pos", },682};683 684static const u8 iqs620at_cal_regs[] = {685	IQS620_TEMP_CAL_MULT,686	IQS620_TEMP_CAL_DIV,687	IQS620_TEMP_CAL_OFFS,688};689 690static const u8 iqs621_cal_regs[] = {691	IQS621_ALS_CAL_DIV_LUX,692	IQS621_ALS_CAL_DIV_IR,693};694 695static const enum iqs62x_event_reg iqs620a_event_regs[][IQS62X_EVENT_SIZE] = {696	[IQS62X_UI_PROX] = {697		IQS62X_EVENT_SYS,	/* 0x10 */698		IQS62X_EVENT_NONE,699		IQS62X_EVENT_PROX,	/* 0x12 */700		IQS62X_EVENT_HYST,	/* 0x13 */701		IQS62X_EVENT_NONE,702		IQS62X_EVENT_NONE,703		IQS62X_EVENT_HALL,	/* 0x16 */704		IQS62X_EVENT_NONE,705		IQS62X_EVENT_NONE,706		IQS62X_EVENT_NONE,707	},708	[IQS62X_UI_SAR1] = {709		IQS62X_EVENT_SYS,	/* 0x10 */710		IQS62X_EVENT_NONE,711		IQS62X_EVENT_NONE,712		IQS62X_EVENT_HYST,	/* 0x13 */713		IQS62X_EVENT_NONE,714		IQS62X_EVENT_NONE,715		IQS62X_EVENT_HALL,	/* 0x16 */716		IQS62X_EVENT_NONE,717		IQS62X_EVENT_NONE,718		IQS62X_EVENT_NONE,719	},720};721 722static const enum iqs62x_event_reg iqs621_event_regs[][IQS62X_EVENT_SIZE] = {723	[IQS62X_UI_PROX] = {724		IQS62X_EVENT_SYS,	/* 0x10 */725		IQS62X_EVENT_NONE,726		IQS62X_EVENT_PROX,	/* 0x12 */727		IQS62X_EVENT_HYST,	/* 0x13 */728		IQS62X_EVENT_NONE,729		IQS62X_EVENT_NONE,730		IQS62X_EVENT_ALS,	/* 0x16 */731		IQS62X_EVENT_UI_LO,	/* 0x17 */732		IQS62X_EVENT_UI_HI,	/* 0x18 */733		IQS62X_EVENT_HALL,	/* 0x19 */734	},735};736 737static const enum iqs62x_event_reg iqs622_event_regs[][IQS62X_EVENT_SIZE] = {738	[IQS62X_UI_PROX] = {739		IQS62X_EVENT_SYS,	/* 0x10 */740		IQS62X_EVENT_NONE,741		IQS62X_EVENT_PROX,	/* 0x12 */742		IQS62X_EVENT_NONE,743		IQS62X_EVENT_ALS,	/* 0x14 */744		IQS62X_EVENT_NONE,745		IQS62X_EVENT_IR,	/* 0x16 */746		IQS62X_EVENT_UI_LO,	/* 0x17 */747		IQS62X_EVENT_UI_HI,	/* 0x18 */748		IQS62X_EVENT_HALL,	/* 0x19 */749	},750	[IQS62X_UI_SAR1] = {751		IQS62X_EVENT_SYS,	/* 0x10 */752		IQS62X_EVENT_NONE,753		IQS62X_EVENT_NONE,754		IQS62X_EVENT_HYST,	/* 0x13 */755		IQS62X_EVENT_ALS,	/* 0x14 */756		IQS62X_EVENT_NONE,757		IQS62X_EVENT_IR,	/* 0x16 */758		IQS62X_EVENT_UI_LO,	/* 0x17 */759		IQS62X_EVENT_UI_HI,	/* 0x18 */760		IQS62X_EVENT_HALL,	/* 0x19 */761	},762};763 764static const enum iqs62x_event_reg iqs624_event_regs[][IQS62X_EVENT_SIZE] = {765	[IQS62X_UI_PROX] = {766		IQS62X_EVENT_SYS,	/* 0x10 */767		IQS62X_EVENT_NONE,768		IQS62X_EVENT_PROX,	/* 0x12 */769		IQS62X_EVENT_NONE,770		IQS62X_EVENT_WHEEL,	/* 0x14 */771		IQS62X_EVENT_NONE,772		IQS62X_EVENT_UI_LO,	/* 0x16 */773		IQS62X_EVENT_UI_HI,	/* 0x17 */774		IQS62X_EVENT_INTER,	/* 0x18 */775		IQS62X_EVENT_NONE,776	},777};778 779static const enum iqs62x_event_reg iqs625_event_regs[][IQS62X_EVENT_SIZE] = {780	[IQS62X_UI_PROX] = {781		IQS62X_EVENT_SYS,	/* 0x10 */782		IQS62X_EVENT_PROX,	/* 0x11 */783		IQS62X_EVENT_INTER,	/* 0x12 */784		IQS62X_EVENT_NONE,785		IQS62X_EVENT_NONE,786		IQS62X_EVENT_NONE,787		IQS62X_EVENT_NONE,788		IQS62X_EVENT_NONE,789		IQS62X_EVENT_NONE,790		IQS62X_EVENT_NONE,791	},792};793 794static const struct iqs62x_dev_desc iqs62x_devs[] = {795	{796		.dev_name	= "iqs620at",797		.sub_devs	= iqs620at_sub_devs,798		.num_sub_devs	= ARRAY_SIZE(iqs620at_sub_devs),799		.prod_num	= IQS620_PROD_NUM,800		.sw_num		= 0x08,801		.cal_regs	= iqs620at_cal_regs,802		.num_cal_regs	= ARRAY_SIZE(iqs620at_cal_regs),803		.prox_mask	= BIT(0),804		.sar_mask	= BIT(1) | BIT(7),805		.hall_mask	= BIT(2),806		.hyst_mask	= BIT(3),807		.temp_mask	= BIT(4),808		.prox_settings	= IQS620_PROX_SETTINGS_4,809		.hall_flags	= IQS620_HALL_FLAGS,810		.fw_name	= "iqs620a.bin",811		.event_regs	= &iqs620a_event_regs[IQS62X_UI_PROX],812	},813	{814		.dev_name	= "iqs620a",815		.sub_devs	= iqs620a_sub_devs,816		.num_sub_devs	= ARRAY_SIZE(iqs620a_sub_devs),817		.prod_num	= IQS620_PROD_NUM,818		.sw_num		= 0x08,819		.prox_mask	= BIT(0),820		.sar_mask	= BIT(1) | BIT(7),821		.hall_mask	= BIT(2),822		.hyst_mask	= BIT(3),823		.temp_mask	= BIT(4),824		.prox_settings	= IQS620_PROX_SETTINGS_4,825		.hall_flags	= IQS620_HALL_FLAGS,826		.fw_name	= "iqs620a.bin",827		.event_regs	= &iqs620a_event_regs[IQS62X_UI_PROX],828	},829	{830		.dev_name	= "iqs621",831		.sub_devs	= iqs621_sub_devs,832		.num_sub_devs	= ARRAY_SIZE(iqs621_sub_devs),833		.prod_num	= IQS621_PROD_NUM,834		.sw_num		= 0x09,835		.cal_regs	= iqs621_cal_regs,836		.num_cal_regs	= ARRAY_SIZE(iqs621_cal_regs),837		.prox_mask	= BIT(0),838		.hall_mask	= BIT(1),839		.als_mask	= BIT(2),840		.hyst_mask	= BIT(3),841		.temp_mask	= BIT(4),842		.als_flags	= IQS621_ALS_FLAGS,843		.hall_flags	= IQS621_HALL_FLAGS,844		.hyst_shift	= 5,845		.fw_name	= "iqs621.bin",846		.event_regs	= &iqs621_event_regs[IQS62X_UI_PROX],847	},848	{849		.dev_name	= "iqs622",850		.sub_devs	= iqs622_sub_devs,851		.num_sub_devs	= ARRAY_SIZE(iqs622_sub_devs),852		.prod_num	= IQS622_PROD_NUM,853		.sw_num		= 0x06,854		.prox_mask	= BIT(0),855		.sar_mask	= BIT(1),856		.hall_mask	= BIT(2),857		.als_mask	= BIT(3),858		.ir_mask	= BIT(4),859		.prox_settings	= IQS622_PROX_SETTINGS_4,860		.als_flags	= IQS622_ALS_FLAGS,861		.hall_flags	= IQS622_HALL_FLAGS,862		.fw_name	= "iqs622.bin",863		.event_regs	= &iqs622_event_regs[IQS62X_UI_PROX],864	},865	{866		.dev_name	= "iqs624",867		.sub_devs	= iqs624_sub_devs,868		.num_sub_devs	= ARRAY_SIZE(iqs624_sub_devs),869		.prod_num	= IQS624_PROD_NUM,870		.sw_num		= 0x0B,871		.interval	= IQS624_INTERVAL_NUM,872		.interval_div	= 3,873		.fw_name	= "iqs624.bin",874		.event_regs	= &iqs624_event_regs[IQS62X_UI_PROX],875	},876	{877		.dev_name	= "iqs625",878		.sub_devs	= iqs625_sub_devs,879		.num_sub_devs	= ARRAY_SIZE(iqs625_sub_devs),880		.prod_num	= IQS625_PROD_NUM,881		.sw_num		= 0x0B,882		.interval	= IQS625_INTERVAL_NUM,883		.interval_div	= 10,884		.fw_name	= "iqs625.bin",885		.event_regs	= &iqs625_event_regs[IQS62X_UI_PROX],886	},887};888 889static const struct regmap_config iqs62x_regmap_config = {890	.reg_bits = 8,891	.val_bits = 8,892	.max_register = IQS62X_MAX_REG,893};894 895static int iqs62x_probe(struct i2c_client *client)896{897	struct iqs62x_core *iqs62x;898	struct iqs62x_info info;899	unsigned int val;900	int ret, i, j;901	const char *fw_name = NULL;902 903	iqs62x = devm_kzalloc(&client->dev, sizeof(*iqs62x), GFP_KERNEL);904	if (!iqs62x)905		return -ENOMEM;906 907	i2c_set_clientdata(client, iqs62x);908	iqs62x->client = client;909 910	BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);911	INIT_LIST_HEAD(&iqs62x->fw_blk_head);912 913	init_completion(&iqs62x->ati_done);914	init_completion(&iqs62x->fw_done);915 916	iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config);917	if (IS_ERR(iqs62x->regmap)) {918		ret = PTR_ERR(iqs62x->regmap);919		dev_err(&client->dev, "Failed to initialize register map: %d\n",920			ret);921		return ret;922	}923 924	ret = regmap_raw_read(iqs62x->regmap, IQS62X_PROD_NUM, &info,925			      sizeof(info));926	if (ret)927		return ret;928 929	/*930	 * The following sequence validates the device's product and software931	 * numbers. It then determines if the device is factory-calibrated by932	 * checking for nonzero values in the device's designated calibration933	 * registers (if applicable). Depending on the device, the absence of934	 * calibration data indicates a reduced feature set or invalid device.935	 *936	 * For devices given in both calibrated and uncalibrated versions, the937	 * calibrated version (e.g. IQS620AT) appears first in the iqs62x_devs938	 * array. The uncalibrated version (e.g. IQS620A) appears next and has939	 * the same product and software numbers, but no calibration registers940	 * are specified.941	 */942	for (i = 0; i < ARRAY_SIZE(iqs62x_devs); i++) {943		if (info.prod_num != iqs62x_devs[i].prod_num)944			continue;945 946		iqs62x->dev_desc = &iqs62x_devs[i];947 948		if (info.sw_num < iqs62x->dev_desc->sw_num)949			continue;950 951		iqs62x->sw_num = info.sw_num;952		iqs62x->hw_num = info.hw_num;953 954		/*955		 * Read each of the device's designated calibration registers,956		 * if any, and exit from the inner loop early if any are equal957		 * to zero (indicating the device is uncalibrated). This could958		 * be acceptable depending on the device (e.g. IQS620A instead959		 * of IQS620AT).960		 */961		for (j = 0; j < iqs62x->dev_desc->num_cal_regs; j++) {962			ret = regmap_read(iqs62x->regmap,963					  iqs62x->dev_desc->cal_regs[j], &val);964			if (ret)965				return ret;966 967			if (!val)968				break;969		}970 971		/*972		 * If the number of nonzero values read from the device equals973		 * the number of designated calibration registers (which could974		 * be zero), exit from the outer loop early to signal that the975		 * device's product and software numbers match a known device,976		 * and the device is calibrated (if applicable).977		 */978		if (j == iqs62x->dev_desc->num_cal_regs)979			break;980	}981 982	if (!iqs62x->dev_desc) {983		dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",984			info.prod_num);985		return -EINVAL;986	}987 988	if (!iqs62x->sw_num) {989		dev_err(&client->dev, "Unrecognized software number: 0x%02X\n",990			info.sw_num);991		return -EINVAL;992	}993 994	if (i == ARRAY_SIZE(iqs62x_devs)) {995		dev_err(&client->dev, "Uncalibrated device\n");996		return -ENODATA;997	}998 999	device_property_read_string(&client->dev, "firmware-name", &fw_name);1000 1001	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,1002				      fw_name ? : iqs62x->dev_desc->fw_name,1003				      &client->dev, GFP_KERNEL, iqs62x,1004				      iqs62x_firmware_load);1005	if (ret)1006		dev_err(&client->dev, "Failed to request firmware: %d\n", ret);1007 1008	return ret;1009}1010 1011static void iqs62x_remove(struct i2c_client *client)1012{1013	struct iqs62x_core *iqs62x = i2c_get_clientdata(client);1014 1015	wait_for_completion(&iqs62x->fw_done);1016}1017 1018static int __maybe_unused iqs62x_suspend(struct device *dev)1019{1020	struct iqs62x_core *iqs62x = dev_get_drvdata(dev);1021	int ret;1022 1023	wait_for_completion(&iqs62x->fw_done);1024 1025	/*1026	 * As per the datasheet, automatic mode switching must be disabled1027	 * before the device is placed in or taken out of halt mode.1028	 */1029	ret = regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,1030				 IQS62X_PWR_SETTINGS_DIS_AUTO, 0xFF);1031	if (ret)1032		return ret;1033 1034	return regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,1035				  IQS62X_PWR_SETTINGS_PWR_MODE_MASK,1036				  IQS62X_PWR_SETTINGS_PWR_MODE_HALT);1037}1038 1039static int __maybe_unused iqs62x_resume(struct device *dev)1040{1041	struct iqs62x_core *iqs62x = dev_get_drvdata(dev);1042	int ret;1043 1044	ret = regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,1045				 IQS62X_PWR_SETTINGS_PWR_MODE_MASK,1046				 IQS62X_PWR_SETTINGS_PWR_MODE_NORM);1047	if (ret)1048		return ret;1049 1050	return regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,1051				  IQS62X_PWR_SETTINGS_DIS_AUTO, 0);1052}1053 1054static SIMPLE_DEV_PM_OPS(iqs62x_pm, iqs62x_suspend, iqs62x_resume);1055 1056static const struct of_device_id iqs62x_of_match[] = {1057	{ .compatible = "azoteq,iqs620a" },1058	{ .compatible = "azoteq,iqs621" },1059	{ .compatible = "azoteq,iqs622" },1060	{ .compatible = "azoteq,iqs624" },1061	{ .compatible = "azoteq,iqs625" },1062	{ }1063};1064MODULE_DEVICE_TABLE(of, iqs62x_of_match);1065 1066static struct i2c_driver iqs62x_i2c_driver = {1067	.driver = {1068		.name = "iqs62x",1069		.of_match_table = iqs62x_of_match,1070		.pm = &iqs62x_pm,1071	},1072	.probe = iqs62x_probe,1073	.remove = iqs62x_remove,1074};1075module_i2c_driver(iqs62x_i2c_driver);1076 1077MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");1078MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Multi-Function Sensors");1079MODULE_LICENSE("GPL");1080