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