18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * si1133.c - Support for Silabs SI1133 combined ambient 48c2ecf20Sopenharmony_ci * light and UV index sensors 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 168c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/util_macros.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SI1133_REG_PART_ID 0x00 238c2ecf20Sopenharmony_ci#define SI1133_REG_REV_ID 0x01 248c2ecf20Sopenharmony_ci#define SI1133_REG_MFR_ID 0x02 258c2ecf20Sopenharmony_ci#define SI1133_REG_INFO0 0x03 268c2ecf20Sopenharmony_ci#define SI1133_REG_INFO1 0x04 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SI1133_PART_ID 0x33 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SI1133_REG_HOSTIN0 0x0A 318c2ecf20Sopenharmony_ci#define SI1133_REG_COMMAND 0x0B 328c2ecf20Sopenharmony_ci#define SI1133_REG_IRQ_ENABLE 0x0F 338c2ecf20Sopenharmony_ci#define SI1133_REG_RESPONSE1 0x10 348c2ecf20Sopenharmony_ci#define SI1133_REG_RESPONSE0 0x11 358c2ecf20Sopenharmony_ci#define SI1133_REG_IRQ_STATUS 0x12 368c2ecf20Sopenharmony_ci#define SI1133_REG_MEAS_RATE 0x1A 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SI1133_IRQ_CHANNEL_ENABLE 0xF 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define SI1133_CMD_RESET_CTR 0x00 418c2ecf20Sopenharmony_ci#define SI1133_CMD_RESET_SW 0x01 428c2ecf20Sopenharmony_ci#define SI1133_CMD_FORCE 0x11 438c2ecf20Sopenharmony_ci#define SI1133_CMD_START_AUTONOMOUS 0x13 448c2ecf20Sopenharmony_ci#define SI1133_CMD_PARAM_SET 0x80 458c2ecf20Sopenharmony_ci#define SI1133_CMD_PARAM_QUERY 0x40 468c2ecf20Sopenharmony_ci#define SI1133_CMD_PARAM_MASK 0x3F 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define SI1133_CMD_ERR_MASK BIT(4) 498c2ecf20Sopenharmony_ci#define SI1133_CMD_SEQ_MASK 0xF 508c2ecf20Sopenharmony_ci#define SI1133_MAX_CMD_CTR 0xF 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_CHAN_LIST 0x01 538c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_ADCCONFIG(x) ((x) * 4) + 2 548c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_ADCSENS(x) ((x) * 4) + 3 558c2ecf20Sopenharmony_ci#define SI1133_PARAM_REG_ADCPOST(x) ((x) * 4) + 4 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define SI1133_ADCMUX_MASK 0x1F 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define SI1133_ADCCONFIG_DECIM_RATE(x) (x) << 5 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_SCALE_MASK 0x70 628c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_SCALE_SHIFT 4 638c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_HSIG_MASK BIT(7) 648c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_HSIG_SHIFT 7 658c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_HW_GAIN_MASK 0xF 668c2ecf20Sopenharmony_ci#define SI1133_ADCSENS_NB_MEAS(x) fls(x) << SI1133_ADCSENS_SCALE_SHIFT 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define SI1133_ADCPOST_24BIT_EN BIT(6) 698c2ecf20Sopenharmony_ci#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_SMALL_IR 0x0 728c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_MED_IR 0x1 738c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_LARGE_IR 0x2 748c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_WHITE 0xB 758c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_LARGE_WHITE 0xD 768c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_UV 0x18 778c2ecf20Sopenharmony_ci#define SI1133_PARAM_ADCMUX_UV_DEEP 0x19 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define SI1133_ERR_INVALID_CMD 0x0 808c2ecf20Sopenharmony_ci#define SI1133_ERR_INVALID_LOCATION_CMD 0x1 818c2ecf20Sopenharmony_ci#define SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION 0x2 828c2ecf20Sopenharmony_ci#define SI1133_ERR_OUTPUT_BUFFER_OVERFLOW 0x3 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define SI1133_COMPLETION_TIMEOUT_MS 500 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define SI1133_CMD_MINSLEEP_US_LOW 5000 878c2ecf20Sopenharmony_ci#define SI1133_CMD_MINSLEEP_US_HIGH 7500 888c2ecf20Sopenharmony_ci#define SI1133_CMD_TIMEOUT_MS 25 898c2ecf20Sopenharmony_ci#define SI1133_CMD_LUX_TIMEOUT_MS 5000 908c2ecf20Sopenharmony_ci#define SI1133_CMD_TIMEOUT_US SI1133_CMD_TIMEOUT_MS * 1000 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define SI1133_REG_HOSTOUT(x) (x) + 0x13 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define SI1133_MEASUREMENT_FREQUENCY 1250 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define SI1133_X_ORDER_MASK 0x0070 978c2ecf20Sopenharmony_ci#define SI1133_Y_ORDER_MASK 0x0007 988c2ecf20Sopenharmony_ci#define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4 998c2ecf20Sopenharmony_ci#define si1133_get_y_order(m) ((m) & SI1133_Y_ORDER_MASK) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define SI1133_LUX_ADC_MASK 0xE 1028c2ecf20Sopenharmony_ci#define SI1133_ADC_THRESHOLD 16000 1038c2ecf20Sopenharmony_ci#define SI1133_INPUT_FRACTION_HIGH 7 1048c2ecf20Sopenharmony_ci#define SI1133_INPUT_FRACTION_LOW 15 1058c2ecf20Sopenharmony_ci#define SI1133_LUX_OUTPUT_FRACTION 12 1068c2ecf20Sopenharmony_ci#define SI1133_LUX_BUFFER_SIZE 9 1078c2ecf20Sopenharmony_ci#define SI1133_MEASURE_BUFFER_SIZE 3 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic const int si1133_scale_available[] = { 1108c2ecf20Sopenharmony_ci 1, 2, 4, 8, 16, 32, 64, 128}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(scale_available, "1 2 4 8 16 32 64 128"); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_INT_TIME_AVAIL("0.0244 0.0488 0.0975 0.195 0.390 0.780 " 1158c2ecf20Sopenharmony_ci "1.560 3.120 6.24 12.48 25.0 50.0"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* A.K.A. HW_GAIN in datasheet */ 1188c2ecf20Sopenharmony_cienum si1133_int_time { 1198c2ecf20Sopenharmony_ci _24_4_us = 0, 1208c2ecf20Sopenharmony_ci _48_8_us = 1, 1218c2ecf20Sopenharmony_ci _97_5_us = 2, 1228c2ecf20Sopenharmony_ci _195_0_us = 3, 1238c2ecf20Sopenharmony_ci _390_0_us = 4, 1248c2ecf20Sopenharmony_ci _780_0_us = 5, 1258c2ecf20Sopenharmony_ci _1_560_0_us = 6, 1268c2ecf20Sopenharmony_ci _3_120_0_us = 7, 1278c2ecf20Sopenharmony_ci _6_240_0_us = 8, 1288c2ecf20Sopenharmony_ci _12_480_0_us = 9, 1298c2ecf20Sopenharmony_ci _25_ms = 10, 1308c2ecf20Sopenharmony_ci _50_ms = 11, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Integration time in milliseconds, nanoseconds */ 1348c2ecf20Sopenharmony_cistatic const int si1133_int_time_table[][2] = { 1358c2ecf20Sopenharmony_ci [_24_4_us] = {0, 24400}, 1368c2ecf20Sopenharmony_ci [_48_8_us] = {0, 48800}, 1378c2ecf20Sopenharmony_ci [_97_5_us] = {0, 97500}, 1388c2ecf20Sopenharmony_ci [_195_0_us] = {0, 195000}, 1398c2ecf20Sopenharmony_ci [_390_0_us] = {0, 390000}, 1408c2ecf20Sopenharmony_ci [_780_0_us] = {0, 780000}, 1418c2ecf20Sopenharmony_ci [_1_560_0_us] = {1, 560000}, 1428c2ecf20Sopenharmony_ci [_3_120_0_us] = {3, 120000}, 1438c2ecf20Sopenharmony_ci [_6_240_0_us] = {6, 240000}, 1448c2ecf20Sopenharmony_ci [_12_480_0_us] = {12, 480000}, 1458c2ecf20Sopenharmony_ci [_25_ms] = {25, 000000}, 1468c2ecf20Sopenharmony_ci [_50_ms] = {50, 000000}, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct regmap_range si1133_reg_ranges[] = { 1508c2ecf20Sopenharmony_ci regmap_reg_range(0x00, 0x02), 1518c2ecf20Sopenharmony_ci regmap_reg_range(0x0A, 0x0B), 1528c2ecf20Sopenharmony_ci regmap_reg_range(0x0F, 0x0F), 1538c2ecf20Sopenharmony_ci regmap_reg_range(0x10, 0x12), 1548c2ecf20Sopenharmony_ci regmap_reg_range(0x13, 0x2C), 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic const struct regmap_range si1133_reg_ro_ranges[] = { 1588c2ecf20Sopenharmony_ci regmap_reg_range(0x00, 0x02), 1598c2ecf20Sopenharmony_ci regmap_reg_range(0x10, 0x2C), 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic const struct regmap_range si1133_precious_ranges[] = { 1638c2ecf20Sopenharmony_ci regmap_reg_range(0x12, 0x12), 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic const struct regmap_access_table si1133_write_ranges_table = { 1678c2ecf20Sopenharmony_ci .yes_ranges = si1133_reg_ranges, 1688c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(si1133_reg_ranges), 1698c2ecf20Sopenharmony_ci .no_ranges = si1133_reg_ro_ranges, 1708c2ecf20Sopenharmony_ci .n_no_ranges = ARRAY_SIZE(si1133_reg_ro_ranges), 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const struct regmap_access_table si1133_read_ranges_table = { 1748c2ecf20Sopenharmony_ci .yes_ranges = si1133_reg_ranges, 1758c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(si1133_reg_ranges), 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic const struct regmap_access_table si1133_precious_table = { 1798c2ecf20Sopenharmony_ci .yes_ranges = si1133_precious_ranges, 1808c2ecf20Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(si1133_precious_ranges), 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const struct regmap_config si1133_regmap_config = { 1848c2ecf20Sopenharmony_ci .reg_bits = 8, 1858c2ecf20Sopenharmony_ci .val_bits = 8, 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci .max_register = 0x2C, 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci .wr_table = &si1133_write_ranges_table, 1908c2ecf20Sopenharmony_ci .rd_table = &si1133_read_ranges_table, 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci .precious_table = &si1133_precious_table, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistruct si1133_data { 1968c2ecf20Sopenharmony_ci struct regmap *regmap; 1978c2ecf20Sopenharmony_ci struct i2c_client *client; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Lock protecting one command at a time can be processed */ 2008c2ecf20Sopenharmony_ci struct mutex mutex; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci int rsp_seq; 2038c2ecf20Sopenharmony_ci u8 scan_mask; 2048c2ecf20Sopenharmony_ci u8 adc_sens[6]; 2058c2ecf20Sopenharmony_ci u8 adc_config[6]; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci struct completion completion; 2088c2ecf20Sopenharmony_ci}; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistruct si1133_coeff { 2118c2ecf20Sopenharmony_ci s16 info; 2128c2ecf20Sopenharmony_ci u16 mag; 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistruct si1133_lux_coeff { 2168c2ecf20Sopenharmony_ci struct si1133_coeff coeff_high[4]; 2178c2ecf20Sopenharmony_ci struct si1133_coeff coeff_low[9]; 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic const struct si1133_lux_coeff lux_coeff = { 2218c2ecf20Sopenharmony_ci { 2228c2ecf20Sopenharmony_ci { 0, 209}, 2238c2ecf20Sopenharmony_ci { 1665, 93}, 2248c2ecf20Sopenharmony_ci { 2064, 65}, 2258c2ecf20Sopenharmony_ci {-2671, 234} 2268c2ecf20Sopenharmony_ci }, 2278c2ecf20Sopenharmony_ci { 2288c2ecf20Sopenharmony_ci { 0, 0}, 2298c2ecf20Sopenharmony_ci { 1921, 29053}, 2308c2ecf20Sopenharmony_ci {-1022, 36363}, 2318c2ecf20Sopenharmony_ci { 2320, 20789}, 2328c2ecf20Sopenharmony_ci { -367, 57909}, 2338c2ecf20Sopenharmony_ci {-1774, 38240}, 2348c2ecf20Sopenharmony_ci { -608, 46775}, 2358c2ecf20Sopenharmony_ci {-1503, 51831}, 2368c2ecf20Sopenharmony_ci {-1886, 58928} 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int si1133_calculate_polynomial_inner(s32 input, u8 fraction, u16 mag, 2418c2ecf20Sopenharmony_ci s8 shift) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci return ((input << fraction) / mag) << shift; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int si1133_calculate_output(s32 x, s32 y, u8 x_order, u8 y_order, 2478c2ecf20Sopenharmony_ci u8 input_fraction, s8 sign, 2488c2ecf20Sopenharmony_ci const struct si1133_coeff *coeffs) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci s8 shift; 2518c2ecf20Sopenharmony_ci int x1 = 1; 2528c2ecf20Sopenharmony_ci int x2 = 1; 2538c2ecf20Sopenharmony_ci int y1 = 1; 2548c2ecf20Sopenharmony_ci int y2 = 1; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci shift = ((u16)coeffs->info & 0xFF00) >> 8; 2578c2ecf20Sopenharmony_ci shift ^= 0xFF; 2588c2ecf20Sopenharmony_ci shift += 1; 2598c2ecf20Sopenharmony_ci shift = -shift; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (x_order > 0) { 2628c2ecf20Sopenharmony_ci x1 = si1133_calculate_polynomial_inner(x, input_fraction, 2638c2ecf20Sopenharmony_ci coeffs->mag, shift); 2648c2ecf20Sopenharmony_ci if (x_order > 1) 2658c2ecf20Sopenharmony_ci x2 = x1; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (y_order > 0) { 2698c2ecf20Sopenharmony_ci y1 = si1133_calculate_polynomial_inner(y, input_fraction, 2708c2ecf20Sopenharmony_ci coeffs->mag, shift); 2718c2ecf20Sopenharmony_ci if (y_order > 1) 2728c2ecf20Sopenharmony_ci y2 = y1; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return sign * x1 * x2 * y1 * y2; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* 2798c2ecf20Sopenharmony_ci * The algorithm is from: 2808c2ecf20Sopenharmony_ci * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_cistatic int si1133_calc_polynomial(s32 x, s32 y, u8 input_fraction, u8 num_coeff, 2838c2ecf20Sopenharmony_ci const struct si1133_coeff *coeffs) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci u8 x_order, y_order; 2868c2ecf20Sopenharmony_ci u8 counter; 2878c2ecf20Sopenharmony_ci s8 sign; 2888c2ecf20Sopenharmony_ci int output = 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (counter = 0; counter < num_coeff; counter++) { 2918c2ecf20Sopenharmony_ci if (coeffs->info < 0) 2928c2ecf20Sopenharmony_ci sign = -1; 2938c2ecf20Sopenharmony_ci else 2948c2ecf20Sopenharmony_ci sign = 1; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci x_order = si1133_get_x_order(coeffs->info); 2978c2ecf20Sopenharmony_ci y_order = si1133_get_y_order(coeffs->info); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if ((x_order == 0) && (y_order == 0)) 3008c2ecf20Sopenharmony_ci output += 3018c2ecf20Sopenharmony_ci sign * coeffs->mag << SI1133_LUX_OUTPUT_FRACTION; 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci output += si1133_calculate_output(x, y, x_order, 3048c2ecf20Sopenharmony_ci y_order, 3058c2ecf20Sopenharmony_ci input_fraction, sign, 3068c2ecf20Sopenharmony_ci coeffs); 3078c2ecf20Sopenharmony_ci coeffs++; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return abs(output); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int si1133_cmd_reset_sw(struct si1133_data *data) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct device *dev = &data->client->dev; 3168c2ecf20Sopenharmony_ci unsigned int resp; 3178c2ecf20Sopenharmony_ci unsigned long timeout; 3188c2ecf20Sopenharmony_ci int err; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci err = regmap_write(data->regmap, SI1133_REG_COMMAND, 3218c2ecf20Sopenharmony_ci SI1133_CMD_RESET_SW); 3228c2ecf20Sopenharmony_ci if (err) 3238c2ecf20Sopenharmony_ci return err; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(SI1133_CMD_TIMEOUT_MS); 3268c2ecf20Sopenharmony_ci while (true) { 3278c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp); 3288c2ecf20Sopenharmony_ci if (err == -ENXIO) { 3298c2ecf20Sopenharmony_ci usleep_range(SI1133_CMD_MINSLEEP_US_LOW, 3308c2ecf20Sopenharmony_ci SI1133_CMD_MINSLEEP_US_HIGH); 3318c2ecf20Sopenharmony_ci continue; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if ((resp & SI1133_MAX_CMD_CTR) == SI1133_MAX_CMD_CTR) 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 3388c2ecf20Sopenharmony_ci dev_warn(dev, "Timeout on reset ctr resp: %d\n", resp); 3398c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!err) 3448c2ecf20Sopenharmony_ci data->rsp_seq = SI1133_MAX_CMD_CTR; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return err; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci resp &= 0xF; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci switch (resp) { 3548c2ecf20Sopenharmony_ci case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW: 3558c2ecf20Sopenharmony_ci dev_warn(dev, "Output buffer overflow: %#02hhx\n", cmd); 3568c2ecf20Sopenharmony_ci return -EOVERFLOW; 3578c2ecf20Sopenharmony_ci case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION: 3588c2ecf20Sopenharmony_ci dev_warn(dev, "Saturation of the ADC or overflow of accumulation: %#02hhx\n", 3598c2ecf20Sopenharmony_ci cmd); 3608c2ecf20Sopenharmony_ci return -EOVERFLOW; 3618c2ecf20Sopenharmony_ci case SI1133_ERR_INVALID_LOCATION_CMD: 3628c2ecf20Sopenharmony_ci dev_warn(dev, 3638c2ecf20Sopenharmony_ci "Parameter access to an invalid location: %#02hhx\n", 3648c2ecf20Sopenharmony_ci cmd); 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci case SI1133_ERR_INVALID_CMD: 3678c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid command %#02hhx\n", cmd); 3688c2ecf20Sopenharmony_ci return -EINVAL; 3698c2ecf20Sopenharmony_ci default: 3708c2ecf20Sopenharmony_ci dev_warn(dev, "Unknown error %#02hhx\n", cmd); 3718c2ecf20Sopenharmony_ci return -EINVAL; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int si1133_cmd_reset_counter(struct si1133_data *data) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci int err = regmap_write(data->regmap, SI1133_REG_COMMAND, 3788c2ecf20Sopenharmony_ci SI1133_CMD_RESET_CTR); 3798c2ecf20Sopenharmony_ci if (err) 3808c2ecf20Sopenharmony_ci return err; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci data->rsp_seq = 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int si1133_command(struct si1133_data *data, u8 cmd) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct device *dev = &data->client->dev; 3908c2ecf20Sopenharmony_ci u32 resp; 3918c2ecf20Sopenharmony_ci int err; 3928c2ecf20Sopenharmony_ci int expected_seq; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (cmd == SI1133_CMD_FORCE) 3998c2ecf20Sopenharmony_ci reinit_completion(&data->completion); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd); 4028c2ecf20Sopenharmony_ci if (err) { 4038c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to write command %#02hhx, ret=%d\n", cmd, 4048c2ecf20Sopenharmony_ci err); 4058c2ecf20Sopenharmony_ci goto out; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (cmd == SI1133_CMD_FORCE) { 4098c2ecf20Sopenharmony_ci /* wait for irq */ 4108c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&data->completion, 4118c2ecf20Sopenharmony_ci msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) { 4128c2ecf20Sopenharmony_ci err = -ETIMEDOUT; 4138c2ecf20Sopenharmony_ci goto out; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp); 4168c2ecf20Sopenharmony_ci if (err) 4178c2ecf20Sopenharmony_ci goto out; 4188c2ecf20Sopenharmony_ci } else { 4198c2ecf20Sopenharmony_ci err = regmap_read_poll_timeout(data->regmap, 4208c2ecf20Sopenharmony_ci SI1133_REG_RESPONSE0, resp, 4218c2ecf20Sopenharmony_ci (resp & SI1133_CMD_SEQ_MASK) == 4228c2ecf20Sopenharmony_ci expected_seq || 4238c2ecf20Sopenharmony_ci (resp & SI1133_CMD_ERR_MASK), 4248c2ecf20Sopenharmony_ci SI1133_CMD_MINSLEEP_US_LOW, 4258c2ecf20Sopenharmony_ci SI1133_CMD_TIMEOUT_MS * 1000); 4268c2ecf20Sopenharmony_ci if (err) { 4278c2ecf20Sopenharmony_ci dev_warn(dev, 4288c2ecf20Sopenharmony_ci "Failed to read command %#02hhx, ret=%d\n", 4298c2ecf20Sopenharmony_ci cmd, err); 4308c2ecf20Sopenharmony_ci goto out; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (resp & SI1133_CMD_ERR_MASK) { 4358c2ecf20Sopenharmony_ci err = si1133_parse_response_err(dev, resp, cmd); 4368c2ecf20Sopenharmony_ci si1133_cmd_reset_counter(data); 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci data->rsp_seq = expected_seq; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciout: 4428c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return err; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int si1133_param_set(struct si1133_data *data, u8 param, u32 value) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci int err = regmap_write(data->regmap, SI1133_REG_HOSTIN0, value); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (err) 4528c2ecf20Sopenharmony_ci return err; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return si1133_command(data, SI1133_CMD_PARAM_SET | 4558c2ecf20Sopenharmony_ci (param & SI1133_CMD_PARAM_MASK)); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int si1133_param_query(struct si1133_data *data, u8 param, u32 *result) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci int err = si1133_command(data, SI1133_CMD_PARAM_QUERY | 4618c2ecf20Sopenharmony_ci (param & SI1133_CMD_PARAM_MASK)); 4628c2ecf20Sopenharmony_ci if (err) 4638c2ecf20Sopenharmony_ci return err; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return regmap_read(data->regmap, SI1133_REG_RESPONSE1, result); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci#define SI1133_CHANNEL(_ch, _type) \ 4698c2ecf20Sopenharmony_ci .type = _type, \ 4708c2ecf20Sopenharmony_ci .channel = _ch, \ 4718c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 4728c2ecf20Sopenharmony_ci .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | \ 4738c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 4748c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic const struct iio_chan_spec si1133_channels[] = { 4778c2ecf20Sopenharmony_ci { 4788c2ecf20Sopenharmony_ci .type = IIO_LIGHT, 4798c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 4808c2ecf20Sopenharmony_ci .channel = 0, 4818c2ecf20Sopenharmony_ci }, 4828c2ecf20Sopenharmony_ci { 4838c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_WHITE, IIO_INTENSITY) 4848c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_BOTH, 4858c2ecf20Sopenharmony_ci }, 4868c2ecf20Sopenharmony_ci { 4878c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_WHITE, IIO_INTENSITY) 4888c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_BOTH, 4898c2ecf20Sopenharmony_ci .extend_name = "large", 4908c2ecf20Sopenharmony_ci }, 4918c2ecf20Sopenharmony_ci { 4928c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_SMALL_IR, IIO_INTENSITY) 4938c2ecf20Sopenharmony_ci .extend_name = "small", 4948c2ecf20Sopenharmony_ci .modified = 1, 4958c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_IR, 4968c2ecf20Sopenharmony_ci }, 4978c2ecf20Sopenharmony_ci { 4988c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_MED_IR, IIO_INTENSITY) 4998c2ecf20Sopenharmony_ci .modified = 1, 5008c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_IR, 5018c2ecf20Sopenharmony_ci }, 5028c2ecf20Sopenharmony_ci { 5038c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_IR, IIO_INTENSITY) 5048c2ecf20Sopenharmony_ci .extend_name = "large", 5058c2ecf20Sopenharmony_ci .modified = 1, 5068c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_IR, 5078c2ecf20Sopenharmony_ci }, 5088c2ecf20Sopenharmony_ci { 5098c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV, IIO_UVINDEX) 5108c2ecf20Sopenharmony_ci }, 5118c2ecf20Sopenharmony_ci { 5128c2ecf20Sopenharmony_ci SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV_DEEP, IIO_UVINDEX) 5138c2ecf20Sopenharmony_ci .modified = 1, 5148c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_LIGHT_DUV, 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci}; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int si1133_get_int_time_index(int milliseconds, int nanoseconds) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci int i; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(si1133_int_time_table); i++) { 5238c2ecf20Sopenharmony_ci if (milliseconds == si1133_int_time_table[i][0] && 5248c2ecf20Sopenharmony_ci nanoseconds == si1133_int_time_table[i][1]) 5258c2ecf20Sopenharmony_ci return i; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int si1133_set_integration_time(struct si1133_data *data, u8 adc, 5318c2ecf20Sopenharmony_ci int milliseconds, int nanoseconds) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci int index; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci index = si1133_get_int_time_index(milliseconds, nanoseconds); 5368c2ecf20Sopenharmony_ci if (index < 0) 5378c2ecf20Sopenharmony_ci return index; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci data->adc_sens[adc] &= 0xF0; 5408c2ecf20Sopenharmony_ci data->adc_sens[adc] |= index; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(0), 5438c2ecf20Sopenharmony_ci data->adc_sens[adc]); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int si1133_set_chlist(struct si1133_data *data, u8 scan_mask) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci /* channel list already set, no need to reprogram */ 5498c2ecf20Sopenharmony_ci if (data->scan_mask == scan_mask) 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci data->scan_mask = scan_mask; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return si1133_param_set(data, SI1133_PARAM_REG_CHAN_LIST, scan_mask); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int si1133_chan_set_adcconfig(struct si1133_data *data, u8 adc, 5588c2ecf20Sopenharmony_ci u8 adc_config) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci int err; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci err = si1133_param_set(data, SI1133_PARAM_REG_ADCCONFIG(adc), 5638c2ecf20Sopenharmony_ci adc_config); 5648c2ecf20Sopenharmony_ci if (err) 5658c2ecf20Sopenharmony_ci return err; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci data->adc_config[adc] = adc_config; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int si1133_update_adcconfig(struct si1133_data *data, uint8_t adc, 5738c2ecf20Sopenharmony_ci u8 mask, u8 shift, u8 value) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci u32 adc_config; 5768c2ecf20Sopenharmony_ci int err; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci err = si1133_param_query(data, SI1133_PARAM_REG_ADCCONFIG(adc), 5798c2ecf20Sopenharmony_ci &adc_config); 5808c2ecf20Sopenharmony_ci if (err) 5818c2ecf20Sopenharmony_ci return err; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci adc_config &= ~mask; 5848c2ecf20Sopenharmony_ci adc_config |= (value << shift); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return si1133_chan_set_adcconfig(data, adc, adc_config); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int si1133_set_adcmux(struct si1133_data *data, u8 adc, u8 mux) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci if ((mux & data->adc_config[adc]) == mux) 5928c2ecf20Sopenharmony_ci return 0; /* mux already set to correct value */ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return si1133_update_adcconfig(data, adc, SI1133_ADCMUX_MASK, 0, mux); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int si1133_force_measurement(struct si1133_data *data) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci return si1133_command(data, SI1133_CMD_FORCE); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int si1133_bulk_read(struct si1133_data *data, u8 start_reg, u8 length, 6038c2ecf20Sopenharmony_ci u8 *buffer) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int err; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci err = si1133_force_measurement(data); 6088c2ecf20Sopenharmony_ci if (err) 6098c2ecf20Sopenharmony_ci return err; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return regmap_bulk_read(data->regmap, start_reg, buffer, length); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic int si1133_measure(struct si1133_data *data, 6158c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 6168c2ecf20Sopenharmony_ci int *val) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci int err; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci u8 buffer[SI1133_MEASURE_BUFFER_SIZE]; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci err = si1133_set_adcmux(data, 0, chan->channel); 6238c2ecf20Sopenharmony_ci if (err) 6248c2ecf20Sopenharmony_ci return err; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Deactivate lux measurements if they were active */ 6278c2ecf20Sopenharmony_ci err = si1133_set_chlist(data, BIT(0)); 6288c2ecf20Sopenharmony_ci if (err) 6298c2ecf20Sopenharmony_ci return err; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(buffer), 6328c2ecf20Sopenharmony_ci buffer); 6338c2ecf20Sopenharmony_ci if (err) 6348c2ecf20Sopenharmony_ci return err; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci *val = sign_extend32(get_unaligned_be24(&buffer[0]), 23); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return err; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic irqreturn_t si1133_threaded_irq_handler(int irq, void *private) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct iio_dev *iio_dev = private; 6448c2ecf20Sopenharmony_ci struct si1133_data *data = iio_priv(iio_dev); 6458c2ecf20Sopenharmony_ci u32 irq_status; 6468c2ecf20Sopenharmony_ci int err; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &irq_status); 6498c2ecf20Sopenharmony_ci if (err) { 6508c2ecf20Sopenharmony_ci dev_err_ratelimited(&iio_dev->dev, "Error reading IRQ\n"); 6518c2ecf20Sopenharmony_ci goto out; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (irq_status != data->scan_mask) 6558c2ecf20Sopenharmony_ci return IRQ_NONE; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ciout: 6588c2ecf20Sopenharmony_ci complete(&data->completion); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int si1133_scale_to_swgain(int scale_integer, int scale_fractional) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci scale_integer = find_closest(scale_integer, si1133_scale_available, 6668c2ecf20Sopenharmony_ci ARRAY_SIZE(si1133_scale_available)); 6678c2ecf20Sopenharmony_ci if (scale_integer < 0 || 6688c2ecf20Sopenharmony_ci scale_integer > ARRAY_SIZE(si1133_scale_available) || 6698c2ecf20Sopenharmony_ci scale_fractional != 0) 6708c2ecf20Sopenharmony_ci return -EINVAL; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return scale_integer; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int si1133_chan_set_adcsens(struct si1133_data *data, u8 adc, 6768c2ecf20Sopenharmony_ci u8 adc_sens) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci int err; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci err = si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(adc), adc_sens); 6818c2ecf20Sopenharmony_ci if (err) 6828c2ecf20Sopenharmony_ci return err; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci data->adc_sens[adc] = adc_sens; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int si1133_update_adcsens(struct si1133_data *data, u8 mask, 6908c2ecf20Sopenharmony_ci u8 shift, u8 value) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci int err; 6938c2ecf20Sopenharmony_ci u32 adc_sens; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci err = si1133_param_query(data, SI1133_PARAM_REG_ADCSENS(0), 6968c2ecf20Sopenharmony_ci &adc_sens); 6978c2ecf20Sopenharmony_ci if (err) 6988c2ecf20Sopenharmony_ci return err; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci adc_sens &= ~mask; 7018c2ecf20Sopenharmony_ci adc_sens |= (value << shift); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return si1133_chan_set_adcsens(data, 0, adc_sens); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int si1133_get_lux(struct si1133_data *data, int *val) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci int err; 7098c2ecf20Sopenharmony_ci int lux; 7108c2ecf20Sopenharmony_ci s32 high_vis; 7118c2ecf20Sopenharmony_ci s32 low_vis; 7128c2ecf20Sopenharmony_ci s32 ir; 7138c2ecf20Sopenharmony_ci u8 buffer[SI1133_LUX_BUFFER_SIZE]; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Activate lux channels */ 7168c2ecf20Sopenharmony_ci err = si1133_set_chlist(data, SI1133_LUX_ADC_MASK); 7178c2ecf20Sopenharmony_ci if (err) 7188c2ecf20Sopenharmony_ci return err; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), 7218c2ecf20Sopenharmony_ci SI1133_LUX_BUFFER_SIZE, buffer); 7228c2ecf20Sopenharmony_ci if (err) 7238c2ecf20Sopenharmony_ci return err; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci high_vis = sign_extend32(get_unaligned_be24(&buffer[0]), 23); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci low_vis = sign_extend32(get_unaligned_be24(&buffer[3]), 23); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ir = sign_extend32(get_unaligned_be24(&buffer[6]), 23); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD) 7328c2ecf20Sopenharmony_ci lux = si1133_calc_polynomial(high_vis, ir, 7338c2ecf20Sopenharmony_ci SI1133_INPUT_FRACTION_HIGH, 7348c2ecf20Sopenharmony_ci ARRAY_SIZE(lux_coeff.coeff_high), 7358c2ecf20Sopenharmony_ci &lux_coeff.coeff_high[0]); 7368c2ecf20Sopenharmony_ci else 7378c2ecf20Sopenharmony_ci lux = si1133_calc_polynomial(low_vis, ir, 7388c2ecf20Sopenharmony_ci SI1133_INPUT_FRACTION_LOW, 7398c2ecf20Sopenharmony_ci ARRAY_SIZE(lux_coeff.coeff_low), 7408c2ecf20Sopenharmony_ci &lux_coeff.coeff_low[0]); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci *val = lux >> SI1133_LUX_OUTPUT_FRACTION; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return err; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int si1133_read_raw(struct iio_dev *iio_dev, 7488c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 7498c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct si1133_data *data = iio_priv(iio_dev); 7528c2ecf20Sopenharmony_ci u8 adc_sens = data->adc_sens[0]; 7538c2ecf20Sopenharmony_ci int err; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci switch (mask) { 7568c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_PROCESSED: 7578c2ecf20Sopenharmony_ci switch (chan->type) { 7588c2ecf20Sopenharmony_ci case IIO_LIGHT: 7598c2ecf20Sopenharmony_ci err = si1133_get_lux(data, val); 7608c2ecf20Sopenharmony_ci if (err) 7618c2ecf20Sopenharmony_ci return err; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return IIO_VAL_INT; 7648c2ecf20Sopenharmony_ci default: 7658c2ecf20Sopenharmony_ci return -EINVAL; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 7688c2ecf20Sopenharmony_ci switch (chan->type) { 7698c2ecf20Sopenharmony_ci case IIO_INTENSITY: 7708c2ecf20Sopenharmony_ci case IIO_UVINDEX: 7718c2ecf20Sopenharmony_ci err = si1133_measure(data, chan, val); 7728c2ecf20Sopenharmony_ci if (err) 7738c2ecf20Sopenharmony_ci return err; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return IIO_VAL_INT; 7768c2ecf20Sopenharmony_ci default: 7778c2ecf20Sopenharmony_ci return -EINVAL; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 7808c2ecf20Sopenharmony_ci switch (chan->type) { 7818c2ecf20Sopenharmony_ci case IIO_INTENSITY: 7828c2ecf20Sopenharmony_ci case IIO_UVINDEX: 7838c2ecf20Sopenharmony_ci adc_sens &= SI1133_ADCSENS_HW_GAIN_MASK; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci *val = si1133_int_time_table[adc_sens][0]; 7868c2ecf20Sopenharmony_ci *val2 = si1133_int_time_table[adc_sens][1]; 7878c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 7888c2ecf20Sopenharmony_ci default: 7898c2ecf20Sopenharmony_ci return -EINVAL; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 7928c2ecf20Sopenharmony_ci switch (chan->type) { 7938c2ecf20Sopenharmony_ci case IIO_INTENSITY: 7948c2ecf20Sopenharmony_ci case IIO_UVINDEX: 7958c2ecf20Sopenharmony_ci adc_sens &= SI1133_ADCSENS_SCALE_MASK; 7968c2ecf20Sopenharmony_ci adc_sens >>= SI1133_ADCSENS_SCALE_SHIFT; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci *val = BIT(adc_sens); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return IIO_VAL_INT; 8018c2ecf20Sopenharmony_ci default: 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_HARDWAREGAIN: 8058c2ecf20Sopenharmony_ci switch (chan->type) { 8068c2ecf20Sopenharmony_ci case IIO_INTENSITY: 8078c2ecf20Sopenharmony_ci case IIO_UVINDEX: 8088c2ecf20Sopenharmony_ci adc_sens >>= SI1133_ADCSENS_HSIG_SHIFT; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci *val = adc_sens; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return IIO_VAL_INT; 8138c2ecf20Sopenharmony_ci default: 8148c2ecf20Sopenharmony_ci return -EINVAL; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci default: 8178c2ecf20Sopenharmony_ci return -EINVAL; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int si1133_write_raw(struct iio_dev *iio_dev, 8228c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 8238c2ecf20Sopenharmony_ci int val, int val2, long mask) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct si1133_data *data = iio_priv(iio_dev); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci switch (mask) { 8288c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 8298c2ecf20Sopenharmony_ci switch (chan->type) { 8308c2ecf20Sopenharmony_ci case IIO_INTENSITY: 8318c2ecf20Sopenharmony_ci case IIO_UVINDEX: 8328c2ecf20Sopenharmony_ci val = si1133_scale_to_swgain(val, val2); 8338c2ecf20Sopenharmony_ci if (val < 0) 8348c2ecf20Sopenharmony_ci return val; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return si1133_update_adcsens(data, 8378c2ecf20Sopenharmony_ci SI1133_ADCSENS_SCALE_MASK, 8388c2ecf20Sopenharmony_ci SI1133_ADCSENS_SCALE_SHIFT, 8398c2ecf20Sopenharmony_ci val); 8408c2ecf20Sopenharmony_ci default: 8418c2ecf20Sopenharmony_ci return -EINVAL; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 8448c2ecf20Sopenharmony_ci return si1133_set_integration_time(data, 0, val, val2); 8458c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_HARDWAREGAIN: 8468c2ecf20Sopenharmony_ci switch (chan->type) { 8478c2ecf20Sopenharmony_ci case IIO_INTENSITY: 8488c2ecf20Sopenharmony_ci case IIO_UVINDEX: 8498c2ecf20Sopenharmony_ci if (val != 0 && val != 1) 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci return si1133_update_adcsens(data, 8538c2ecf20Sopenharmony_ci SI1133_ADCSENS_HSIG_MASK, 8548c2ecf20Sopenharmony_ci SI1133_ADCSENS_HSIG_SHIFT, 8558c2ecf20Sopenharmony_ci val); 8568c2ecf20Sopenharmony_ci default: 8578c2ecf20Sopenharmony_ci return -EINVAL; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci default: 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic struct attribute *si1133_attributes[] = { 8658c2ecf20Sopenharmony_ci &iio_const_attr_integration_time_available.dev_attr.attr, 8668c2ecf20Sopenharmony_ci &iio_const_attr_scale_available.dev_attr.attr, 8678c2ecf20Sopenharmony_ci NULL, 8688c2ecf20Sopenharmony_ci}; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic const struct attribute_group si1133_attribute_group = { 8718c2ecf20Sopenharmony_ci .attrs = si1133_attributes, 8728c2ecf20Sopenharmony_ci}; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic const struct iio_info si1133_info = { 8758c2ecf20Sopenharmony_ci .read_raw = si1133_read_raw, 8768c2ecf20Sopenharmony_ci .write_raw = si1133_write_raw, 8778c2ecf20Sopenharmony_ci .attrs = &si1133_attribute_group, 8788c2ecf20Sopenharmony_ci}; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci/* 8818c2ecf20Sopenharmony_ci * si1133_init_lux_channels - Configure 3 different channels(adc) (1,2 and 3) 8828c2ecf20Sopenharmony_ci * The channel configuration for the lux measurement was taken from : 8838c2ecf20Sopenharmony_ci * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00578 8848c2ecf20Sopenharmony_ci * 8858c2ecf20Sopenharmony_ci * Reserved the channel 0 for the other raw measurements 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_cistatic int si1133_init_lux_channels(struct si1133_data *data) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci int err; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci err = si1133_chan_set_adcconfig(data, 1, 8928c2ecf20Sopenharmony_ci SI1133_ADCCONFIG_DECIM_RATE(1) | 8938c2ecf20Sopenharmony_ci SI1133_PARAM_ADCMUX_LARGE_WHITE); 8948c2ecf20Sopenharmony_ci if (err) 8958c2ecf20Sopenharmony_ci return err; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(1), 8988c2ecf20Sopenharmony_ci SI1133_ADCPOST_24BIT_EN | 8998c2ecf20Sopenharmony_ci SI1133_ADCPOST_POSTSHIFT_BITQTY(0)); 9008c2ecf20Sopenharmony_ci if (err) 9018c2ecf20Sopenharmony_ci return err; 9028c2ecf20Sopenharmony_ci err = si1133_chan_set_adcsens(data, 1, SI1133_ADCSENS_HSIG_MASK | 9038c2ecf20Sopenharmony_ci SI1133_ADCSENS_NB_MEAS(64) | _48_8_us); 9048c2ecf20Sopenharmony_ci if (err) 9058c2ecf20Sopenharmony_ci return err; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci err = si1133_chan_set_adcconfig(data, 2, 9088c2ecf20Sopenharmony_ci SI1133_ADCCONFIG_DECIM_RATE(1) | 9098c2ecf20Sopenharmony_ci SI1133_PARAM_ADCMUX_LARGE_WHITE); 9108c2ecf20Sopenharmony_ci if (err) 9118c2ecf20Sopenharmony_ci return err; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(2), 9148c2ecf20Sopenharmony_ci SI1133_ADCPOST_24BIT_EN | 9158c2ecf20Sopenharmony_ci SI1133_ADCPOST_POSTSHIFT_BITQTY(2)); 9168c2ecf20Sopenharmony_ci if (err) 9178c2ecf20Sopenharmony_ci return err; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci err = si1133_chan_set_adcsens(data, 2, SI1133_ADCSENS_HSIG_MASK | 9208c2ecf20Sopenharmony_ci SI1133_ADCSENS_NB_MEAS(1) | _3_120_0_us); 9218c2ecf20Sopenharmony_ci if (err) 9228c2ecf20Sopenharmony_ci return err; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci err = si1133_chan_set_adcconfig(data, 3, 9258c2ecf20Sopenharmony_ci SI1133_ADCCONFIG_DECIM_RATE(1) | 9268c2ecf20Sopenharmony_ci SI1133_PARAM_ADCMUX_MED_IR); 9278c2ecf20Sopenharmony_ci if (err) 9288c2ecf20Sopenharmony_ci return err; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(3), 9318c2ecf20Sopenharmony_ci SI1133_ADCPOST_24BIT_EN | 9328c2ecf20Sopenharmony_ci SI1133_ADCPOST_POSTSHIFT_BITQTY(2)); 9338c2ecf20Sopenharmony_ci if (err) 9348c2ecf20Sopenharmony_ci return err; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return si1133_chan_set_adcsens(data, 3, SI1133_ADCSENS_HSIG_MASK | 9378c2ecf20Sopenharmony_ci SI1133_ADCSENS_NB_MEAS(64) | _48_8_us); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int si1133_initialize(struct si1133_data *data) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci int err; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci err = si1133_cmd_reset_sw(data); 9458c2ecf20Sopenharmony_ci if (err) 9468c2ecf20Sopenharmony_ci return err; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* Turn off autonomous mode */ 9498c2ecf20Sopenharmony_ci err = si1133_param_set(data, SI1133_REG_MEAS_RATE, 0); 9508c2ecf20Sopenharmony_ci if (err) 9518c2ecf20Sopenharmony_ci return err; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci err = si1133_init_lux_channels(data); 9548c2ecf20Sopenharmony_ci if (err) 9558c2ecf20Sopenharmony_ci return err; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 9588c2ecf20Sopenharmony_ci SI1133_IRQ_CHANNEL_ENABLE); 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic int si1133_validate_ids(struct iio_dev *iio_dev) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci struct si1133_data *data = iio_priv(iio_dev); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci unsigned int part_id, rev_id, mfr_id; 9668c2ecf20Sopenharmony_ci int err; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, SI1133_REG_PART_ID, &part_id); 9698c2ecf20Sopenharmony_ci if (err) 9708c2ecf20Sopenharmony_ci return err; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, SI1133_REG_REV_ID, &rev_id); 9738c2ecf20Sopenharmony_ci if (err) 9748c2ecf20Sopenharmony_ci return err; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci err = regmap_read(data->regmap, SI1133_REG_MFR_ID, &mfr_id); 9778c2ecf20Sopenharmony_ci if (err) 9788c2ecf20Sopenharmony_ci return err; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci dev_info(&iio_dev->dev, 9818c2ecf20Sopenharmony_ci "Device ID part %#02hhx rev %#02hhx mfr %#02hhx\n", 9828c2ecf20Sopenharmony_ci part_id, rev_id, mfr_id); 9838c2ecf20Sopenharmony_ci if (part_id != SI1133_PART_ID) { 9848c2ecf20Sopenharmony_ci dev_err(&iio_dev->dev, 9858c2ecf20Sopenharmony_ci "Part ID mismatch got %#02hhx, expected %#02x\n", 9868c2ecf20Sopenharmony_ci part_id, SI1133_PART_ID); 9878c2ecf20Sopenharmony_ci return -ENODEV; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic int si1133_probe(struct i2c_client *client, 9948c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci struct si1133_data *data; 9978c2ecf20Sopenharmony_ci struct iio_dev *iio_dev; 9988c2ecf20Sopenharmony_ci int err; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 10018c2ecf20Sopenharmony_ci if (!iio_dev) 10028c2ecf20Sopenharmony_ci return -ENOMEM; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci data = iio_priv(iio_dev); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci init_completion(&data->completion); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &si1133_regmap_config); 10098c2ecf20Sopenharmony_ci if (IS_ERR(data->regmap)) { 10108c2ecf20Sopenharmony_ci err = PTR_ERR(data->regmap); 10118c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to initialise regmap: %d\n", err); 10128c2ecf20Sopenharmony_ci return err; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci i2c_set_clientdata(client, iio_dev); 10168c2ecf20Sopenharmony_ci data->client = client; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci iio_dev->name = id->name; 10198c2ecf20Sopenharmony_ci iio_dev->channels = si1133_channels; 10208c2ecf20Sopenharmony_ci iio_dev->num_channels = ARRAY_SIZE(si1133_channels); 10218c2ecf20Sopenharmony_ci iio_dev->info = &si1133_info; 10228c2ecf20Sopenharmony_ci iio_dev->modes = INDIO_DIRECT_MODE; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci mutex_init(&data->mutex); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci err = si1133_validate_ids(iio_dev); 10278c2ecf20Sopenharmony_ci if (err) 10288c2ecf20Sopenharmony_ci return err; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci err = si1133_initialize(data); 10318c2ecf20Sopenharmony_ci if (err) { 10328c2ecf20Sopenharmony_ci dev_err(&client->dev, 10338c2ecf20Sopenharmony_ci "Error when initializing chip: %d\n", err); 10348c2ecf20Sopenharmony_ci return err; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (!client->irq) { 10388c2ecf20Sopenharmony_ci dev_err(&client->dev, 10398c2ecf20Sopenharmony_ci "Required interrupt not provided, cannot proceed\n"); 10408c2ecf20Sopenharmony_ci return -EINVAL; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci err = devm_request_threaded_irq(&client->dev, client->irq, 10448c2ecf20Sopenharmony_ci NULL, 10458c2ecf20Sopenharmony_ci si1133_threaded_irq_handler, 10468c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED, 10478c2ecf20Sopenharmony_ci client->name, iio_dev); 10488c2ecf20Sopenharmony_ci if (err) { 10498c2ecf20Sopenharmony_ci dev_warn(&client->dev, "Request irq %d failed: %i\n", 10508c2ecf20Sopenharmony_ci client->irq, err); 10518c2ecf20Sopenharmony_ci return err; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return devm_iio_device_register(&client->dev, iio_dev); 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic const struct i2c_device_id si1133_ids[] = { 10588c2ecf20Sopenharmony_ci { "si1133", 0 }, 10598c2ecf20Sopenharmony_ci { } 10608c2ecf20Sopenharmony_ci}; 10618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, si1133_ids); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_cistatic struct i2c_driver si1133_driver = { 10648c2ecf20Sopenharmony_ci .driver = { 10658c2ecf20Sopenharmony_ci .name = "si1133", 10668c2ecf20Sopenharmony_ci }, 10678c2ecf20Sopenharmony_ci .probe = si1133_probe, 10688c2ecf20Sopenharmony_ci .id_table = si1133_ids, 10698c2ecf20Sopenharmony_ci}; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cimodule_i2c_driver(si1133_driver); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); 10748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Silabs SI1133, UV index sensor and ambient light sensor driver"); 10758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1076