1*971672c0SKevin Tsai /* 2*971672c0SKevin Tsai * Copyright (C) 2013 Capella Microsystems Inc. 3*971672c0SKevin Tsai * Author: Kevin Tsai <ktsai@capellamicro.com> 4*971672c0SKevin Tsai * 5*971672c0SKevin Tsai * This program is free software; you can redistribute it and/or modify it 6*971672c0SKevin Tsai * under the terms of the GNU General Public License version 2, as published 7*971672c0SKevin Tsai * by the Free Software Foundation. 8*971672c0SKevin Tsai */ 9*971672c0SKevin Tsai 10*971672c0SKevin Tsai #include <linux/delay.h> 11*971672c0SKevin Tsai #include <linux/err.h> 12*971672c0SKevin Tsai #include <linux/i2c.h> 13*971672c0SKevin Tsai #include <linux/mutex.h> 14*971672c0SKevin Tsai #include <linux/module.h> 15*971672c0SKevin Tsai #include <linux/interrupt.h> 16*971672c0SKevin Tsai #include <linux/regulator/consumer.h> 17*971672c0SKevin Tsai #include <linux/iio/iio.h> 18*971672c0SKevin Tsai #include <linux/iio/sysfs.h> 19*971672c0SKevin Tsai #include <linux/iio/events.h> 20*971672c0SKevin Tsai #include <linux/init.h> 21*971672c0SKevin Tsai 22*971672c0SKevin Tsai /* Registers Address */ 23*971672c0SKevin Tsai #define CM32181_REG_ADDR_CMD 0x00 24*971672c0SKevin Tsai #define CM32181_REG_ADDR_ALS 0x04 25*971672c0SKevin Tsai #define CM32181_REG_ADDR_STATUS 0x06 26*971672c0SKevin Tsai #define CM32181_REG_ADDR_ID 0x07 27*971672c0SKevin Tsai 28*971672c0SKevin Tsai /* Number of Configurable Registers */ 29*971672c0SKevin Tsai #define CM32181_CONF_REG_NUM 0x01 30*971672c0SKevin Tsai 31*971672c0SKevin Tsai /* CMD register */ 32*971672c0SKevin Tsai #define CM32181_CMD_ALS_ENABLE 0x00 33*971672c0SKevin Tsai #define CM32181_CMD_ALS_DISABLE 0x01 34*971672c0SKevin Tsai #define CM32181_CMD_ALS_INT_EN 0x02 35*971672c0SKevin Tsai 36*971672c0SKevin Tsai #define CM32181_CMD_ALS_IT_SHIFT 6 37*971672c0SKevin Tsai #define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT) 38*971672c0SKevin Tsai #define CM32181_CMD_ALS_IT_DEFAULT (0x00 << CM32181_CMD_ALS_IT_SHIFT) 39*971672c0SKevin Tsai 40*971672c0SKevin Tsai #define CM32181_CMD_ALS_SM_SHIFT 11 41*971672c0SKevin Tsai #define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT) 42*971672c0SKevin Tsai #define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT) 43*971672c0SKevin Tsai 44*971672c0SKevin Tsai #define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */ 45*971672c0SKevin Tsai #define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */ 46*971672c0SKevin Tsai #define CM32181_CALIBSCALE_DEFAULT 1000 47*971672c0SKevin Tsai #define CM32181_CALIBSCALE_RESOLUTION 1000 48*971672c0SKevin Tsai #define MLUX_PER_LUX 1000 49*971672c0SKevin Tsai 50*971672c0SKevin Tsai static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = { 51*971672c0SKevin Tsai CM32181_REG_ADDR_CMD, 52*971672c0SKevin Tsai }; 53*971672c0SKevin Tsai 54*971672c0SKevin Tsai static const int als_it_bits[] = {12, 8, 0, 1, 2, 3}; 55*971672c0SKevin Tsai static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000, 56*971672c0SKevin Tsai 800000}; 57*971672c0SKevin Tsai 58*971672c0SKevin Tsai struct cm32181_chip { 59*971672c0SKevin Tsai struct i2c_client *client; 60*971672c0SKevin Tsai struct mutex lock; 61*971672c0SKevin Tsai u16 conf_regs[CM32181_CONF_REG_NUM]; 62*971672c0SKevin Tsai int calibscale; 63*971672c0SKevin Tsai }; 64*971672c0SKevin Tsai 65*971672c0SKevin Tsai /** 66*971672c0SKevin Tsai * cm32181_reg_init() - Initialize CM32181 registers 67*971672c0SKevin Tsai * @cm32181: pointer of struct cm32181. 68*971672c0SKevin Tsai * 69*971672c0SKevin Tsai * Initialize CM32181 ambient light sensor register to default values. 70*971672c0SKevin Tsai * 71*971672c0SKevin Tsai * Return: 0 for success; otherwise for error code. 72*971672c0SKevin Tsai */ 73*971672c0SKevin Tsai static int cm32181_reg_init(struct cm32181_chip *cm32181) 74*971672c0SKevin Tsai { 75*971672c0SKevin Tsai struct i2c_client *client = cm32181->client; 76*971672c0SKevin Tsai int i; 77*971672c0SKevin Tsai s32 ret; 78*971672c0SKevin Tsai 79*971672c0SKevin Tsai ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID); 80*971672c0SKevin Tsai if (ret < 0) 81*971672c0SKevin Tsai return ret; 82*971672c0SKevin Tsai 83*971672c0SKevin Tsai /* check device ID */ 84*971672c0SKevin Tsai if ((ret & 0xFF) != 0x81) 85*971672c0SKevin Tsai return -ENODEV; 86*971672c0SKevin Tsai 87*971672c0SKevin Tsai /* Default Values */ 88*971672c0SKevin Tsai cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE | 89*971672c0SKevin Tsai CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT; 90*971672c0SKevin Tsai cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT; 91*971672c0SKevin Tsai 92*971672c0SKevin Tsai /* Initialize registers*/ 93*971672c0SKevin Tsai for (i = 0; i < CM32181_CONF_REG_NUM; i++) { 94*971672c0SKevin Tsai ret = i2c_smbus_write_word_data(client, cm32181_reg[i], 95*971672c0SKevin Tsai cm32181->conf_regs[i]); 96*971672c0SKevin Tsai if (ret < 0) 97*971672c0SKevin Tsai return ret; 98*971672c0SKevin Tsai } 99*971672c0SKevin Tsai 100*971672c0SKevin Tsai return 0; 101*971672c0SKevin Tsai } 102*971672c0SKevin Tsai 103*971672c0SKevin Tsai /** 104*971672c0SKevin Tsai * cm32181_read_als_it() - Get sensor integration time (ms) 105*971672c0SKevin Tsai * @cm32181: pointer of struct cm32181 106*971672c0SKevin Tsai * @val: pointer of int to load the als_it value. 107*971672c0SKevin Tsai * 108*971672c0SKevin Tsai * Report the current integartion time by millisecond. 109*971672c0SKevin Tsai * 110*971672c0SKevin Tsai * Return: IIO_VAL_INT for success, otherwise -EINVAL. 111*971672c0SKevin Tsai */ 112*971672c0SKevin Tsai static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val) 113*971672c0SKevin Tsai { 114*971672c0SKevin Tsai u16 als_it; 115*971672c0SKevin Tsai int i; 116*971672c0SKevin Tsai 117*971672c0SKevin Tsai als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD]; 118*971672c0SKevin Tsai als_it &= CM32181_CMD_ALS_IT_MASK; 119*971672c0SKevin Tsai als_it >>= CM32181_CMD_ALS_IT_SHIFT; 120*971672c0SKevin Tsai for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) { 121*971672c0SKevin Tsai if (als_it == als_it_bits[i]) { 122*971672c0SKevin Tsai *val = als_it_value[i]; 123*971672c0SKevin Tsai return IIO_VAL_INT; 124*971672c0SKevin Tsai } 125*971672c0SKevin Tsai } 126*971672c0SKevin Tsai 127*971672c0SKevin Tsai return -EINVAL; 128*971672c0SKevin Tsai } 129*971672c0SKevin Tsai 130*971672c0SKevin Tsai /** 131*971672c0SKevin Tsai * cm32181_write_als_it() - Write sensor integration time 132*971672c0SKevin Tsai * @cm32181: pointer of struct cm32181. 133*971672c0SKevin Tsai * @val: integration time by millisecond. 134*971672c0SKevin Tsai * 135*971672c0SKevin Tsai * Convert integration time (ms) to sensor value. 136*971672c0SKevin Tsai * 137*971672c0SKevin Tsai * Return: i2c_smbus_write_word_data command return value. 138*971672c0SKevin Tsai */ 139*971672c0SKevin Tsai static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val) 140*971672c0SKevin Tsai { 141*971672c0SKevin Tsai struct i2c_client *client = cm32181->client; 142*971672c0SKevin Tsai u16 als_it; 143*971672c0SKevin Tsai int ret, i, n; 144*971672c0SKevin Tsai 145*971672c0SKevin Tsai n = ARRAY_SIZE(als_it_value); 146*971672c0SKevin Tsai for (i = 0; i < n; i++) 147*971672c0SKevin Tsai if (val <= als_it_value[i]) 148*971672c0SKevin Tsai break; 149*971672c0SKevin Tsai if (i >= n) 150*971672c0SKevin Tsai i = n - 1; 151*971672c0SKevin Tsai 152*971672c0SKevin Tsai als_it = als_it_bits[i]; 153*971672c0SKevin Tsai als_it <<= CM32181_CMD_ALS_IT_SHIFT; 154*971672c0SKevin Tsai 155*971672c0SKevin Tsai mutex_lock(&cm32181->lock); 156*971672c0SKevin Tsai cm32181->conf_regs[CM32181_REG_ADDR_CMD] &= 157*971672c0SKevin Tsai ~CM32181_CMD_ALS_IT_MASK; 158*971672c0SKevin Tsai cm32181->conf_regs[CM32181_REG_ADDR_CMD] |= 159*971672c0SKevin Tsai als_it; 160*971672c0SKevin Tsai ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD, 161*971672c0SKevin Tsai cm32181->conf_regs[CM32181_REG_ADDR_CMD]); 162*971672c0SKevin Tsai mutex_unlock(&cm32181->lock); 163*971672c0SKevin Tsai 164*971672c0SKevin Tsai return ret; 165*971672c0SKevin Tsai } 166*971672c0SKevin Tsai 167*971672c0SKevin Tsai /** 168*971672c0SKevin Tsai * cm32181_get_lux() - report current lux value 169*971672c0SKevin Tsai * @cm32181: pointer of struct cm32181. 170*971672c0SKevin Tsai * 171*971672c0SKevin Tsai * Convert sensor raw data to lux. It depends on integration 172*971672c0SKevin Tsai * time and claibscale variable. 173*971672c0SKevin Tsai * 174*971672c0SKevin Tsai * Return: Positive value is lux, otherwise is error code. 175*971672c0SKevin Tsai */ 176*971672c0SKevin Tsai static int cm32181_get_lux(struct cm32181_chip *cm32181) 177*971672c0SKevin Tsai { 178*971672c0SKevin Tsai struct i2c_client *client = cm32181->client; 179*971672c0SKevin Tsai int ret; 180*971672c0SKevin Tsai int als_it; 181*971672c0SKevin Tsai unsigned long lux; 182*971672c0SKevin Tsai 183*971672c0SKevin Tsai ret = cm32181_read_als_it(cm32181, &als_it); 184*971672c0SKevin Tsai if (ret < 0) 185*971672c0SKevin Tsai return -EINVAL; 186*971672c0SKevin Tsai 187*971672c0SKevin Tsai lux = CM32181_MLUX_PER_BIT; 188*971672c0SKevin Tsai lux *= CM32181_MLUX_PER_BIT_BASE_IT; 189*971672c0SKevin Tsai lux /= als_it; 190*971672c0SKevin Tsai 191*971672c0SKevin Tsai ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS); 192*971672c0SKevin Tsai if (ret < 0) 193*971672c0SKevin Tsai return ret; 194*971672c0SKevin Tsai 195*971672c0SKevin Tsai lux *= ret; 196*971672c0SKevin Tsai lux *= cm32181->calibscale; 197*971672c0SKevin Tsai lux /= CM32181_CALIBSCALE_RESOLUTION; 198*971672c0SKevin Tsai lux /= MLUX_PER_LUX; 199*971672c0SKevin Tsai 200*971672c0SKevin Tsai if (lux > 0xFFFF) 201*971672c0SKevin Tsai lux = 0xFFFF; 202*971672c0SKevin Tsai 203*971672c0SKevin Tsai return lux; 204*971672c0SKevin Tsai } 205*971672c0SKevin Tsai 206*971672c0SKevin Tsai static int cm32181_read_raw(struct iio_dev *indio_dev, 207*971672c0SKevin Tsai struct iio_chan_spec const *chan, 208*971672c0SKevin Tsai int *val, int *val2, long mask) 209*971672c0SKevin Tsai { 210*971672c0SKevin Tsai struct cm32181_chip *cm32181 = iio_priv(indio_dev); 211*971672c0SKevin Tsai int ret; 212*971672c0SKevin Tsai 213*971672c0SKevin Tsai switch (mask) { 214*971672c0SKevin Tsai case IIO_CHAN_INFO_PROCESSED: 215*971672c0SKevin Tsai ret = cm32181_get_lux(cm32181); 216*971672c0SKevin Tsai if (ret < 0) 217*971672c0SKevin Tsai return ret; 218*971672c0SKevin Tsai *val = ret; 219*971672c0SKevin Tsai return IIO_VAL_INT; 220*971672c0SKevin Tsai case IIO_CHAN_INFO_CALIBSCALE: 221*971672c0SKevin Tsai *val = cm32181->calibscale; 222*971672c0SKevin Tsai return IIO_VAL_INT; 223*971672c0SKevin Tsai case IIO_CHAN_INFO_INT_TIME: 224*971672c0SKevin Tsai ret = cm32181_read_als_it(cm32181, val); 225*971672c0SKevin Tsai return ret; 226*971672c0SKevin Tsai } 227*971672c0SKevin Tsai 228*971672c0SKevin Tsai return -EINVAL; 229*971672c0SKevin Tsai } 230*971672c0SKevin Tsai 231*971672c0SKevin Tsai static int cm32181_write_raw(struct iio_dev *indio_dev, 232*971672c0SKevin Tsai struct iio_chan_spec const *chan, 233*971672c0SKevin Tsai int val, int val2, long mask) 234*971672c0SKevin Tsai { 235*971672c0SKevin Tsai struct cm32181_chip *cm32181 = iio_priv(indio_dev); 236*971672c0SKevin Tsai int ret; 237*971672c0SKevin Tsai 238*971672c0SKevin Tsai switch (mask) { 239*971672c0SKevin Tsai case IIO_CHAN_INFO_CALIBSCALE: 240*971672c0SKevin Tsai cm32181->calibscale = val; 241*971672c0SKevin Tsai return val; 242*971672c0SKevin Tsai case IIO_CHAN_INFO_INT_TIME: 243*971672c0SKevin Tsai ret = cm32181_write_als_it(cm32181, val); 244*971672c0SKevin Tsai return ret; 245*971672c0SKevin Tsai } 246*971672c0SKevin Tsai 247*971672c0SKevin Tsai return -EINVAL; 248*971672c0SKevin Tsai } 249*971672c0SKevin Tsai 250*971672c0SKevin Tsai /** 251*971672c0SKevin Tsai * cm32181_get_it_available() - Get available ALS IT value 252*971672c0SKevin Tsai * @dev: pointer of struct device. 253*971672c0SKevin Tsai * @attr: pointer of struct device_attribute. 254*971672c0SKevin Tsai * @buf: pointer of return string buffer. 255*971672c0SKevin Tsai * 256*971672c0SKevin Tsai * Display the available integration time values by millisecond. 257*971672c0SKevin Tsai * 258*971672c0SKevin Tsai * Return: string length. 259*971672c0SKevin Tsai */ 260*971672c0SKevin Tsai static ssize_t cm32181_get_it_available(struct device *dev, 261*971672c0SKevin Tsai struct device_attribute *attr, char *buf) 262*971672c0SKevin Tsai { 263*971672c0SKevin Tsai int i, n, len; 264*971672c0SKevin Tsai 265*971672c0SKevin Tsai n = ARRAY_SIZE(als_it_value); 266*971672c0SKevin Tsai for (i = 0, len = 0; i < n; i++) 267*971672c0SKevin Tsai len += sprintf(buf + len, "%d ", als_it_value[i]); 268*971672c0SKevin Tsai return len + sprintf(buf + len, "\n"); 269*971672c0SKevin Tsai } 270*971672c0SKevin Tsai 271*971672c0SKevin Tsai static const struct iio_chan_spec cm32181_channels[] = { 272*971672c0SKevin Tsai { 273*971672c0SKevin Tsai .type = IIO_LIGHT, 274*971672c0SKevin Tsai .info_mask_separate = 275*971672c0SKevin Tsai BIT(IIO_CHAN_INFO_PROCESSED) | 276*971672c0SKevin Tsai BIT(IIO_CHAN_INFO_CALIBSCALE) | 277*971672c0SKevin Tsai BIT(IIO_CHAN_INFO_INT_TIME), 278*971672c0SKevin Tsai } 279*971672c0SKevin Tsai }; 280*971672c0SKevin Tsai 281*971672c0SKevin Tsai static IIO_DEVICE_ATTR(in_illuminance_integration_time_available, 282*971672c0SKevin Tsai S_IRUGO, cm32181_get_it_available, NULL, 0); 283*971672c0SKevin Tsai 284*971672c0SKevin Tsai static struct attribute *cm32181_attributes[] = { 285*971672c0SKevin Tsai &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr, 286*971672c0SKevin Tsai NULL, 287*971672c0SKevin Tsai }; 288*971672c0SKevin Tsai 289*971672c0SKevin Tsai static const struct attribute_group cm32181_attribute_group = { 290*971672c0SKevin Tsai .attrs = cm32181_attributes 291*971672c0SKevin Tsai }; 292*971672c0SKevin Tsai 293*971672c0SKevin Tsai static const struct iio_info cm32181_info = { 294*971672c0SKevin Tsai .driver_module = THIS_MODULE, 295*971672c0SKevin Tsai .read_raw = &cm32181_read_raw, 296*971672c0SKevin Tsai .write_raw = &cm32181_write_raw, 297*971672c0SKevin Tsai .attrs = &cm32181_attribute_group, 298*971672c0SKevin Tsai }; 299*971672c0SKevin Tsai 300*971672c0SKevin Tsai static int cm32181_probe(struct i2c_client *client, 301*971672c0SKevin Tsai const struct i2c_device_id *id) 302*971672c0SKevin Tsai { 303*971672c0SKevin Tsai struct cm32181_chip *cm32181; 304*971672c0SKevin Tsai struct iio_dev *indio_dev; 305*971672c0SKevin Tsai int ret; 306*971672c0SKevin Tsai 307*971672c0SKevin Tsai indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181)); 308*971672c0SKevin Tsai if (!indio_dev) { 309*971672c0SKevin Tsai dev_err(&client->dev, "devm_iio_device_alloc failed\n"); 310*971672c0SKevin Tsai return -ENOMEM; 311*971672c0SKevin Tsai } 312*971672c0SKevin Tsai 313*971672c0SKevin Tsai cm32181 = iio_priv(indio_dev); 314*971672c0SKevin Tsai i2c_set_clientdata(client, indio_dev); 315*971672c0SKevin Tsai cm32181->client = client; 316*971672c0SKevin Tsai 317*971672c0SKevin Tsai mutex_init(&cm32181->lock); 318*971672c0SKevin Tsai indio_dev->dev.parent = &client->dev; 319*971672c0SKevin Tsai indio_dev->channels = cm32181_channels; 320*971672c0SKevin Tsai indio_dev->num_channels = ARRAY_SIZE(cm32181_channels); 321*971672c0SKevin Tsai indio_dev->info = &cm32181_info; 322*971672c0SKevin Tsai indio_dev->name = id->name; 323*971672c0SKevin Tsai indio_dev->modes = INDIO_DIRECT_MODE; 324*971672c0SKevin Tsai 325*971672c0SKevin Tsai ret = cm32181_reg_init(cm32181); 326*971672c0SKevin Tsai if (ret) { 327*971672c0SKevin Tsai dev_err(&client->dev, 328*971672c0SKevin Tsai "%s: register init failed\n", 329*971672c0SKevin Tsai __func__); 330*971672c0SKevin Tsai return ret; 331*971672c0SKevin Tsai } 332*971672c0SKevin Tsai 333*971672c0SKevin Tsai ret = iio_device_register(indio_dev); 334*971672c0SKevin Tsai if (ret) { 335*971672c0SKevin Tsai dev_err(&client->dev, 336*971672c0SKevin Tsai "%s: regist device failed\n", 337*971672c0SKevin Tsai __func__); 338*971672c0SKevin Tsai return ret; 339*971672c0SKevin Tsai } 340*971672c0SKevin Tsai 341*971672c0SKevin Tsai return 0; 342*971672c0SKevin Tsai } 343*971672c0SKevin Tsai 344*971672c0SKevin Tsai static int cm32181_remove(struct i2c_client *client) 345*971672c0SKevin Tsai { 346*971672c0SKevin Tsai struct iio_dev *indio_dev = i2c_get_clientdata(client); 347*971672c0SKevin Tsai 348*971672c0SKevin Tsai iio_device_unregister(indio_dev); 349*971672c0SKevin Tsai return 0; 350*971672c0SKevin Tsai } 351*971672c0SKevin Tsai 352*971672c0SKevin Tsai static const struct i2c_device_id cm32181_id[] = { 353*971672c0SKevin Tsai { "cm32181", 0 }, 354*971672c0SKevin Tsai { } 355*971672c0SKevin Tsai }; 356*971672c0SKevin Tsai 357*971672c0SKevin Tsai MODULE_DEVICE_TABLE(i2c, cm32181_id); 358*971672c0SKevin Tsai 359*971672c0SKevin Tsai static const struct of_device_id cm32181_of_match[] = { 360*971672c0SKevin Tsai { .compatible = "capella,cm32181" }, 361*971672c0SKevin Tsai { } 362*971672c0SKevin Tsai }; 363*971672c0SKevin Tsai 364*971672c0SKevin Tsai static struct i2c_driver cm32181_driver = { 365*971672c0SKevin Tsai .driver = { 366*971672c0SKevin Tsai .name = "cm32181", 367*971672c0SKevin Tsai .of_match_table = of_match_ptr(cm32181_of_match), 368*971672c0SKevin Tsai .owner = THIS_MODULE, 369*971672c0SKevin Tsai }, 370*971672c0SKevin Tsai .id_table = cm32181_id, 371*971672c0SKevin Tsai .probe = cm32181_probe, 372*971672c0SKevin Tsai .remove = cm32181_remove, 373*971672c0SKevin Tsai }; 374*971672c0SKevin Tsai 375*971672c0SKevin Tsai module_i2c_driver(cm32181_driver); 376*971672c0SKevin Tsai 377*971672c0SKevin Tsai MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>"); 378*971672c0SKevin Tsai MODULE_DESCRIPTION("CM32181 ambient light sensor driver"); 379*971672c0SKevin Tsai MODULE_LICENSE("GPL"); 380