^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) * zopt2201.c - Support for IDT ZOPT2201 ambient light and UV B sensor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Datasheet: https://www.idt.com/document/dst/zopt2201-datasheet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * 7-bit I2C slave addresses 0x53 (default) or 0x52 (programmed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * TODO: interrupt support, ALS/UVB raw mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/iio/iio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/iio/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define ZOPT2201_DRV_NAME "zopt2201"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define ZOPT2201_MAIN_CTRL 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define ZOPT2201_LS_MEAS_RATE 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define ZOPT2201_LS_GAIN 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define ZOPT2201_PART_ID 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define ZOPT2201_MAIN_STATUS 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define ZOPT2201_ALS_DATA 0x0d /* LSB first, 13 to 20 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define ZOPT2201_UVB_DATA 0x10 /* LSB first, 13 to 20 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define ZOPT2201_UV_COMP_DATA 0x13 /* LSB first, 13 to 20 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define ZOPT2201_COMP_DATA 0x16 /* LSB first, 13 to 20 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define ZOPT2201_INT_CFG 0x19
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define ZOPT2201_INT_PST 0x1a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define ZOPT2201_MAIN_CTRL_LS_MODE BIT(3) /* 0 .. ALS, 1 .. UV B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define ZOPT2201_MAIN_CTRL_LS_EN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Values for ZOPT2201_LS_MEAS_RATE resolution / bit width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define ZOPT2201_MEAS_RES_20BIT 0 /* takes 400 ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define ZOPT2201_MEAS_RES_19BIT 1 /* takes 200 ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define ZOPT2201_MEAS_RES_18BIT 2 /* takes 100 ms, default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define ZOPT2201_MEAS_RES_17BIT 3 /* takes 50 ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define ZOPT2201_MEAS_RES_16BIT 4 /* takes 25 ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define ZOPT2201_MEAS_RES_13BIT 5 /* takes 3.125 ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define ZOPT2201_MEAS_RES_SHIFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* Values for ZOPT2201_LS_MEAS_RATE measurement rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define ZOPT2201_MEAS_FREQ_25MS 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define ZOPT2201_MEAS_FREQ_50MS 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define ZOPT2201_MEAS_FREQ_100MS 2 /* default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define ZOPT2201_MEAS_FREQ_200MS 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define ZOPT2201_MEAS_FREQ_500MS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define ZOPT2201_MEAS_FREQ_1000MS 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define ZOPT2201_MEAS_FREQ_2000MS 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* Values for ZOPT2201_LS_GAIN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define ZOPT2201_LS_GAIN_1 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define ZOPT2201_LS_GAIN_3 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define ZOPT2201_LS_GAIN_6 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define ZOPT2201_LS_GAIN_9 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define ZOPT2201_LS_GAIN_18 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* Values for ZOPT2201_MAIN_STATUS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define ZOPT2201_MAIN_STATUS_POWERON BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define ZOPT2201_MAIN_STATUS_INT BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define ZOPT2201_MAIN_STATUS_DRDY BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define ZOPT2201_PART_NUMBER 0xb2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct zopt2201_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u8 gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u8 res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u8 rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned int gain; /* gain factor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned int scale; /* micro lux per count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) } zopt2201_gain_als[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) { 1, 19200000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) { 3, 6400000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) { 6, 3200000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) { 9, 2133333 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) { 18, 1066666 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) unsigned int gain; /* gain factor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) unsigned int scale; /* micro W/m2 per count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) } zopt2201_gain_uvb[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) { 1, 460800 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) { 3, 153600 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) { 6, 76800 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) { 9, 51200 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) { 18, 25600 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unsigned int bits; /* sensor resolution in bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) unsigned long us; /* measurement time in micro seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) } zopt2201_resolution[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) { 20, 400000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) { 19, 200000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) { 18, 100000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) { 17, 50000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) { 16, 25000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) { 13, 3125 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned int scale, uscale; /* scale factor as integer + micro */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) u8 gain; /* gain register value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u8 res; /* resolution register value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) } zopt2201_scale_als[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) { 19, 200000, 0, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) { 6, 400000, 1, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) { 3, 200000, 2, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) { 2, 400000, 0, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) { 2, 133333, 3, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) { 1, 200000, 0, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) { 1, 66666, 4, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) { 0, 800000, 1, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) { 0, 600000, 0, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) { 0, 400000, 2, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) { 0, 300000, 0, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) { 0, 266666, 3, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) { 0, 200000, 2, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) { 0, 150000, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) { 0, 133333, 4, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) { 0, 100000, 2, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) { 0, 66666, 4, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) { 0, 50000, 2, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) { 0, 33333, 4, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) { 0, 25000, 2, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) { 0, 16666, 4, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) { 0, 8333, 4, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) unsigned int scale, uscale; /* scale factor as integer + micro */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) u8 gain; /* gain register value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) u8 res; /* resolution register value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) } zopt2201_scale_uvb[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) { 0, 460800, 0, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) { 0, 153600, 1, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) { 0, 76800, 2, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) { 0, 57600, 0, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) { 0, 51200, 3, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) { 0, 28800, 0, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) { 0, 25600, 4, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) { 0, 19200, 1, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) { 0, 14400, 0, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) { 0, 9600, 2, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) { 0, 7200, 0, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) { 0, 6400, 3, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) { 0, 4800, 2, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) { 0, 3600, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) { 0, 3200, 4, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) { 0, 2400, 2, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) { 0, 1600, 4, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) { 0, 1200, 2, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) { 0, 800, 4, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) { 0, 600, 2, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) { 0, 400, 4, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) { 0, 200, 4, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int zopt2201_enable_mode(struct zopt2201_data *data, bool uvb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) u8 out = ZOPT2201_MAIN_CTRL_LS_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (uvb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) out |= ZOPT2201_MAIN_CTRL_LS_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return i2c_smbus_write_byte_data(data->client, ZOPT2201_MAIN_CTRL, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int zopt2201_read(struct zopt2201_data *data, u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct i2c_client *client = data->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int tries = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) u8 buf[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) while (tries--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) unsigned long t = zopt2201_resolution[data->res].us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (t <= 20000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) usleep_range(t, t + 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) msleep(t / 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (ret & ZOPT2201_MAIN_STATUS_DRDY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (tries < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return get_unaligned_le24(&buf[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static const struct iio_chan_spec zopt2201_channels[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) .type = IIO_LIGHT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .address = ZOPT2201_ALS_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) BIT(IIO_CHAN_INFO_SCALE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .type = IIO_INTENSITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .modified = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .channel2 = IIO_MOD_LIGHT_UV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .address = ZOPT2201_UVB_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) BIT(IIO_CHAN_INFO_SCALE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .type = IIO_UVINDEX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int zopt2201_read_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) int *val, int *val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct zopt2201_data *data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) u64 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) case IIO_CHAN_INFO_RAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) ret = zopt2201_read(data, chan->address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) *val = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return IIO_VAL_INT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) case IIO_CHAN_INFO_PROCESSED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) ret = zopt2201_read(data, ZOPT2201_UVB_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) *val = ret * 18 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) (1 << (20 - zopt2201_resolution[data->res].bits)) /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) zopt2201_gain_uvb[data->gain].gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return IIO_VAL_INT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) case IIO_CHAN_INFO_SCALE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) switch (chan->address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) case ZOPT2201_ALS_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) *val = zopt2201_gain_als[data->gain].scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) case ZOPT2201_UVB_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) *val = zopt2201_gain_uvb[data->gain].scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) *val2 = 1000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) *val2 *= (1 << (zopt2201_resolution[data->res].bits - 13));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) tmp = div_s64(*val * 1000000ULL, *val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) *val = div_s64_rem(tmp, 1000000, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return IIO_VAL_INT_PLUS_MICRO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) case IIO_CHAN_INFO_INT_TIME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) *val2 = zopt2201_resolution[data->res].us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return IIO_VAL_INT_PLUS_MICRO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_MEAS_RATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) (res << ZOPT2201_MEAS_RES_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) data->rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) data->res = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static int zopt2201_write_resolution(struct zopt2201_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) int val, int val2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (val != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (val2 == zopt2201_resolution[i].us) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) ret = zopt2201_set_resolution(data, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_GAIN, gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) data->gain = gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static int zopt2201_write_scale_als(struct zopt2201_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int val, int val2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (val == zopt2201_scale_als[i].scale &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) val2 == zopt2201_scale_als[i].uscale) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return zopt2201_write_scale_als_by_idx(data, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^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) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int val, int val2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (val == zopt2201_scale_uvb[i].scale &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) val2 == zopt2201_scale_uvb[i].uscale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return zopt2201_write_scale_uvb_by_idx(data, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) static int zopt2201_write_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) int val, int val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) struct zopt2201_data *data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) case IIO_CHAN_INFO_INT_TIME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return zopt2201_write_resolution(data, val, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) case IIO_CHAN_INFO_SCALE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) switch (chan->address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) case ZOPT2201_ALS_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return zopt2201_write_scale_als(data, val, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case ZOPT2201_UVB_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return zopt2201_write_scale_uvb(data, val, val2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static ssize_t zopt2201_show_int_time_available(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06lu ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) zopt2201_resolution[i].us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) buf[len - 1] = '\n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static IIO_DEV_ATTR_INT_TIME_AVAIL(zopt2201_show_int_time_available);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) static ssize_t zopt2201_show_als_scale_avail(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) ssize_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) zopt2201_scale_als[i].scale,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) zopt2201_scale_als[i].uscale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) buf[len - 1] = '\n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) static ssize_t zopt2201_show_uvb_scale_avail(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) ssize_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) zopt2201_scale_uvb[i].scale,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) zopt2201_scale_uvb[i].uscale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) buf[len - 1] = '\n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static IIO_DEVICE_ATTR(in_illuminance_scale_available, 0444,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) zopt2201_show_als_scale_avail, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static IIO_DEVICE_ATTR(in_intensity_uv_scale_available, 0444,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) zopt2201_show_uvb_scale_avail, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static struct attribute *zopt2201_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) &iio_dev_attr_integration_time_available.dev_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) &iio_dev_attr_in_illuminance_scale_available.dev_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) &iio_dev_attr_in_intensity_uv_scale_available.dev_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static const struct attribute_group zopt2201_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) .attrs = zopt2201_attributes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static const struct iio_info zopt2201_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .read_raw = zopt2201_read_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .write_raw = zopt2201_write_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) .attrs = &zopt2201_attribute_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static int zopt2201_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) struct zopt2201_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct iio_dev *indio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (!i2c_check_functionality(client->adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) I2C_FUNC_SMBUS_READ_I2C_BLOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) ret = i2c_smbus_read_byte_data(client, ZOPT2201_PART_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (ret != ZOPT2201_PART_NUMBER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (!indio_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) i2c_set_clientdata(client, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) data->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) mutex_init(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) indio_dev->info = &zopt2201_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) indio_dev->channels = zopt2201_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) indio_dev->num_channels = ARRAY_SIZE(zopt2201_channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) indio_dev->name = ZOPT2201_DRV_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) indio_dev->modes = INDIO_DIRECT_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) data->rate = ZOPT2201_MEAS_FREQ_100MS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) ret = zopt2201_set_resolution(data, ZOPT2201_MEAS_RES_18BIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) ret = zopt2201_set_gain(data, ZOPT2201_LS_GAIN_3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return devm_iio_device_register(&client->dev, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) static const struct i2c_device_id zopt2201_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) { "zopt2201", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) MODULE_DEVICE_TABLE(i2c, zopt2201_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) static struct i2c_driver zopt2201_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) .name = ZOPT2201_DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) .probe = zopt2201_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) .id_table = zopt2201_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) module_i2c_driver(zopt2201_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) MODULE_DESCRIPTION("IDT ZOPT2201 ambient light and UV B sensor driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) MODULE_LICENSE("GPL");