1*1f0477f1SLinus Walleij /* 2*1f0477f1SLinus Walleij * ROHM 1780GLI Ambient Light Sensor Driver 3*1f0477f1SLinus Walleij * 4*1f0477f1SLinus Walleij * Copyright (C) 2016 Linaro Ltd. 5*1f0477f1SLinus Walleij * Author: Linus Walleij <linus.walleij@linaro.org> 6*1f0477f1SLinus Walleij * Loosely based on the previous BH1780 ALS misc driver 7*1f0477f1SLinus Walleij * Copyright (C) 2010 Texas Instruments 8*1f0477f1SLinus Walleij * Author: Hemanth V <hemanthv@ti.com> 9*1f0477f1SLinus Walleij */ 10*1f0477f1SLinus Walleij #include <linux/i2c.h> 11*1f0477f1SLinus Walleij #include <linux/slab.h> 12*1f0477f1SLinus Walleij #include <linux/platform_device.h> 13*1f0477f1SLinus Walleij #include <linux/delay.h> 14*1f0477f1SLinus Walleij #include <linux/module.h> 15*1f0477f1SLinus Walleij #include <linux/of.h> 16*1f0477f1SLinus Walleij #include <linux/pm_runtime.h> 17*1f0477f1SLinus Walleij #include <linux/iio/iio.h> 18*1f0477f1SLinus Walleij #include <linux/iio/sysfs.h> 19*1f0477f1SLinus Walleij #include <linux/bitops.h> 20*1f0477f1SLinus Walleij 21*1f0477f1SLinus Walleij #define BH1780_CMD_BIT BIT(7) 22*1f0477f1SLinus Walleij #define BH1780_REG_CONTROL 0x00 23*1f0477f1SLinus Walleij #define BH1780_REG_PARTID 0x0A 24*1f0477f1SLinus Walleij #define BH1780_REG_MANFID 0x0B 25*1f0477f1SLinus Walleij #define BH1780_REG_DLOW 0x0C 26*1f0477f1SLinus Walleij #define BH1780_REG_DHIGH 0x0D 27*1f0477f1SLinus Walleij 28*1f0477f1SLinus Walleij #define BH1780_REVMASK GENMASK(3,0) 29*1f0477f1SLinus Walleij #define BH1780_POWMASK GENMASK(1,0) 30*1f0477f1SLinus Walleij #define BH1780_POFF (0x0) 31*1f0477f1SLinus Walleij #define BH1780_PON (0x3) 32*1f0477f1SLinus Walleij 33*1f0477f1SLinus Walleij /* power on settling time in ms */ 34*1f0477f1SLinus Walleij #define BH1780_PON_DELAY 2 35*1f0477f1SLinus Walleij /* max time before value available in ms */ 36*1f0477f1SLinus Walleij #define BH1780_INTERVAL 250 37*1f0477f1SLinus Walleij 38*1f0477f1SLinus Walleij struct bh1780_data { 39*1f0477f1SLinus Walleij struct i2c_client *client; 40*1f0477f1SLinus Walleij }; 41*1f0477f1SLinus Walleij 42*1f0477f1SLinus Walleij static int bh1780_write(struct bh1780_data *bh1780, u8 reg, u8 val) 43*1f0477f1SLinus Walleij { 44*1f0477f1SLinus Walleij int ret = i2c_smbus_write_byte_data(bh1780->client, 45*1f0477f1SLinus Walleij BH1780_CMD_BIT | reg, 46*1f0477f1SLinus Walleij val); 47*1f0477f1SLinus Walleij if (ret < 0) 48*1f0477f1SLinus Walleij dev_err(&bh1780->client->dev, 49*1f0477f1SLinus Walleij "i2c_smbus_write_byte_data failed error " 50*1f0477f1SLinus Walleij "%d, register %01x\n", 51*1f0477f1SLinus Walleij ret, reg); 52*1f0477f1SLinus Walleij return ret; 53*1f0477f1SLinus Walleij } 54*1f0477f1SLinus Walleij 55*1f0477f1SLinus Walleij static int bh1780_read(struct bh1780_data *bh1780, u8 reg) 56*1f0477f1SLinus Walleij { 57*1f0477f1SLinus Walleij int ret = i2c_smbus_read_byte_data(bh1780->client, 58*1f0477f1SLinus Walleij BH1780_CMD_BIT | reg); 59*1f0477f1SLinus Walleij if (ret < 0) 60*1f0477f1SLinus Walleij dev_err(&bh1780->client->dev, 61*1f0477f1SLinus Walleij "i2c_smbus_read_byte_data failed error " 62*1f0477f1SLinus Walleij "%d, register %01x\n", 63*1f0477f1SLinus Walleij ret, reg); 64*1f0477f1SLinus Walleij return ret; 65*1f0477f1SLinus Walleij } 66*1f0477f1SLinus Walleij 67*1f0477f1SLinus Walleij static int bh1780_read_word(struct bh1780_data *bh1780, u8 reg) 68*1f0477f1SLinus Walleij { 69*1f0477f1SLinus Walleij int ret = i2c_smbus_read_word_data(bh1780->client, 70*1f0477f1SLinus Walleij BH1780_CMD_BIT | reg); 71*1f0477f1SLinus Walleij if (ret < 0) 72*1f0477f1SLinus Walleij dev_err(&bh1780->client->dev, 73*1f0477f1SLinus Walleij "i2c_smbus_read_word_data failed error " 74*1f0477f1SLinus Walleij "%d, register %01x\n", 75*1f0477f1SLinus Walleij ret, reg); 76*1f0477f1SLinus Walleij return ret; 77*1f0477f1SLinus Walleij } 78*1f0477f1SLinus Walleij 79*1f0477f1SLinus Walleij static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev, 80*1f0477f1SLinus Walleij unsigned int reg, unsigned int writeval, 81*1f0477f1SLinus Walleij unsigned int *readval) 82*1f0477f1SLinus Walleij { 83*1f0477f1SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 84*1f0477f1SLinus Walleij int ret; 85*1f0477f1SLinus Walleij 86*1f0477f1SLinus Walleij if (!readval) 87*1f0477f1SLinus Walleij bh1780_write(bh1780, (u8)reg, (u8)writeval); 88*1f0477f1SLinus Walleij 89*1f0477f1SLinus Walleij ret = bh1780_read(bh1780, (u8)reg); 90*1f0477f1SLinus Walleij if (ret < 0) 91*1f0477f1SLinus Walleij return ret; 92*1f0477f1SLinus Walleij 93*1f0477f1SLinus Walleij *readval = ret; 94*1f0477f1SLinus Walleij 95*1f0477f1SLinus Walleij return 0; 96*1f0477f1SLinus Walleij } 97*1f0477f1SLinus Walleij 98*1f0477f1SLinus Walleij static int bh1780_read_raw(struct iio_dev *indio_dev, 99*1f0477f1SLinus Walleij struct iio_chan_spec const *chan, 100*1f0477f1SLinus Walleij int *val, int *val2, long mask) 101*1f0477f1SLinus Walleij { 102*1f0477f1SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 103*1f0477f1SLinus Walleij int value; 104*1f0477f1SLinus Walleij 105*1f0477f1SLinus Walleij switch (mask) { 106*1f0477f1SLinus Walleij case IIO_CHAN_INFO_RAW: 107*1f0477f1SLinus Walleij switch (chan->type) { 108*1f0477f1SLinus Walleij case IIO_LIGHT: 109*1f0477f1SLinus Walleij pm_runtime_get_sync(&bh1780->client->dev); 110*1f0477f1SLinus Walleij value = bh1780_read_word(bh1780, BH1780_REG_DLOW); 111*1f0477f1SLinus Walleij if (value < 0) 112*1f0477f1SLinus Walleij return value; 113*1f0477f1SLinus Walleij pm_runtime_mark_last_busy(&bh1780->client->dev); 114*1f0477f1SLinus Walleij pm_runtime_put_autosuspend(&bh1780->client->dev); 115*1f0477f1SLinus Walleij *val = value; 116*1f0477f1SLinus Walleij 117*1f0477f1SLinus Walleij return IIO_VAL_INT; 118*1f0477f1SLinus Walleij default: 119*1f0477f1SLinus Walleij return -EINVAL; 120*1f0477f1SLinus Walleij } 121*1f0477f1SLinus Walleij case IIO_CHAN_INFO_INT_TIME: 122*1f0477f1SLinus Walleij *val = 0; 123*1f0477f1SLinus Walleij *val2 = BH1780_INTERVAL * 1000; 124*1f0477f1SLinus Walleij return IIO_VAL_INT_PLUS_MICRO; 125*1f0477f1SLinus Walleij default: 126*1f0477f1SLinus Walleij return -EINVAL; 127*1f0477f1SLinus Walleij } 128*1f0477f1SLinus Walleij } 129*1f0477f1SLinus Walleij 130*1f0477f1SLinus Walleij static const struct iio_info bh1780_info = { 131*1f0477f1SLinus Walleij .driver_module = THIS_MODULE, 132*1f0477f1SLinus Walleij .read_raw = bh1780_read_raw, 133*1f0477f1SLinus Walleij .debugfs_reg_access = bh1780_debugfs_reg_access, 134*1f0477f1SLinus Walleij }; 135*1f0477f1SLinus Walleij 136*1f0477f1SLinus Walleij static const struct iio_chan_spec bh1780_channels[] = { 137*1f0477f1SLinus Walleij { 138*1f0477f1SLinus Walleij .type = IIO_LIGHT, 139*1f0477f1SLinus Walleij .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 140*1f0477f1SLinus Walleij BIT(IIO_CHAN_INFO_INT_TIME) 141*1f0477f1SLinus Walleij } 142*1f0477f1SLinus Walleij }; 143*1f0477f1SLinus Walleij 144*1f0477f1SLinus Walleij static int bh1780_probe(struct i2c_client *client, 145*1f0477f1SLinus Walleij const struct i2c_device_id *id) 146*1f0477f1SLinus Walleij { 147*1f0477f1SLinus Walleij int ret; 148*1f0477f1SLinus Walleij struct bh1780_data *bh1780; 149*1f0477f1SLinus Walleij struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 150*1f0477f1SLinus Walleij struct iio_dev *indio_dev; 151*1f0477f1SLinus Walleij 152*1f0477f1SLinus Walleij if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 153*1f0477f1SLinus Walleij return -EIO; 154*1f0477f1SLinus Walleij 155*1f0477f1SLinus Walleij indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1780)); 156*1f0477f1SLinus Walleij if (!indio_dev) 157*1f0477f1SLinus Walleij return -ENOMEM; 158*1f0477f1SLinus Walleij 159*1f0477f1SLinus Walleij bh1780 = iio_priv(indio_dev); 160*1f0477f1SLinus Walleij bh1780->client = client; 161*1f0477f1SLinus Walleij i2c_set_clientdata(client, indio_dev); 162*1f0477f1SLinus Walleij 163*1f0477f1SLinus Walleij /* Power up the device */ 164*1f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); 165*1f0477f1SLinus Walleij if (ret < 0) 166*1f0477f1SLinus Walleij return ret; 167*1f0477f1SLinus Walleij msleep(BH1780_PON_DELAY); 168*1f0477f1SLinus Walleij pm_runtime_get_noresume(&client->dev); 169*1f0477f1SLinus Walleij pm_runtime_set_active(&client->dev); 170*1f0477f1SLinus Walleij pm_runtime_enable(&client->dev); 171*1f0477f1SLinus Walleij 172*1f0477f1SLinus Walleij ret = bh1780_read(bh1780, BH1780_REG_PARTID); 173*1f0477f1SLinus Walleij if (ret < 0) 174*1f0477f1SLinus Walleij goto out_disable_pm; 175*1f0477f1SLinus Walleij dev_info(&client->dev, 176*1f0477f1SLinus Walleij "Ambient Light Sensor, Rev : %lu\n", 177*1f0477f1SLinus Walleij (ret & BH1780_REVMASK)); 178*1f0477f1SLinus Walleij 179*1f0477f1SLinus Walleij /* 180*1f0477f1SLinus Walleij * As the device takes 250 ms to even come up with a fresh 181*1f0477f1SLinus Walleij * measurement after power-on, do not shut it down unnecessarily. 182*1f0477f1SLinus Walleij * Set autosuspend to a five seconds. 183*1f0477f1SLinus Walleij */ 184*1f0477f1SLinus Walleij pm_runtime_set_autosuspend_delay(&client->dev, 5000); 185*1f0477f1SLinus Walleij pm_runtime_use_autosuspend(&client->dev); 186*1f0477f1SLinus Walleij pm_runtime_put(&client->dev); 187*1f0477f1SLinus Walleij 188*1f0477f1SLinus Walleij indio_dev->dev.parent = &client->dev; 189*1f0477f1SLinus Walleij indio_dev->info = &bh1780_info; 190*1f0477f1SLinus Walleij indio_dev->name = id->name; 191*1f0477f1SLinus Walleij indio_dev->channels = bh1780_channels; 192*1f0477f1SLinus Walleij indio_dev->num_channels = ARRAY_SIZE(bh1780_channels); 193*1f0477f1SLinus Walleij indio_dev->modes = INDIO_DIRECT_MODE; 194*1f0477f1SLinus Walleij 195*1f0477f1SLinus Walleij ret = iio_device_register(indio_dev); 196*1f0477f1SLinus Walleij if (ret) 197*1f0477f1SLinus Walleij goto out_disable_pm; 198*1f0477f1SLinus Walleij return 0; 199*1f0477f1SLinus Walleij 200*1f0477f1SLinus Walleij out_disable_pm: 201*1f0477f1SLinus Walleij pm_runtime_put_noidle(&client->dev); 202*1f0477f1SLinus Walleij pm_runtime_disable(&client->dev); 203*1f0477f1SLinus Walleij return ret; 204*1f0477f1SLinus Walleij } 205*1f0477f1SLinus Walleij 206*1f0477f1SLinus Walleij static int bh1780_remove(struct i2c_client *client) 207*1f0477f1SLinus Walleij { 208*1f0477f1SLinus Walleij struct iio_dev *indio_dev = i2c_get_clientdata(client); 209*1f0477f1SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 210*1f0477f1SLinus Walleij int ret; 211*1f0477f1SLinus Walleij 212*1f0477f1SLinus Walleij iio_device_unregister(indio_dev); 213*1f0477f1SLinus Walleij pm_runtime_get_sync(&client->dev); 214*1f0477f1SLinus Walleij pm_runtime_put_noidle(&client->dev); 215*1f0477f1SLinus Walleij pm_runtime_disable(&client->dev); 216*1f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); 217*1f0477f1SLinus Walleij if (ret < 0) { 218*1f0477f1SLinus Walleij dev_err(&client->dev, "failed to power off\n"); 219*1f0477f1SLinus Walleij return ret; 220*1f0477f1SLinus Walleij } 221*1f0477f1SLinus Walleij 222*1f0477f1SLinus Walleij return 0; 223*1f0477f1SLinus Walleij } 224*1f0477f1SLinus Walleij 225*1f0477f1SLinus Walleij #ifdef CONFIG_PM 226*1f0477f1SLinus Walleij static int bh1780_runtime_suspend(struct device *dev) 227*1f0477f1SLinus Walleij { 228*1f0477f1SLinus Walleij struct i2c_client *client = to_i2c_client(dev); 229*1f0477f1SLinus Walleij struct bh1780_data *bh1780 = i2c_get_clientdata(client); 230*1f0477f1SLinus Walleij int ret; 231*1f0477f1SLinus Walleij 232*1f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); 233*1f0477f1SLinus Walleij if (ret < 0) { 234*1f0477f1SLinus Walleij dev_err(dev, "failed to runtime suspend\n"); 235*1f0477f1SLinus Walleij return ret; 236*1f0477f1SLinus Walleij } 237*1f0477f1SLinus Walleij 238*1f0477f1SLinus Walleij return 0; 239*1f0477f1SLinus Walleij } 240*1f0477f1SLinus Walleij 241*1f0477f1SLinus Walleij static int bh1780_runtime_resume(struct device *dev) 242*1f0477f1SLinus Walleij { 243*1f0477f1SLinus Walleij struct i2c_client *client = to_i2c_client(dev); 244*1f0477f1SLinus Walleij struct bh1780_data *bh1780 = i2c_get_clientdata(client); 245*1f0477f1SLinus Walleij int ret; 246*1f0477f1SLinus Walleij 247*1f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); 248*1f0477f1SLinus Walleij if (ret < 0) { 249*1f0477f1SLinus Walleij dev_err(dev, "failed to runtime resume\n"); 250*1f0477f1SLinus Walleij return ret; 251*1f0477f1SLinus Walleij } 252*1f0477f1SLinus Walleij 253*1f0477f1SLinus Walleij /* Wait for power on, then for a value to be available */ 254*1f0477f1SLinus Walleij msleep(BH1780_PON_DELAY + BH1780_INTERVAL); 255*1f0477f1SLinus Walleij 256*1f0477f1SLinus Walleij return 0; 257*1f0477f1SLinus Walleij } 258*1f0477f1SLinus Walleij #endif /* CONFIG_PM */ 259*1f0477f1SLinus Walleij 260*1f0477f1SLinus Walleij static const struct dev_pm_ops bh1780_dev_pm_ops = { 261*1f0477f1SLinus Walleij SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 262*1f0477f1SLinus Walleij pm_runtime_force_resume) 263*1f0477f1SLinus Walleij SET_RUNTIME_PM_OPS(bh1780_runtime_suspend, 264*1f0477f1SLinus Walleij bh1780_runtime_resume, NULL) 265*1f0477f1SLinus Walleij }; 266*1f0477f1SLinus Walleij 267*1f0477f1SLinus Walleij static const struct i2c_device_id bh1780_id[] = { 268*1f0477f1SLinus Walleij { "bh1780", 0 }, 269*1f0477f1SLinus Walleij { }, 270*1f0477f1SLinus Walleij }; 271*1f0477f1SLinus Walleij 272*1f0477f1SLinus Walleij MODULE_DEVICE_TABLE(i2c, bh1780_id); 273*1f0477f1SLinus Walleij 274*1f0477f1SLinus Walleij #ifdef CONFIG_OF 275*1f0477f1SLinus Walleij static const struct of_device_id of_bh1780_match[] = { 276*1f0477f1SLinus Walleij { .compatible = "rohm,bh1780gli", }, 277*1f0477f1SLinus Walleij {}, 278*1f0477f1SLinus Walleij }; 279*1f0477f1SLinus Walleij MODULE_DEVICE_TABLE(of, of_bh1780_match); 280*1f0477f1SLinus Walleij #endif 281*1f0477f1SLinus Walleij 282*1f0477f1SLinus Walleij static struct i2c_driver bh1780_driver = { 283*1f0477f1SLinus Walleij .probe = bh1780_probe, 284*1f0477f1SLinus Walleij .remove = bh1780_remove, 285*1f0477f1SLinus Walleij .id_table = bh1780_id, 286*1f0477f1SLinus Walleij .driver = { 287*1f0477f1SLinus Walleij .name = "bh1780", 288*1f0477f1SLinus Walleij .pm = &bh1780_dev_pm_ops, 289*1f0477f1SLinus Walleij .of_match_table = of_match_ptr(of_bh1780_match), 290*1f0477f1SLinus Walleij }, 291*1f0477f1SLinus Walleij }; 292*1f0477f1SLinus Walleij 293*1f0477f1SLinus Walleij module_i2c_driver(bh1780_driver); 294*1f0477f1SLinus Walleij 295*1f0477f1SLinus Walleij MODULE_DESCRIPTION("ROHM BH1780GLI Ambient Light Sensor Driver"); 296*1f0477f1SLinus Walleij MODULE_LICENSE("GPL"); 297*1f0477f1SLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 298