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