1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * CM3323 - Capella Color Light Sensor 4 * 5 * Copyright (c) 2015, Intel Corporation. 6 * 7 * IIO driver for CM3323 (7-bit I2C slave address 0x10) 8 * 9 * TODO: calibscale to correct the lens factor 10 */ 11 #include <linux/module.h> 12 #include <linux/init.h> 13 #include <linux/i2c.h> 14 #include <linux/mutex.h> 15 16 #include <linux/iio/iio.h> 17 #include <linux/iio/sysfs.h> 18 19 #define CM3323_DRV_NAME "cm3323" 20 21 #define CM3323_CMD_CONF 0x00 22 #define CM3323_CMD_RED_DATA 0x08 23 #define CM3323_CMD_GREEN_DATA 0x09 24 #define CM3323_CMD_BLUE_DATA 0x0A 25 #define CM3323_CMD_CLEAR_DATA 0x0B 26 27 #define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */ 28 #define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */ 29 #define CM3323_CONF_IT_MASK GENMASK(6, 4) 30 #define CM3323_CONF_IT_SHIFT 4 31 32 #define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28" 33 34 static const struct { 35 int val; 36 int val2; 37 } cm3323_int_time[] = { 38 {0, 40000}, /* 40 ms */ 39 {0, 80000}, /* 80 ms */ 40 {0, 160000}, /* 160 ms */ 41 {0, 320000}, /* 320 ms */ 42 {0, 640000}, /* 640 ms */ 43 {1, 280000}, /* 1280 ms */ 44 }; 45 46 struct cm3323_data { 47 struct i2c_client *client; 48 u16 reg_conf; 49 struct mutex mutex; 50 }; 51 52 #define CM3323_COLOR_CHANNEL(_color, _addr) { \ 53 .type = IIO_INTENSITY, \ 54 .modified = 1, \ 55 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 56 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ 57 .channel2 = IIO_MOD_LIGHT_##_color, \ 58 .address = _addr, \ 59 } 60 61 static const struct iio_chan_spec cm3323_channels[] = { 62 CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA), 63 CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA), 64 CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA), 65 CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA), 66 }; 67 68 static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE); 69 70 static struct attribute *cm3323_attributes[] = { 71 &iio_const_attr_integration_time_available.dev_attr.attr, 72 NULL 73 }; 74 75 static const struct attribute_group cm3323_attribute_group = { 76 .attrs = cm3323_attributes, 77 }; 78 79 static int cm3323_init(struct iio_dev *indio_dev) 80 { 81 int ret; 82 struct cm3323_data *data = iio_priv(indio_dev); 83 84 ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF); 85 if (ret < 0) { 86 dev_err(&data->client->dev, "Error reading reg_conf\n"); 87 return ret; 88 } 89 90 /* enable sensor and set auto force mode */ 91 ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT); 92 93 ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret); 94 if (ret < 0) { 95 dev_err(&data->client->dev, "Error writing reg_conf\n"); 96 return ret; 97 } 98 99 data->reg_conf = ret; 100 101 return 0; 102 } 103 104 static void cm3323_disable(void *data) 105 { 106 int ret; 107 struct iio_dev *indio_dev = data; 108 struct cm3323_data *cm_data = iio_priv(indio_dev); 109 110 ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF, 111 CM3323_CONF_SD_BIT); 112 if (ret < 0) 113 dev_err(&cm_data->client->dev, "Error writing reg_conf\n"); 114 } 115 116 static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2) 117 { 118 int i, ret; 119 u16 reg_conf; 120 121 for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) { 122 if (val == cm3323_int_time[i].val && 123 val2 == cm3323_int_time[i].val2) { 124 reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK; 125 reg_conf |= i << CM3323_CONF_IT_SHIFT; 126 127 ret = i2c_smbus_write_word_data(data->client, 128 CM3323_CMD_CONF, 129 reg_conf); 130 if (ret < 0) 131 return ret; 132 133 data->reg_conf = reg_conf; 134 135 return 0; 136 } 137 } 138 139 return -EINVAL; 140 } 141 142 static int cm3323_get_it_bits(struct cm3323_data *data) 143 { 144 int bits; 145 146 bits = (data->reg_conf & CM3323_CONF_IT_MASK) >> 147 CM3323_CONF_IT_SHIFT; 148 149 if (bits >= ARRAY_SIZE(cm3323_int_time)) 150 return -EINVAL; 151 152 return bits; 153 } 154 155 static int cm3323_read_raw(struct iio_dev *indio_dev, 156 struct iio_chan_spec const *chan, int *val, 157 int *val2, long mask) 158 { 159 int ret; 160 struct cm3323_data *data = iio_priv(indio_dev); 161 162 switch (mask) { 163 case IIO_CHAN_INFO_RAW: 164 mutex_lock(&data->mutex); 165 ret = i2c_smbus_read_word_data(data->client, chan->address); 166 if (ret < 0) { 167 mutex_unlock(&data->mutex); 168 return ret; 169 } 170 *val = ret; 171 mutex_unlock(&data->mutex); 172 173 return IIO_VAL_INT; 174 case IIO_CHAN_INFO_INT_TIME: 175 mutex_lock(&data->mutex); 176 ret = cm3323_get_it_bits(data); 177 if (ret < 0) { 178 mutex_unlock(&data->mutex); 179 return ret; 180 } 181 182 *val = cm3323_int_time[ret].val; 183 *val2 = cm3323_int_time[ret].val2; 184 mutex_unlock(&data->mutex); 185 186 return IIO_VAL_INT_PLUS_MICRO; 187 default: 188 return -EINVAL; 189 } 190 } 191 192 static int cm3323_write_raw(struct iio_dev *indio_dev, 193 struct iio_chan_spec const *chan, int val, 194 int val2, long mask) 195 { 196 struct cm3323_data *data = iio_priv(indio_dev); 197 int ret; 198 199 switch (mask) { 200 case IIO_CHAN_INFO_INT_TIME: 201 mutex_lock(&data->mutex); 202 ret = cm3323_set_it_bits(data, val, val2); 203 mutex_unlock(&data->mutex); 204 205 return ret; 206 default: 207 return -EINVAL; 208 } 209 } 210 211 static const struct iio_info cm3323_info = { 212 .read_raw = cm3323_read_raw, 213 .write_raw = cm3323_write_raw, 214 .attrs = &cm3323_attribute_group, 215 }; 216 217 static int cm3323_probe(struct i2c_client *client, 218 const struct i2c_device_id *id) 219 { 220 struct cm3323_data *data; 221 struct iio_dev *indio_dev; 222 int ret; 223 224 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 225 if (!indio_dev) 226 return -ENOMEM; 227 228 data = iio_priv(indio_dev); 229 i2c_set_clientdata(client, indio_dev); 230 data->client = client; 231 232 mutex_init(&data->mutex); 233 234 indio_dev->info = &cm3323_info; 235 indio_dev->name = CM3323_DRV_NAME; 236 indio_dev->channels = cm3323_channels; 237 indio_dev->num_channels = ARRAY_SIZE(cm3323_channels); 238 indio_dev->modes = INDIO_DIRECT_MODE; 239 240 ret = cm3323_init(indio_dev); 241 if (ret < 0) { 242 dev_err(&client->dev, "cm3323 chip init failed\n"); 243 return ret; 244 } 245 246 ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev); 247 if (ret < 0) 248 return ret; 249 250 return devm_iio_device_register(&client->dev, indio_dev); 251 } 252 253 static const struct i2c_device_id cm3323_id[] = { 254 {"cm3323", 0}, 255 {} 256 }; 257 MODULE_DEVICE_TABLE(i2c, cm3323_id); 258 259 static const struct of_device_id cm3323_of_match[] = { 260 { .compatible = "capella,cm3323", }, 261 { /* sentinel */ } 262 }; 263 MODULE_DEVICE_TABLE(of, cm3323_of_match); 264 265 static struct i2c_driver cm3323_driver = { 266 .driver = { 267 .name = CM3323_DRV_NAME, 268 .of_match_table = cm3323_of_match, 269 }, 270 .probe = cm3323_probe, 271 .id_table = cm3323_id, 272 }; 273 274 module_i2c_driver(cm3323_driver); 275 276 MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); 277 MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver"); 278 MODULE_LICENSE("GPL v2"); 279