18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 InvenSense, Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Driver for InvenSense ICP-1010xx barometric pressure and temperature sensor. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Datasheet: 88c2ecf20Sopenharmony_ci * http://www.invensense.com/wp-content/uploads/2018/01/DS-000186-ICP-101xx-v1.2.pdf 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci#include <linux/crc8.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/log2.h> 208c2ecf20Sopenharmony_ci#include <linux/math64.h> 218c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 228c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define ICP10100_ID_REG_GET(_reg) ((_reg) & 0x003F) 258c2ecf20Sopenharmony_ci#define ICP10100_ID_REG 0x08 268c2ecf20Sopenharmony_ci#define ICP10100_RESPONSE_WORD_LENGTH 3 278c2ecf20Sopenharmony_ci#define ICP10100_CRC8_WORD_LENGTH 2 288c2ecf20Sopenharmony_ci#define ICP10100_CRC8_POLYNOMIAL 0x31 298c2ecf20Sopenharmony_ci#define ICP10100_CRC8_INIT 0xFF 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cienum icp10100_mode { 328c2ecf20Sopenharmony_ci ICP10100_MODE_LP, /* Low power mode: 1x sampling */ 338c2ecf20Sopenharmony_ci ICP10100_MODE_N, /* Normal mode: 2x sampling */ 348c2ecf20Sopenharmony_ci ICP10100_MODE_LN, /* Low noise mode: 4x sampling */ 358c2ecf20Sopenharmony_ci ICP10100_MODE_ULN, /* Ultra low noise mode: 8x sampling */ 368c2ecf20Sopenharmony_ci ICP10100_MODE_NB, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct icp10100_state { 408c2ecf20Sopenharmony_ci struct mutex lock; 418c2ecf20Sopenharmony_ci struct i2c_client *client; 428c2ecf20Sopenharmony_ci struct regulator *vdd; 438c2ecf20Sopenharmony_ci enum icp10100_mode mode; 448c2ecf20Sopenharmony_ci int16_t cal[4]; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct icp10100_command { 488c2ecf20Sopenharmony_ci __be16 cmd; 498c2ecf20Sopenharmony_ci unsigned long wait_us; 508c2ecf20Sopenharmony_ci unsigned long wait_max_us; 518c2ecf20Sopenharmony_ci size_t response_word_nb; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_soft_reset = { 558c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0x805D), 568c2ecf20Sopenharmony_ci .wait_us = 170, 578c2ecf20Sopenharmony_ci .wait_max_us = 200, 588c2ecf20Sopenharmony_ci .response_word_nb = 0, 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_read_id = { 628c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0xEFC8), 638c2ecf20Sopenharmony_ci .wait_us = 0, 648c2ecf20Sopenharmony_ci .response_word_nb = 1, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_read_otp = { 688c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0xC7F7), 698c2ecf20Sopenharmony_ci .wait_us = 0, 708c2ecf20Sopenharmony_ci .response_word_nb = 1, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct icp10100_command icp10100_cmd_measure[] = { 748c2ecf20Sopenharmony_ci [ICP10100_MODE_LP] = { 758c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0x401A), 768c2ecf20Sopenharmony_ci .wait_us = 1800, 778c2ecf20Sopenharmony_ci .wait_max_us = 2000, 788c2ecf20Sopenharmony_ci .response_word_nb = 3, 798c2ecf20Sopenharmony_ci }, 808c2ecf20Sopenharmony_ci [ICP10100_MODE_N] = { 818c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0x48A3), 828c2ecf20Sopenharmony_ci .wait_us = 6300, 838c2ecf20Sopenharmony_ci .wait_max_us = 6500, 848c2ecf20Sopenharmony_ci .response_word_nb = 3, 858c2ecf20Sopenharmony_ci }, 868c2ecf20Sopenharmony_ci [ICP10100_MODE_LN] = { 878c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0x5059), 888c2ecf20Sopenharmony_ci .wait_us = 23800, 898c2ecf20Sopenharmony_ci .wait_max_us = 24000, 908c2ecf20Sopenharmony_ci .response_word_nb = 3, 918c2ecf20Sopenharmony_ci }, 928c2ecf20Sopenharmony_ci [ICP10100_MODE_ULN] = { 938c2ecf20Sopenharmony_ci .cmd = cpu_to_be16(0x58E0), 948c2ecf20Sopenharmony_ci .wait_us = 94500, 958c2ecf20Sopenharmony_ci .wait_max_us = 94700, 968c2ecf20Sopenharmony_ci .response_word_nb = 3, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic const uint8_t icp10100_switch_mode_otp[] = 1018c2ecf20Sopenharmony_ci {0xC5, 0x95, 0x00, 0x66, 0x9c}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciDECLARE_CRC8_TABLE(icp10100_crc8_table); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic inline int icp10100_i2c_xfer(struct i2c_adapter *adap, 1068c2ecf20Sopenharmony_ci struct i2c_msg *msgs, int num) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ret = i2c_transfer(adap, msgs, num); 1118c2ecf20Sopenharmony_ci if (ret < 0) 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (ret != num) 1158c2ecf20Sopenharmony_ci return -EIO; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int icp10100_send_cmd(struct icp10100_state *st, 1218c2ecf20Sopenharmony_ci const struct icp10100_command *cmd, 1228c2ecf20Sopenharmony_ci __be16 *buf, size_t buf_len) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci size_t size = cmd->response_word_nb * ICP10100_RESPONSE_WORD_LENGTH; 1258c2ecf20Sopenharmony_ci uint8_t data[16]; 1268c2ecf20Sopenharmony_ci uint8_t *ptr; 1278c2ecf20Sopenharmony_ci uint8_t *buf_ptr = (uint8_t *)buf; 1288c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = { 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci .addr = st->client->addr, 1318c2ecf20Sopenharmony_ci .flags = 0, 1328c2ecf20Sopenharmony_ci .len = 2, 1338c2ecf20Sopenharmony_ci .buf = (uint8_t *)&cmd->cmd, 1348c2ecf20Sopenharmony_ci }, { 1358c2ecf20Sopenharmony_ci .addr = st->client->addr, 1368c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 1378c2ecf20Sopenharmony_ci .len = size, 1388c2ecf20Sopenharmony_ci .buf = data, 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci }; 1418c2ecf20Sopenharmony_ci uint8_t crc; 1428c2ecf20Sopenharmony_ci unsigned int i; 1438c2ecf20Sopenharmony_ci int ret; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (size > sizeof(data)) 1468c2ecf20Sopenharmony_ci return -EINVAL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (cmd->response_word_nb > 0 && 1498c2ecf20Sopenharmony_ci (buf == NULL || buf_len < (cmd->response_word_nb * 2))) 1508c2ecf20Sopenharmony_ci return -EINVAL; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "sending cmd %#x\n", be16_to_cpu(cmd->cmd)); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (cmd->response_word_nb > 0 && cmd->wait_us == 0) { 1558c2ecf20Sopenharmony_ci /* direct command-response without waiting */ 1568c2ecf20Sopenharmony_ci ret = icp10100_i2c_xfer(st->client->adapter, msgs, 1578c2ecf20Sopenharmony_ci ARRAY_SIZE(msgs)); 1588c2ecf20Sopenharmony_ci if (ret) 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci } else { 1618c2ecf20Sopenharmony_ci /* transfer command write */ 1628c2ecf20Sopenharmony_ci ret = icp10100_i2c_xfer(st->client->adapter, &msgs[0], 1); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci if (cmd->wait_us > 0) 1668c2ecf20Sopenharmony_ci usleep_range(cmd->wait_us, cmd->wait_max_us); 1678c2ecf20Sopenharmony_ci /* transfer response read if needed */ 1688c2ecf20Sopenharmony_ci if (cmd->response_word_nb > 0) { 1698c2ecf20Sopenharmony_ci ret = icp10100_i2c_xfer(st->client->adapter, &msgs[1], 1); 1708c2ecf20Sopenharmony_ci if (ret) 1718c2ecf20Sopenharmony_ci return ret; 1728c2ecf20Sopenharmony_ci } else { 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* process read words with crc checking */ 1788c2ecf20Sopenharmony_ci for (i = 0; i < cmd->response_word_nb; ++i) { 1798c2ecf20Sopenharmony_ci ptr = &data[i * ICP10100_RESPONSE_WORD_LENGTH]; 1808c2ecf20Sopenharmony_ci crc = crc8(icp10100_crc8_table, ptr, ICP10100_CRC8_WORD_LENGTH, 1818c2ecf20Sopenharmony_ci ICP10100_CRC8_INIT); 1828c2ecf20Sopenharmony_ci if (crc != ptr[ICP10100_CRC8_WORD_LENGTH]) { 1838c2ecf20Sopenharmony_ci dev_err(&st->client->dev, "crc error recv=%#x calc=%#x\n", 1848c2ecf20Sopenharmony_ci ptr[ICP10100_CRC8_WORD_LENGTH], crc); 1858c2ecf20Sopenharmony_ci return -EIO; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci *buf_ptr++ = ptr[0]; 1888c2ecf20Sopenharmony_ci *buf_ptr++ = ptr[1]; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int icp10100_read_cal_otp(struct icp10100_state *st) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci __be16 val; 1978c2ecf20Sopenharmony_ci int i; 1988c2ecf20Sopenharmony_ci int ret; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* switch into OTP read mode */ 2018c2ecf20Sopenharmony_ci ret = i2c_master_send(st->client, icp10100_switch_mode_otp, 2028c2ecf20Sopenharmony_ci ARRAY_SIZE(icp10100_switch_mode_otp)); 2038c2ecf20Sopenharmony_ci if (ret < 0) 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci if (ret != ARRAY_SIZE(icp10100_switch_mode_otp)) 2068c2ecf20Sopenharmony_ci return -EIO; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* read 4 calibration values */ 2098c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 2108c2ecf20Sopenharmony_ci ret = icp10100_send_cmd(st, &icp10100_cmd_read_otp, 2118c2ecf20Sopenharmony_ci &val, sizeof(val)); 2128c2ecf20Sopenharmony_ci if (ret) 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci st->cal[i] = be16_to_cpu(val); 2158c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "cal[%d] = %d\n", i, st->cal[i]); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int icp10100_init_chip(struct icp10100_state *st) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci __be16 val; 2248c2ecf20Sopenharmony_ci uint16_t id; 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* read and check id */ 2288c2ecf20Sopenharmony_ci ret = icp10100_send_cmd(st, &icp10100_cmd_read_id, &val, sizeof(val)); 2298c2ecf20Sopenharmony_ci if (ret) 2308c2ecf20Sopenharmony_ci return ret; 2318c2ecf20Sopenharmony_ci id = ICP10100_ID_REG_GET(be16_to_cpu(val)); 2328c2ecf20Sopenharmony_ci if (id != ICP10100_ID_REG) { 2338c2ecf20Sopenharmony_ci dev_err(&st->client->dev, "invalid id %#x\n", id); 2348c2ecf20Sopenharmony_ci return -ENODEV; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* read calibration data from OTP */ 2388c2ecf20Sopenharmony_ci ret = icp10100_read_cal_otp(st); 2398c2ecf20Sopenharmony_ci if (ret) 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* reset chip */ 2438c2ecf20Sopenharmony_ci return icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int icp10100_get_measures(struct icp10100_state *st, 2478c2ecf20Sopenharmony_ci uint32_t *pressure, uint16_t *temperature) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci const struct icp10100_command *cmd; 2508c2ecf20Sopenharmony_ci __be16 measures[3]; 2518c2ecf20Sopenharmony_ci int ret; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci pm_runtime_get_sync(&st->client->dev); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2568c2ecf20Sopenharmony_ci cmd = &icp10100_cmd_measure[st->mode]; 2578c2ecf20Sopenharmony_ci ret = icp10100_send_cmd(st, cmd, measures, sizeof(measures)); 2588c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2598c2ecf20Sopenharmony_ci if (ret) 2608c2ecf20Sopenharmony_ci goto error_measure; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci *pressure = (be16_to_cpu(measures[0]) << 8) | 2638c2ecf20Sopenharmony_ci (be16_to_cpu(measures[1]) >> 8); 2648c2ecf20Sopenharmony_ci *temperature = be16_to_cpu(measures[2]); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&st->client->dev); 2678c2ecf20Sopenharmony_cierror_measure: 2688c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&st->client->dev); 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic uint32_t icp10100_get_pressure(struct icp10100_state *st, 2738c2ecf20Sopenharmony_ci uint32_t raw_pressure, uint16_t raw_temp) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci static int32_t p_calib[] = {45000, 80000, 105000}; 2768c2ecf20Sopenharmony_ci static int32_t lut_lower = 3670016; 2778c2ecf20Sopenharmony_ci static int32_t lut_upper = 12058624; 2788c2ecf20Sopenharmony_ci static int32_t inv_quadr_factor = 16777216; 2798c2ecf20Sopenharmony_ci static int32_t offset_factor = 2048; 2808c2ecf20Sopenharmony_ci int64_t val1, val2; 2818c2ecf20Sopenharmony_ci int32_t p_lut[3]; 2828c2ecf20Sopenharmony_ci int32_t t, t_square; 2838c2ecf20Sopenharmony_ci int64_t a, b, c; 2848c2ecf20Sopenharmony_ci uint32_t pressure_mPa; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "raw: pressure = %u, temp = %u\n", 2878c2ecf20Sopenharmony_ci raw_pressure, raw_temp); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* compute p_lut values */ 2908c2ecf20Sopenharmony_ci t = (int32_t)raw_temp - 32768; 2918c2ecf20Sopenharmony_ci t_square = t * t; 2928c2ecf20Sopenharmony_ci val1 = (int64_t)st->cal[0] * (int64_t)t_square; 2938c2ecf20Sopenharmony_ci p_lut[0] = lut_lower + (int32_t)div_s64(val1, inv_quadr_factor); 2948c2ecf20Sopenharmony_ci val1 = (int64_t)st->cal[1] * (int64_t)t_square; 2958c2ecf20Sopenharmony_ci p_lut[1] = offset_factor * st->cal[3] + 2968c2ecf20Sopenharmony_ci (int32_t)div_s64(val1, inv_quadr_factor); 2978c2ecf20Sopenharmony_ci val1 = (int64_t)st->cal[2] * (int64_t)t_square; 2988c2ecf20Sopenharmony_ci p_lut[2] = lut_upper + (int32_t)div_s64(val1, inv_quadr_factor); 2998c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "p_lut = [%d, %d, %d]\n", 3008c2ecf20Sopenharmony_ci p_lut[0], p_lut[1], p_lut[2]); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* compute a, b, c factors */ 3038c2ecf20Sopenharmony_ci val1 = (int64_t)p_lut[0] * (int64_t)p_lut[1] * 3048c2ecf20Sopenharmony_ci (int64_t)(p_calib[0] - p_calib[1]) + 3058c2ecf20Sopenharmony_ci (int64_t)p_lut[1] * (int64_t)p_lut[2] * 3068c2ecf20Sopenharmony_ci (int64_t)(p_calib[1] - p_calib[2]) + 3078c2ecf20Sopenharmony_ci (int64_t)p_lut[2] * (int64_t)p_lut[0] * 3088c2ecf20Sopenharmony_ci (int64_t)(p_calib[2] - p_calib[0]); 3098c2ecf20Sopenharmony_ci val2 = (int64_t)p_lut[2] * (int64_t)(p_calib[0] - p_calib[1]) + 3108c2ecf20Sopenharmony_ci (int64_t)p_lut[0] * (int64_t)(p_calib[1] - p_calib[2]) + 3118c2ecf20Sopenharmony_ci (int64_t)p_lut[1] * (int64_t)(p_calib[2] - p_calib[0]); 3128c2ecf20Sopenharmony_ci c = div64_s64(val1, val2); 3138c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, c = %lld\n", 3148c2ecf20Sopenharmony_ci val1, val2, c); 3158c2ecf20Sopenharmony_ci val1 = (int64_t)p_calib[0] * (int64_t)p_lut[0] - 3168c2ecf20Sopenharmony_ci (int64_t)p_calib[1] * (int64_t)p_lut[1] - 3178c2ecf20Sopenharmony_ci (int64_t)(p_calib[1] - p_calib[0]) * c; 3188c2ecf20Sopenharmony_ci val2 = (int64_t)p_lut[0] - (int64_t)p_lut[1]; 3198c2ecf20Sopenharmony_ci a = div64_s64(val1, val2); 3208c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, a = %lld\n", 3218c2ecf20Sopenharmony_ci val1, val2, a); 3228c2ecf20Sopenharmony_ci b = ((int64_t)p_calib[0] - a) * ((int64_t)p_lut[0] + c); 3238c2ecf20Sopenharmony_ci dev_dbg(&st->client->dev, "b = %lld\n", b); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* 3268c2ecf20Sopenharmony_ci * pressure_Pa = a + (b / (c + raw_pressure)) 3278c2ecf20Sopenharmony_ci * pressure_mPa = 1000 * pressure_Pa 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ci pressure_mPa = 1000LL * a + div64_s64(1000LL * b, c + raw_pressure); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return pressure_mPa; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int icp10100_read_raw_measures(struct iio_dev *indio_dev, 3358c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3368c2ecf20Sopenharmony_ci int *val, int *val2) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct icp10100_state *st = iio_priv(indio_dev); 3398c2ecf20Sopenharmony_ci uint32_t raw_pressure; 3408c2ecf20Sopenharmony_ci uint16_t raw_temp; 3418c2ecf20Sopenharmony_ci uint32_t pressure_mPa; 3428c2ecf20Sopenharmony_ci int ret; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 3458c2ecf20Sopenharmony_ci if (ret) 3468c2ecf20Sopenharmony_ci return ret; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = icp10100_get_measures(st, &raw_pressure, &raw_temp); 3498c2ecf20Sopenharmony_ci if (ret) 3508c2ecf20Sopenharmony_ci goto error_release; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci switch (chan->type) { 3538c2ecf20Sopenharmony_ci case IIO_PRESSURE: 3548c2ecf20Sopenharmony_ci pressure_mPa = icp10100_get_pressure(st, raw_pressure, 3558c2ecf20Sopenharmony_ci raw_temp); 3568c2ecf20Sopenharmony_ci /* mPa to kPa */ 3578c2ecf20Sopenharmony_ci *val = pressure_mPa / 1000000; 3588c2ecf20Sopenharmony_ci *val2 = pressure_mPa % 1000000; 3598c2ecf20Sopenharmony_ci ret = IIO_VAL_INT_PLUS_MICRO; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci case IIO_TEMP: 3628c2ecf20Sopenharmony_ci *val = raw_temp; 3638c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci default: 3668c2ecf20Sopenharmony_ci ret = -EINVAL; 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cierror_release: 3718c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 3728c2ecf20Sopenharmony_ci return ret; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int icp10100_read_raw(struct iio_dev *indio_dev, 3768c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3778c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct icp10100_state *st = iio_priv(indio_dev); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci switch (mask) { 3828c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3838c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_PROCESSED: 3848c2ecf20Sopenharmony_ci return icp10100_read_raw_measures(indio_dev, chan, val, val2); 3858c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3868c2ecf20Sopenharmony_ci switch (chan->type) { 3878c2ecf20Sopenharmony_ci case IIO_TEMP: 3888c2ecf20Sopenharmony_ci /* 1000 * 175°C / 65536 in m°C */ 3898c2ecf20Sopenharmony_ci *val = 2; 3908c2ecf20Sopenharmony_ci *val2 = 670288; 3918c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 3928c2ecf20Sopenharmony_ci default: 3938c2ecf20Sopenharmony_ci return -EINVAL; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 3978c2ecf20Sopenharmony_ci switch (chan->type) { 3988c2ecf20Sopenharmony_ci case IIO_TEMP: 3998c2ecf20Sopenharmony_ci /* 1000 * -45°C in m°C */ 4008c2ecf20Sopenharmony_ci *val = -45000; 4018c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4028c2ecf20Sopenharmony_ci default: 4038c2ecf20Sopenharmony_ci return -EINVAL; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 4078c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 4088c2ecf20Sopenharmony_ci *val = 1 << st->mode; 4098c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 4108c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4118c2ecf20Sopenharmony_ci default: 4128c2ecf20Sopenharmony_ci return -EINVAL; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int icp10100_read_avail(struct iio_dev *indio_dev, 4178c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 4188c2ecf20Sopenharmony_ci const int **vals, int *type, int *length, 4198c2ecf20Sopenharmony_ci long mask) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci static int oversamplings[] = {1, 2, 4, 8}; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci switch (mask) { 4248c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 4258c2ecf20Sopenharmony_ci *vals = oversamplings; 4268c2ecf20Sopenharmony_ci *type = IIO_VAL_INT; 4278c2ecf20Sopenharmony_ci *length = ARRAY_SIZE(oversamplings); 4288c2ecf20Sopenharmony_ci return IIO_AVAIL_LIST; 4298c2ecf20Sopenharmony_ci default: 4308c2ecf20Sopenharmony_ci return -EINVAL; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int icp10100_write_raw(struct iio_dev *indio_dev, 4358c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 4368c2ecf20Sopenharmony_ci int val, int val2, long mask) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct icp10100_state *st = iio_priv(indio_dev); 4398c2ecf20Sopenharmony_ci unsigned int mode; 4408c2ecf20Sopenharmony_ci int ret; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci switch (mask) { 4438c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 4448c2ecf20Sopenharmony_ci /* oversampling is always positive and a power of 2 */ 4458c2ecf20Sopenharmony_ci if (val <= 0 || !is_power_of_2(val)) 4468c2ecf20Sopenharmony_ci return -EINVAL; 4478c2ecf20Sopenharmony_ci mode = ilog2(val); 4488c2ecf20Sopenharmony_ci if (mode >= ICP10100_MODE_NB) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 4518c2ecf20Sopenharmony_ci if (ret) 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 4548c2ecf20Sopenharmony_ci st->mode = mode; 4558c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 4568c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci default: 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int icp10100_write_raw_get_fmt(struct iio_dev *indio_dev, 4648c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 4658c2ecf20Sopenharmony_ci long mask) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci switch (mask) { 4688c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 4698c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4708c2ecf20Sopenharmony_ci default: 4718c2ecf20Sopenharmony_ci return -EINVAL; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic const struct iio_info icp10100_info = { 4768c2ecf20Sopenharmony_ci .read_raw = icp10100_read_raw, 4778c2ecf20Sopenharmony_ci .read_avail = icp10100_read_avail, 4788c2ecf20Sopenharmony_ci .write_raw = icp10100_write_raw, 4798c2ecf20Sopenharmony_ci .write_raw_get_fmt = icp10100_write_raw_get_fmt, 4808c2ecf20Sopenharmony_ci}; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic const struct iio_chan_spec icp10100_channels[] = { 4838c2ecf20Sopenharmony_ci { 4848c2ecf20Sopenharmony_ci .type = IIO_PRESSURE, 4858c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 4868c2ecf20Sopenharmony_ci .info_mask_shared_by_all = 4878c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 4888c2ecf20Sopenharmony_ci .info_mask_shared_by_all_available = 4898c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 4908c2ecf20Sopenharmony_ci }, { 4918c2ecf20Sopenharmony_ci .type = IIO_TEMP, 4928c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 4938c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | 4948c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET), 4958c2ecf20Sopenharmony_ci .info_mask_shared_by_all = 4968c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 4978c2ecf20Sopenharmony_ci .info_mask_shared_by_all_available = 4988c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 4998c2ecf20Sopenharmony_ci }, 5008c2ecf20Sopenharmony_ci}; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int icp10100_enable_regulator(struct icp10100_state *st) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int ret; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci ret = regulator_enable(st->vdd); 5078c2ecf20Sopenharmony_ci if (ret) 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci msleep(100); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void icp10100_disable_regulator_action(void *data) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct icp10100_state *st = data; 5178c2ecf20Sopenharmony_ci int ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci ret = regulator_disable(st->vdd); 5208c2ecf20Sopenharmony_ci if (ret) 5218c2ecf20Sopenharmony_ci dev_err(&st->client->dev, "error %d disabling vdd\n", ret); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void icp10100_pm_disable(void *data) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct device *dev = data; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci pm_runtime_put_sync_suspend(dev); 5298c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int icp10100_probe(struct i2c_client *client, 5338c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 5368c2ecf20Sopenharmony_ci struct icp10100_state *st; 5378c2ecf20Sopenharmony_ci int ret; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 5408c2ecf20Sopenharmony_ci dev_err(&client->dev, "plain i2c transactions not supported\n"); 5418c2ecf20Sopenharmony_ci return -ENODEV; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); 5458c2ecf20Sopenharmony_ci if (!indio_dev) 5468c2ecf20Sopenharmony_ci return -ENOMEM; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 5498c2ecf20Sopenharmony_ci indio_dev->name = client->name; 5508c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 5518c2ecf20Sopenharmony_ci indio_dev->channels = icp10100_channels; 5528c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(icp10100_channels); 5538c2ecf20Sopenharmony_ci indio_dev->info = &icp10100_info; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 5568c2ecf20Sopenharmony_ci mutex_init(&st->lock); 5578c2ecf20Sopenharmony_ci st->client = client; 5588c2ecf20Sopenharmony_ci st->mode = ICP10100_MODE_N; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci st->vdd = devm_regulator_get(&client->dev, "vdd"); 5618c2ecf20Sopenharmony_ci if (IS_ERR(st->vdd)) 5628c2ecf20Sopenharmony_ci return PTR_ERR(st->vdd); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = icp10100_enable_regulator(st); 5658c2ecf20Sopenharmony_ci if (ret) 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(&client->dev, 5698c2ecf20Sopenharmony_ci icp10100_disable_regulator_action, st); 5708c2ecf20Sopenharmony_ci if (ret) 5718c2ecf20Sopenharmony_ci return ret; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* has to be done before the first i2c communication */ 5748c2ecf20Sopenharmony_ci crc8_populate_msb(icp10100_crc8_table, ICP10100_CRC8_POLYNOMIAL); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ret = icp10100_init_chip(st); 5778c2ecf20Sopenharmony_ci if (ret) { 5788c2ecf20Sopenharmony_ci dev_err(&client->dev, "init chip error %d\n", ret); 5798c2ecf20Sopenharmony_ci return ret; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* enable runtime pm with autosuspend delay of 2s */ 5838c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&client->dev); 5848c2ecf20Sopenharmony_ci pm_runtime_set_active(&client->dev); 5858c2ecf20Sopenharmony_ci pm_runtime_enable(&client->dev); 5868c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&client->dev, 2000); 5878c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&client->dev); 5888c2ecf20Sopenharmony_ci pm_runtime_put(&client->dev); 5898c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(&client->dev, icp10100_pm_disable, 5908c2ecf20Sopenharmony_ci &client->dev); 5918c2ecf20Sopenharmony_ci if (ret) 5928c2ecf20Sopenharmony_ci return ret; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return devm_iio_device_register(&client->dev, indio_dev); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int __maybe_unused icp10100_suspend(struct device *dev) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct icp10100_state *st = iio_priv(dev_get_drvdata(dev)); 6008c2ecf20Sopenharmony_ci int ret; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 6038c2ecf20Sopenharmony_ci ret = regulator_disable(st->vdd); 6048c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return ret; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int __maybe_unused icp10100_resume(struct device *dev) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct icp10100_state *st = iio_priv(dev_get_drvdata(dev)); 6128c2ecf20Sopenharmony_ci int ret; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ret = icp10100_enable_regulator(st); 6178c2ecf20Sopenharmony_ci if (ret) 6188c2ecf20Sopenharmony_ci goto out_unlock; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* reset chip */ 6218c2ecf20Sopenharmony_ci ret = icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ciout_unlock: 6248c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 6258c2ecf20Sopenharmony_ci return ret; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic UNIVERSAL_DEV_PM_OPS(icp10100_pm, icp10100_suspend, icp10100_resume, 6298c2ecf20Sopenharmony_ci NULL); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic const struct of_device_id icp10100_of_match[] = { 6328c2ecf20Sopenharmony_ci { 6338c2ecf20Sopenharmony_ci .compatible = "invensense,icp10100", 6348c2ecf20Sopenharmony_ci }, 6358c2ecf20Sopenharmony_ci { } 6368c2ecf20Sopenharmony_ci}; 6378c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, icp10100_of_match); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic const struct i2c_device_id icp10100_id[] = { 6408c2ecf20Sopenharmony_ci { "icp10100", 0 }, 6418c2ecf20Sopenharmony_ci { } 6428c2ecf20Sopenharmony_ci}; 6438c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, icp10100_id); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic struct i2c_driver icp10100_driver = { 6468c2ecf20Sopenharmony_ci .driver = { 6478c2ecf20Sopenharmony_ci .name = "icp10100", 6488c2ecf20Sopenharmony_ci .pm = &icp10100_pm, 6498c2ecf20Sopenharmony_ci .of_match_table = icp10100_of_match, 6508c2ecf20Sopenharmony_ci }, 6518c2ecf20Sopenharmony_ci .probe = icp10100_probe, 6528c2ecf20Sopenharmony_ci .id_table = icp10100_id, 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_cimodule_i2c_driver(icp10100_driver); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ciMODULE_AUTHOR("InvenSense, Inc."); 6578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("InvenSense icp10100 driver"); 6588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 659