18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Capella Microsystems Inc. 48c2ecf20Sopenharmony_ci * Author: Kevin Tsai <ktsai@capellamicro.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/acpi.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/mutex.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 178c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 188c2ecf20Sopenharmony_ci#include <linux/iio/events.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Registers Address */ 228c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_CMD 0x00 238c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_WH 0x01 248c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_WL 0x02 258c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_TEST 0x03 268c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_ALS 0x04 278c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_STATUS 0x06 288c2ecf20Sopenharmony_ci#define CM32181_REG_ADDR_ID 0x07 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Number of Configurable Registers */ 318c2ecf20Sopenharmony_ci#define CM32181_CONF_REG_NUM 4 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* CMD register */ 348c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_DISABLE BIT(0) 358c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_INT_EN BIT(1) 368c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_THRES_WINDOW BIT(2) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_PERS_SHIFT 4 398c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_PERS_MASK (0x03 << CM32181_CMD_ALS_PERS_SHIFT) 408c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_PERS_DEFAULT (0x01 << CM32181_CMD_ALS_PERS_SHIFT) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_IT_SHIFT 6 438c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT) 448c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_IT_DEFAULT (0x00 << CM32181_CMD_ALS_IT_SHIFT) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_SM_SHIFT 11 478c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT) 488c2ecf20Sopenharmony_ci#define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define CM32181_LUX_PER_BIT 500 /* ALS_SM=01 IT=800ms */ 518c2ecf20Sopenharmony_ci#define CM32181_LUX_PER_BIT_RESOLUTION 100000 528c2ecf20Sopenharmony_ci#define CM32181_LUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */ 538c2ecf20Sopenharmony_ci#define CM32181_CALIBSCALE_DEFAULT 100000 548c2ecf20Sopenharmony_ci#define CM32181_CALIBSCALE_RESOLUTION 100000 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define SMBUS_ALERT_RESPONSE_ADDRESS 0x0c 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* CPM0 Index 0: device-id (3218 or 32181), 1: Unknown, 2: init_regs_bitmap */ 598c2ecf20Sopenharmony_ci#define CPM0_REGS_BITMAP 2 608c2ecf20Sopenharmony_ci#define CPM0_HEADER_SIZE 3 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* CPM1 Index 0: lux_per_bit, 1: calibscale, 2: resolution (100000) */ 638c2ecf20Sopenharmony_ci#define CPM1_LUX_PER_BIT 0 648c2ecf20Sopenharmony_ci#define CPM1_CALIBSCALE 1 658c2ecf20Sopenharmony_ci#define CPM1_SIZE 3 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* CM3218 Family */ 688c2ecf20Sopenharmony_cistatic const int cm3218_als_it_bits[] = { 0, 1, 2, 3 }; 698c2ecf20Sopenharmony_cistatic const int cm3218_als_it_values[] = { 100000, 200000, 400000, 800000 }; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* CM32181 Family */ 728c2ecf20Sopenharmony_cistatic const int cm32181_als_it_bits[] = { 12, 8, 0, 1, 2, 3 }; 738c2ecf20Sopenharmony_cistatic const int cm32181_als_it_values[] = { 748c2ecf20Sopenharmony_ci 25000, 50000, 100000, 200000, 400000, 800000 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct cm32181_chip { 788c2ecf20Sopenharmony_ci struct i2c_client *client; 798c2ecf20Sopenharmony_ci struct device *dev; 808c2ecf20Sopenharmony_ci struct mutex lock; 818c2ecf20Sopenharmony_ci u16 conf_regs[CM32181_CONF_REG_NUM]; 828c2ecf20Sopenharmony_ci unsigned long init_regs_bitmap; 838c2ecf20Sopenharmony_ci int calibscale; 848c2ecf20Sopenharmony_ci int lux_per_bit; 858c2ecf20Sopenharmony_ci int lux_per_bit_base_it; 868c2ecf20Sopenharmony_ci int num_als_it; 878c2ecf20Sopenharmony_ci const int *als_it_bits; 888c2ecf20Sopenharmony_ci const int *als_it_values; 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * cm32181_acpi_get_cpm() - Get CPM object from ACPI 968c2ecf20Sopenharmony_ci * @dev: pointer of struct device. 978c2ecf20Sopenharmony_ci * @obj_name: pointer of ACPI object name. 988c2ecf20Sopenharmony_ci * @values: pointer of array for return elements. 998c2ecf20Sopenharmony_ci * @count: maximum size of return array. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * Convert ACPI CPM table to array. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Return: -ENODEV for fail. Otherwise is number of elements. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic int cm32181_acpi_get_cpm(struct device *dev, char *obj_name, 1068c2ecf20Sopenharmony_ci u64 *values, int count) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 1098c2ecf20Sopenharmony_ci union acpi_object *cpm, *elem; 1108c2ecf20Sopenharmony_ci acpi_handle handle; 1118c2ecf20Sopenharmony_ci acpi_status status; 1128c2ecf20Sopenharmony_ci int i; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci handle = ACPI_HANDLE(dev); 1158c2ecf20Sopenharmony_ci if (!handle) 1168c2ecf20Sopenharmony_ci return -ENODEV; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, obj_name, NULL, &buffer); 1198c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 1208c2ecf20Sopenharmony_ci dev_err(dev, "object %s not found\n", obj_name); 1218c2ecf20Sopenharmony_ci return -ENODEV; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci cpm = buffer.pointer; 1258c2ecf20Sopenharmony_ci if (cpm->package.count > count) 1268c2ecf20Sopenharmony_ci dev_warn(dev, "%s table contains %u values, only using first %d values\n", 1278c2ecf20Sopenharmony_ci obj_name, cpm->package.count, count); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci count = min_t(int, cpm->package.count, count); 1308c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 1318c2ecf20Sopenharmony_ci elem = &(cpm->package.elements[i]); 1328c2ecf20Sopenharmony_ci values[i] = elem->integer.value; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci kfree(buffer.pointer); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return count; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void cm32181_acpi_parse_cpm_tables(struct cm32181_chip *cm32181) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci u64 vals[CPM0_HEADER_SIZE + CM32181_CONF_REG_NUM]; 1438c2ecf20Sopenharmony_ci struct device *dev = cm32181->dev; 1448c2ecf20Sopenharmony_ci int i, count; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci count = cm32181_acpi_get_cpm(dev, "CPM0", vals, ARRAY_SIZE(vals)); 1478c2ecf20Sopenharmony_ci if (count <= CPM0_HEADER_SIZE) 1488c2ecf20Sopenharmony_ci return; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci count -= CPM0_HEADER_SIZE; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci cm32181->init_regs_bitmap = vals[CPM0_REGS_BITMAP]; 1538c2ecf20Sopenharmony_ci cm32181->init_regs_bitmap &= GENMASK(count - 1, 0); 1548c2ecf20Sopenharmony_ci for_each_set_bit(i, &cm32181->init_regs_bitmap, count) 1558c2ecf20Sopenharmony_ci cm32181->conf_regs[i] = vals[CPM0_HEADER_SIZE + i]; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci count = cm32181_acpi_get_cpm(dev, "CPM1", vals, ARRAY_SIZE(vals)); 1588c2ecf20Sopenharmony_ci if (count != CPM1_SIZE) 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci cm32181->lux_per_bit = vals[CPM1_LUX_PER_BIT]; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Check for uncalibrated devices */ 1648c2ecf20Sopenharmony_ci if (vals[CPM1_CALIBSCALE] == CM32181_CALIBSCALE_DEFAULT) 1658c2ecf20Sopenharmony_ci return; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci cm32181->calibscale = vals[CPM1_CALIBSCALE]; 1688c2ecf20Sopenharmony_ci /* CPM1 lux_per_bit is for the current it value */ 1698c2ecf20Sopenharmony_ci cm32181_read_als_it(cm32181, &cm32181->lux_per_bit_base_it); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci#else 1728c2ecf20Sopenharmony_cistatic void cm32181_acpi_parse_cpm_tables(struct cm32181_chip *cm32181) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/** 1788c2ecf20Sopenharmony_ci * cm32181_reg_init() - Initialize CM32181 registers 1798c2ecf20Sopenharmony_ci * @cm32181: pointer of struct cm32181. 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * Initialize CM32181 ambient light sensor register to default values. 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * Return: 0 for success; otherwise for error code. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_cistatic int cm32181_reg_init(struct cm32181_chip *cm32181) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct i2c_client *client = cm32181->client; 1888c2ecf20Sopenharmony_ci int i; 1898c2ecf20Sopenharmony_ci s32 ret; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID); 1928c2ecf20Sopenharmony_ci if (ret < 0) 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* check device ID */ 1968c2ecf20Sopenharmony_ci switch (ret & 0xFF) { 1978c2ecf20Sopenharmony_ci case 0x18: /* CM3218 */ 1988c2ecf20Sopenharmony_ci cm32181->num_als_it = ARRAY_SIZE(cm3218_als_it_bits); 1998c2ecf20Sopenharmony_ci cm32181->als_it_bits = cm3218_als_it_bits; 2008c2ecf20Sopenharmony_ci cm32181->als_it_values = cm3218_als_it_values; 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci case 0x81: /* CM32181 */ 2038c2ecf20Sopenharmony_ci case 0x82: /* CM32182, fully compat. with CM32181 */ 2048c2ecf20Sopenharmony_ci cm32181->num_als_it = ARRAY_SIZE(cm32181_als_it_bits); 2058c2ecf20Sopenharmony_ci cm32181->als_it_bits = cm32181_als_it_bits; 2068c2ecf20Sopenharmony_ci cm32181->als_it_values = cm32181_als_it_values; 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci default: 2098c2ecf20Sopenharmony_ci return -ENODEV; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Default Values */ 2138c2ecf20Sopenharmony_ci cm32181->conf_regs[CM32181_REG_ADDR_CMD] = 2148c2ecf20Sopenharmony_ci CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT; 2158c2ecf20Sopenharmony_ci cm32181->init_regs_bitmap = BIT(CM32181_REG_ADDR_CMD); 2168c2ecf20Sopenharmony_ci cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT; 2178c2ecf20Sopenharmony_ci cm32181->lux_per_bit = CM32181_LUX_PER_BIT; 2188c2ecf20Sopenharmony_ci cm32181->lux_per_bit_base_it = CM32181_LUX_PER_BIT_BASE_IT; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (ACPI_HANDLE(cm32181->dev)) 2218c2ecf20Sopenharmony_ci cm32181_acpi_parse_cpm_tables(cm32181); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Initialize registers*/ 2248c2ecf20Sopenharmony_ci for_each_set_bit(i, &cm32181->init_regs_bitmap, CM32181_CONF_REG_NUM) { 2258c2ecf20Sopenharmony_ci ret = i2c_smbus_write_word_data(client, i, 2268c2ecf20Sopenharmony_ci cm32181->conf_regs[i]); 2278c2ecf20Sopenharmony_ci if (ret < 0) 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/** 2358c2ecf20Sopenharmony_ci * cm32181_read_als_it() - Get sensor integration time (ms) 2368c2ecf20Sopenharmony_ci * @cm32181: pointer of struct cm32181 2378c2ecf20Sopenharmony_ci * @val2: pointer of int to load the als_it value. 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Report the current integration time in milliseconds. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci u16 als_it; 2468c2ecf20Sopenharmony_ci int i; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD]; 2498c2ecf20Sopenharmony_ci als_it &= CM32181_CMD_ALS_IT_MASK; 2508c2ecf20Sopenharmony_ci als_it >>= CM32181_CMD_ALS_IT_SHIFT; 2518c2ecf20Sopenharmony_ci for (i = 0; i < cm32181->num_als_it; i++) { 2528c2ecf20Sopenharmony_ci if (als_it == cm32181->als_it_bits[i]) { 2538c2ecf20Sopenharmony_ci *val2 = cm32181->als_it_values[i]; 2548c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return -EINVAL; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/** 2628c2ecf20Sopenharmony_ci * cm32181_write_als_it() - Write sensor integration time 2638c2ecf20Sopenharmony_ci * @cm32181: pointer of struct cm32181. 2648c2ecf20Sopenharmony_ci * @val: integration time by millisecond. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Convert integration time (ms) to sensor value. 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Return: i2c_smbus_write_word_data command return value. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_cistatic int cm32181_write_als_it(struct cm32181_chip *cm32181, int val) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct i2c_client *client = cm32181->client; 2738c2ecf20Sopenharmony_ci u16 als_it; 2748c2ecf20Sopenharmony_ci int ret, i, n; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci n = cm32181->num_als_it; 2778c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 2788c2ecf20Sopenharmony_ci if (val <= cm32181->als_it_values[i]) 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci if (i >= n) 2818c2ecf20Sopenharmony_ci i = n - 1; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci als_it = cm32181->als_it_bits[i]; 2848c2ecf20Sopenharmony_ci als_it <<= CM32181_CMD_ALS_IT_SHIFT; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci mutex_lock(&cm32181->lock); 2878c2ecf20Sopenharmony_ci cm32181->conf_regs[CM32181_REG_ADDR_CMD] &= 2888c2ecf20Sopenharmony_ci ~CM32181_CMD_ALS_IT_MASK; 2898c2ecf20Sopenharmony_ci cm32181->conf_regs[CM32181_REG_ADDR_CMD] |= 2908c2ecf20Sopenharmony_ci als_it; 2918c2ecf20Sopenharmony_ci ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD, 2928c2ecf20Sopenharmony_ci cm32181->conf_regs[CM32181_REG_ADDR_CMD]); 2938c2ecf20Sopenharmony_ci mutex_unlock(&cm32181->lock); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/** 2998c2ecf20Sopenharmony_ci * cm32181_get_lux() - report current lux value 3008c2ecf20Sopenharmony_ci * @cm32181: pointer of struct cm32181. 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * Convert sensor raw data to lux. It depends on integration 3038c2ecf20Sopenharmony_ci * time and calibscale variable. 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * Return: Positive value is lux, otherwise is error code. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistatic int cm32181_get_lux(struct cm32181_chip *cm32181) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct i2c_client *client = cm32181->client; 3108c2ecf20Sopenharmony_ci int ret; 3118c2ecf20Sopenharmony_ci int als_it; 3128c2ecf20Sopenharmony_ci u64 lux; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ret = cm32181_read_als_it(cm32181, &als_it); 3158c2ecf20Sopenharmony_ci if (ret < 0) 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci lux = cm32181->lux_per_bit; 3198c2ecf20Sopenharmony_ci lux *= cm32181->lux_per_bit_base_it; 3208c2ecf20Sopenharmony_ci lux = div_u64(lux, als_it); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS); 3238c2ecf20Sopenharmony_ci if (ret < 0) 3248c2ecf20Sopenharmony_ci return ret; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci lux *= ret; 3278c2ecf20Sopenharmony_ci lux *= cm32181->calibscale; 3288c2ecf20Sopenharmony_ci lux = div_u64(lux, CM32181_CALIBSCALE_RESOLUTION); 3298c2ecf20Sopenharmony_ci lux = div_u64(lux, CM32181_LUX_PER_BIT_RESOLUTION); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (lux > 0xFFFF) 3328c2ecf20Sopenharmony_ci lux = 0xFFFF; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return lux; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int cm32181_read_raw(struct iio_dev *indio_dev, 3388c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3398c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct cm32181_chip *cm32181 = iio_priv(indio_dev); 3428c2ecf20Sopenharmony_ci int ret; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci switch (mask) { 3458c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_PROCESSED: 3468c2ecf20Sopenharmony_ci ret = cm32181_get_lux(cm32181); 3478c2ecf20Sopenharmony_ci if (ret < 0) 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci *val = ret; 3508c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3518c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBSCALE: 3528c2ecf20Sopenharmony_ci *val = cm32181->calibscale; 3538c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3548c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 3558c2ecf20Sopenharmony_ci *val = 0; 3568c2ecf20Sopenharmony_ci ret = cm32181_read_als_it(cm32181, val2); 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return -EINVAL; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int cm32181_write_raw(struct iio_dev *indio_dev, 3648c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3658c2ecf20Sopenharmony_ci int val, int val2, long mask) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct cm32181_chip *cm32181 = iio_priv(indio_dev); 3688c2ecf20Sopenharmony_ci int ret; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci switch (mask) { 3718c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBSCALE: 3728c2ecf20Sopenharmony_ci cm32181->calibscale = val; 3738c2ecf20Sopenharmony_ci return val; 3748c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 3758c2ecf20Sopenharmony_ci ret = cm32181_write_als_it(cm32181, val2); 3768c2ecf20Sopenharmony_ci return ret; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return -EINVAL; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/** 3838c2ecf20Sopenharmony_ci * cm32181_get_it_available() - Get available ALS IT value 3848c2ecf20Sopenharmony_ci * @dev: pointer of struct device. 3858c2ecf20Sopenharmony_ci * @attr: pointer of struct device_attribute. 3868c2ecf20Sopenharmony_ci * @buf: pointer of return string buffer. 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci * Display the available integration time values by millisecond. 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * Return: string length. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic ssize_t cm32181_get_it_available(struct device *dev, 3938c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct cm32181_chip *cm32181 = iio_priv(dev_to_iio_dev(dev)); 3968c2ecf20Sopenharmony_ci int i, n, len; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci n = cm32181->num_als_it; 3998c2ecf20Sopenharmony_ci for (i = 0, len = 0; i < n; i++) 4008c2ecf20Sopenharmony_ci len += sprintf(buf + len, "0.%06u ", cm32181->als_it_values[i]); 4018c2ecf20Sopenharmony_ci return len + sprintf(buf + len, "\n"); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic const struct iio_chan_spec cm32181_channels[] = { 4058c2ecf20Sopenharmony_ci { 4068c2ecf20Sopenharmony_ci .type = IIO_LIGHT, 4078c2ecf20Sopenharmony_ci .info_mask_separate = 4088c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_PROCESSED) | 4098c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_CALIBSCALE) | 4108c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_INT_TIME), 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(in_illuminance_integration_time_available, 4158c2ecf20Sopenharmony_ci S_IRUGO, cm32181_get_it_available, NULL, 0); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic struct attribute *cm32181_attributes[] = { 4188c2ecf20Sopenharmony_ci &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr, 4198c2ecf20Sopenharmony_ci NULL, 4208c2ecf20Sopenharmony_ci}; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic const struct attribute_group cm32181_attribute_group = { 4238c2ecf20Sopenharmony_ci .attrs = cm32181_attributes 4248c2ecf20Sopenharmony_ci}; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic const struct iio_info cm32181_info = { 4278c2ecf20Sopenharmony_ci .read_raw = &cm32181_read_raw, 4288c2ecf20Sopenharmony_ci .write_raw = &cm32181_write_raw, 4298c2ecf20Sopenharmony_ci .attrs = &cm32181_attribute_group, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void cm32181_unregister_dummy_client(void *data) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct i2c_client *client = data; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Unregister the dummy client */ 4378c2ecf20Sopenharmony_ci i2c_unregister_device(client); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int cm32181_probe(struct i2c_client *client) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 4438c2ecf20Sopenharmony_ci struct cm32181_chip *cm32181; 4448c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 4458c2ecf20Sopenharmony_ci int ret; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*cm32181)); 4488c2ecf20Sopenharmony_ci if (!indio_dev) 4498c2ecf20Sopenharmony_ci return -ENOMEM; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* 4528c2ecf20Sopenharmony_ci * Some ACPI systems list 2 I2C resources for the CM3218 sensor, the 4538c2ecf20Sopenharmony_ci * SMBus Alert Response Address (ARA, 0x0c) and the actual I2C address. 4548c2ecf20Sopenharmony_ci * Detect this and take the following step to deal with it: 4558c2ecf20Sopenharmony_ci * 1. When a SMBus Alert capable sensor has an Alert asserted, it will 4568c2ecf20Sopenharmony_ci * not respond on its actual I2C address. Read a byte from the ARA 4578c2ecf20Sopenharmony_ci * to clear any pending Alerts. 4588c2ecf20Sopenharmony_ci * 2. Create a "dummy" client for the actual I2C address and 4598c2ecf20Sopenharmony_ci * use that client to communicate with the sensor. 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ci if (ACPI_HANDLE(dev) && client->addr == SMBUS_ALERT_RESPONSE_ADDRESS) { 4628c2ecf20Sopenharmony_ci struct i2c_board_info board_info = { .type = "dummy" }; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci i2c_smbus_read_byte(client); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci client = i2c_acpi_new_device(dev, 1, &board_info); 4678c2ecf20Sopenharmony_ci if (IS_ERR(client)) 4688c2ecf20Sopenharmony_ci return PTR_ERR(client); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, cm32181_unregister_dummy_client, client); 4718c2ecf20Sopenharmony_ci if (ret) 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci cm32181 = iio_priv(indio_dev); 4768c2ecf20Sopenharmony_ci cm32181->client = client; 4778c2ecf20Sopenharmony_ci cm32181->dev = dev; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci mutex_init(&cm32181->lock); 4808c2ecf20Sopenharmony_ci indio_dev->channels = cm32181_channels; 4818c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(cm32181_channels); 4828c2ecf20Sopenharmony_ci indio_dev->info = &cm32181_info; 4838c2ecf20Sopenharmony_ci indio_dev->name = dev_name(dev); 4848c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci ret = cm32181_reg_init(cm32181); 4878c2ecf20Sopenharmony_ci if (ret) { 4888c2ecf20Sopenharmony_ci dev_err(dev, "%s: register init failed\n", __func__); 4898c2ecf20Sopenharmony_ci return ret; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ret = devm_iio_device_register(dev, indio_dev); 4938c2ecf20Sopenharmony_ci if (ret) { 4948c2ecf20Sopenharmony_ci dev_err(dev, "%s: regist device failed\n", __func__); 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic const struct of_device_id cm32181_of_match[] = { 5028c2ecf20Sopenharmony_ci { .compatible = "capella,cm3218" }, 5038c2ecf20Sopenharmony_ci { .compatible = "capella,cm32181" }, 5048c2ecf20Sopenharmony_ci { } 5058c2ecf20Sopenharmony_ci}; 5068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cm32181_of_match); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 5098c2ecf20Sopenharmony_cistatic const struct acpi_device_id cm32181_acpi_match[] = { 5108c2ecf20Sopenharmony_ci { "CPLM3218", 0 }, 5118c2ecf20Sopenharmony_ci { } 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, cm32181_acpi_match); 5148c2ecf20Sopenharmony_ci#endif 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic struct i2c_driver cm32181_driver = { 5178c2ecf20Sopenharmony_ci .driver = { 5188c2ecf20Sopenharmony_ci .name = "cm32181", 5198c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(cm32181_acpi_match), 5208c2ecf20Sopenharmony_ci .of_match_table = cm32181_of_match, 5218c2ecf20Sopenharmony_ci }, 5228c2ecf20Sopenharmony_ci .probe_new = cm32181_probe, 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cimodule_i2c_driver(cm32181_driver); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>"); 5288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CM32181 ambient light sensor driver"); 5298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 530