^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * CM3232 Ambient Light Sensor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2014-2015 Capella Microsystems Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Kevin Tsai <ktsai@capellamicro.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * IIO driver for CM3232 (7-bit I2C slave address 0x10).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/iio/iio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/iio/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /* Registers Address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define CM3232_REG_ADDR_CMD 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define CM3232_REG_ADDR_ALS 0x50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define CM3232_REG_ADDR_ID 0x53
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CM3232_CMD_ALS_DISABLE BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define CM3232_CMD_ALS_IT_SHIFT 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define CM3232_CMD_ALS_IT_MASK (BIT(2) | BIT(3) | BIT(4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define CM3232_CMD_ALS_IT_DEFAULT (0x01 << CM3232_CMD_ALS_IT_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define CM3232_CMD_ALS_RESET BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define CM3232_CMD_DEFAULT CM3232_CMD_ALS_IT_DEFAULT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define CM3232_HW_ID 0x32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define CM3232_CALIBSCALE_DEFAULT 100000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define CM3232_CALIBSCALE_RESOLUTION 100000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define CM3232_MLUX_PER_LUX 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CM3232_MLUX_PER_BIT_DEFAULT 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define CM3232_MLUX_PER_BIT_BASE_IT 100000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int val2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u8 it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) } cm3232_als_it_scales[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {0, 100000, 0}, /* 0.100000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {0, 200000, 1}, /* 0.200000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {0, 400000, 2}, /* 0.400000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {0, 800000, 3}, /* 0.800000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {1, 600000, 4}, /* 1.600000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {3, 200000, 5}, /* 3.200000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct cm3232_als_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u8 regs_cmd_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) u8 hw_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int calibscale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int mlux_per_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int mlux_per_bit_base_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static struct cm3232_als_info cm3232_als_info_default = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .regs_cmd_default = CM3232_CMD_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .hw_id = CM3232_HW_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .calibscale = CM3232_CALIBSCALE_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .mlux_per_bit = CM3232_MLUX_PER_BIT_DEFAULT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .mlux_per_bit_base_it = CM3232_MLUX_PER_BIT_BASE_IT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct cm3232_chip {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct cm3232_als_info *als_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u8 regs_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u16 regs_als;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * cm3232_reg_init() - Initialize CM3232
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * @chip: pointer of struct cm3232_chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * Check and initialize CM3232 ambient light sensor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * Return: 0 for success; otherwise for error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int cm3232_reg_init(struct cm3232_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct i2c_client *client = chip->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) s32 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) chip->als_info = &cm3232_als_info_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* Identify device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) dev_err(&chip->client->dev, "Error reading addr_id\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if ((ret & 0xFF) != chip->als_info->hw_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* Disable and reset device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) chip->regs_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) dev_err(&chip->client->dev, "Error writing reg_cmd\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* Register default value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) chip->regs_cmd = chip->als_info->regs_cmd_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Configure register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) chip->regs_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) dev_err(&chip->client->dev, "Error writing reg_cmd\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * cm3232_read_als_it() - Get sensor integration time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * @chip: pointer of struct cm3232_chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * @val: pointer of int to load the integration (sec).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * @val2: pointer of int to load the integration time (microsecond).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Report the current integration time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int cm3232_read_als_it(struct cm3232_chip *chip, int *val, int *val2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) u16 als_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) als_it = chip->regs_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) als_it &= CM3232_CMD_ALS_IT_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) als_it >>= CM3232_CMD_ALS_IT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (als_it == cm3232_als_it_scales[i].it) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) *val = cm3232_als_it_scales[i].val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) *val2 = cm3232_als_it_scales[i].val2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return IIO_VAL_INT_PLUS_MICRO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * cm3232_write_als_it() - Write sensor integration time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @chip: pointer of struct cm3232_chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * @val: integration time in second.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * @val2: integration time in microsecond.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * Convert integration time to sensor value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * Return: i2c_smbus_write_byte_data command return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static int cm3232_write_als_it(struct cm3232_chip *chip, int val, int val2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct i2c_client *client = chip->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u16 als_it, cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) s32 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (val == cm3232_als_it_scales[i].val &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) val2 == cm3232_als_it_scales[i].val2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) als_it = cm3232_als_it_scales[i].it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) als_it <<= CM3232_CMD_ALS_IT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) cmd = chip->regs_cmd & ~CM3232_CMD_ALS_IT_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) cmd |= als_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) ret = i2c_smbus_write_byte_data(client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) CM3232_REG_ADDR_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) chip->regs_cmd = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * cm3232_get_lux() - report current lux value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * @chip: pointer of struct cm3232_chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * Convert sensor data to lux. It depends on integration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * time and calibscale variable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * Return: Zero or positive value is lux, otherwise error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static int cm3232_get_lux(struct cm3232_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct i2c_client *client = chip->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct cm3232_als_info *als_info = chip->als_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) int val, val2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int als_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) u64 lux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* Calculate mlux per bit based on als_it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ret = cm3232_read_als_it(chip, &val, &val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) als_it = val * 1000000 + val2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) lux = (__force u64)als_info->mlux_per_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) lux *= als_info->mlux_per_bit_base_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) lux = div_u64(lux, als_it);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ALS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) dev_err(&client->dev, "Error reading reg_addr_als\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) chip->regs_als = (u16)ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) lux *= chip->regs_als;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) lux *= als_info->calibscale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) lux = div_u64(lux, CM3232_CALIBSCALE_RESOLUTION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) lux = div_u64(lux, CM3232_MLUX_PER_LUX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (lux > 0xFFFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) lux = 0xFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return (int)lux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static int cm3232_read_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) int *val, int *val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct cm3232_chip *chip = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct cm3232_als_info *als_info = chip->als_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) case IIO_CHAN_INFO_PROCESSED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) ret = cm3232_get_lux(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *val = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return IIO_VAL_INT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case IIO_CHAN_INFO_CALIBSCALE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) *val = als_info->calibscale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return IIO_VAL_INT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) case IIO_CHAN_INFO_INT_TIME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return cm3232_read_als_it(chip, val, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static int cm3232_write_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) int val, int val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct cm3232_chip *chip = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct cm3232_als_info *als_info = chip->als_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) case IIO_CHAN_INFO_CALIBSCALE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) als_info->calibscale = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) case IIO_CHAN_INFO_INT_TIME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return cm3232_write_als_it(chip, val, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * cm3232_get_it_available() - Get available ALS IT value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * @dev: pointer of struct device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * @attr: pointer of struct device_attribute.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * @buf: pointer of return string buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * Display the available integration time in second.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * Return: string length.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) static ssize_t cm3232_get_it_available(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int i, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) for (i = 0, len = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) cm3232_als_it_scales[i].val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) cm3232_als_it_scales[i].val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static const struct iio_chan_spec cm3232_channels[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .type = IIO_LIGHT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .info_mask_separate =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) BIT(IIO_CHAN_INFO_PROCESSED) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) BIT(IIO_CHAN_INFO_CALIBSCALE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) BIT(IIO_CHAN_INFO_INT_TIME),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) S_IRUGO, cm3232_get_it_available, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static struct attribute *cm3232_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static const struct attribute_group cm3232_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .attrs = cm3232_attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static const struct iio_info cm3232_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .read_raw = &cm3232_read_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .write_raw = &cm3232_write_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .attrs = &cm3232_attribute_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static int cm3232_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct cm3232_chip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct iio_dev *indio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (!indio_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) chip = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) i2c_set_clientdata(client, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) chip->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) indio_dev->channels = cm3232_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) indio_dev->num_channels = ARRAY_SIZE(cm3232_channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) indio_dev->info = &cm3232_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) indio_dev->name = id->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) indio_dev->modes = INDIO_DIRECT_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) ret = cm3232_reg_init(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) "%s: register init failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return iio_device_register(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static int cm3232_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct iio_dev *indio_dev = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) CM3232_CMD_ALS_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) iio_device_unregister(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) static const struct i2c_device_id cm3232_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {"cm3232", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static int cm3232_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) struct cm3232_chip *chip = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) struct i2c_client *client = chip->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) chip->regs_cmd |= CM3232_CMD_ALS_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) chip->regs_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static int cm3232_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct cm3232_chip *chip = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct i2c_client *client = chip->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) chip->regs_cmd &= ~CM3232_CMD_ALS_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) chip->regs_cmd | CM3232_CMD_ALS_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) static const struct dev_pm_ops cm3232_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) SET_SYSTEM_SLEEP_PM_OPS(cm3232_suspend, cm3232_resume)};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) MODULE_DEVICE_TABLE(i2c, cm3232_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static const struct of_device_id cm3232_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) {.compatible = "capella,cm3232"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) MODULE_DEVICE_TABLE(of, cm3232_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) static struct i2c_driver cm3232_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) .name = "cm3232",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) .of_match_table = cm3232_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) .pm = &cm3232_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) .id_table = cm3232_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .probe = cm3232_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .remove = cm3232_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) module_i2c_driver(cm3232_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) MODULE_DESCRIPTION("CM3232 ambient light sensor driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) MODULE_LICENSE("GPL");