11f0477f1SLinus Walleij /* 21f0477f1SLinus Walleij * ROHM 1780GLI Ambient Light Sensor Driver 31f0477f1SLinus Walleij * 41f0477f1SLinus Walleij * Copyright (C) 2016 Linaro Ltd. 51f0477f1SLinus Walleij * Author: Linus Walleij <linus.walleij@linaro.org> 61f0477f1SLinus Walleij * Loosely based on the previous BH1780 ALS misc driver 71f0477f1SLinus Walleij * Copyright (C) 2010 Texas Instruments 81f0477f1SLinus Walleij * Author: Hemanth V <hemanthv@ti.com> 91f0477f1SLinus Walleij */ 101f0477f1SLinus Walleij #include <linux/i2c.h> 111f0477f1SLinus Walleij #include <linux/slab.h> 121f0477f1SLinus Walleij #include <linux/platform_device.h> 131f0477f1SLinus Walleij #include <linux/delay.h> 141f0477f1SLinus Walleij #include <linux/module.h> 151f0477f1SLinus Walleij #include <linux/of.h> 161f0477f1SLinus Walleij #include <linux/pm_runtime.h> 171f0477f1SLinus Walleij #include <linux/iio/iio.h> 181f0477f1SLinus Walleij #include <linux/iio/sysfs.h> 191f0477f1SLinus Walleij #include <linux/bitops.h> 201f0477f1SLinus Walleij 211f0477f1SLinus Walleij #define BH1780_CMD_BIT BIT(7) 221f0477f1SLinus Walleij #define BH1780_REG_CONTROL 0x00 231f0477f1SLinus Walleij #define BH1780_REG_PARTID 0x0A 241f0477f1SLinus Walleij #define BH1780_REG_MANFID 0x0B 251f0477f1SLinus Walleij #define BH1780_REG_DLOW 0x0C 261f0477f1SLinus Walleij #define BH1780_REG_DHIGH 0x0D 271f0477f1SLinus Walleij 281f0477f1SLinus Walleij #define BH1780_REVMASK GENMASK(3,0) 291f0477f1SLinus Walleij #define BH1780_POWMASK GENMASK(1,0) 301f0477f1SLinus Walleij #define BH1780_POFF (0x0) 311f0477f1SLinus Walleij #define BH1780_PON (0x3) 321f0477f1SLinus Walleij 331f0477f1SLinus Walleij /* power on settling time in ms */ 341f0477f1SLinus Walleij #define BH1780_PON_DELAY 2 351f0477f1SLinus Walleij /* max time before value available in ms */ 361f0477f1SLinus Walleij #define BH1780_INTERVAL 250 371f0477f1SLinus Walleij 381f0477f1SLinus Walleij struct bh1780_data { 391f0477f1SLinus Walleij struct i2c_client *client; 401f0477f1SLinus Walleij }; 411f0477f1SLinus Walleij 421f0477f1SLinus Walleij static int bh1780_write(struct bh1780_data *bh1780, u8 reg, u8 val) 431f0477f1SLinus Walleij { 441f0477f1SLinus Walleij int ret = i2c_smbus_write_byte_data(bh1780->client, 451f0477f1SLinus Walleij BH1780_CMD_BIT | reg, 461f0477f1SLinus Walleij val); 471f0477f1SLinus Walleij if (ret < 0) 481f0477f1SLinus Walleij dev_err(&bh1780->client->dev, 491f0477f1SLinus Walleij "i2c_smbus_write_byte_data failed error " 501f0477f1SLinus Walleij "%d, register %01x\n", 511f0477f1SLinus Walleij ret, reg); 521f0477f1SLinus Walleij return ret; 531f0477f1SLinus Walleij } 541f0477f1SLinus Walleij 551f0477f1SLinus Walleij static int bh1780_read(struct bh1780_data *bh1780, u8 reg) 561f0477f1SLinus Walleij { 571f0477f1SLinus Walleij int ret = i2c_smbus_read_byte_data(bh1780->client, 581f0477f1SLinus Walleij BH1780_CMD_BIT | reg); 591f0477f1SLinus Walleij if (ret < 0) 601f0477f1SLinus Walleij dev_err(&bh1780->client->dev, 611f0477f1SLinus Walleij "i2c_smbus_read_byte_data failed error " 621f0477f1SLinus Walleij "%d, register %01x\n", 631f0477f1SLinus Walleij ret, reg); 641f0477f1SLinus Walleij return ret; 651f0477f1SLinus Walleij } 661f0477f1SLinus Walleij 671f0477f1SLinus Walleij static int bh1780_read_word(struct bh1780_data *bh1780, u8 reg) 681f0477f1SLinus Walleij { 691f0477f1SLinus Walleij int ret = i2c_smbus_read_word_data(bh1780->client, 701f0477f1SLinus Walleij BH1780_CMD_BIT | reg); 711f0477f1SLinus Walleij if (ret < 0) 721f0477f1SLinus Walleij dev_err(&bh1780->client->dev, 731f0477f1SLinus Walleij "i2c_smbus_read_word_data failed error " 741f0477f1SLinus Walleij "%d, register %01x\n", 751f0477f1SLinus Walleij ret, reg); 761f0477f1SLinus Walleij return ret; 771f0477f1SLinus Walleij } 781f0477f1SLinus Walleij 791f0477f1SLinus Walleij static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev, 801f0477f1SLinus Walleij unsigned int reg, unsigned int writeval, 811f0477f1SLinus Walleij unsigned int *readval) 821f0477f1SLinus Walleij { 831f0477f1SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 841f0477f1SLinus Walleij int ret; 851f0477f1SLinus Walleij 861f0477f1SLinus Walleij if (!readval) 8753dfc3b9SLinus Walleij return bh1780_write(bh1780, (u8)reg, (u8)writeval); 881f0477f1SLinus Walleij 891f0477f1SLinus Walleij ret = bh1780_read(bh1780, (u8)reg); 901f0477f1SLinus Walleij if (ret < 0) 911f0477f1SLinus Walleij return ret; 921f0477f1SLinus Walleij 931f0477f1SLinus Walleij *readval = ret; 941f0477f1SLinus Walleij 951f0477f1SLinus Walleij return 0; 961f0477f1SLinus Walleij } 971f0477f1SLinus Walleij 981f0477f1SLinus Walleij static int bh1780_read_raw(struct iio_dev *indio_dev, 991f0477f1SLinus Walleij struct iio_chan_spec const *chan, 1001f0477f1SLinus Walleij int *val, int *val2, long mask) 1011f0477f1SLinus Walleij { 1021f0477f1SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 1031f0477f1SLinus Walleij int value; 1041f0477f1SLinus Walleij 1051f0477f1SLinus Walleij switch (mask) { 1061f0477f1SLinus Walleij case IIO_CHAN_INFO_RAW: 1071f0477f1SLinus Walleij switch (chan->type) { 1081f0477f1SLinus Walleij case IIO_LIGHT: 1091f0477f1SLinus Walleij pm_runtime_get_sync(&bh1780->client->dev); 1101f0477f1SLinus Walleij value = bh1780_read_word(bh1780, BH1780_REG_DLOW); 1111f0477f1SLinus Walleij if (value < 0) 1121f0477f1SLinus Walleij return value; 1131f0477f1SLinus Walleij pm_runtime_mark_last_busy(&bh1780->client->dev); 1141f0477f1SLinus Walleij pm_runtime_put_autosuspend(&bh1780->client->dev); 1151f0477f1SLinus Walleij *val = value; 1161f0477f1SLinus Walleij 1171f0477f1SLinus Walleij return IIO_VAL_INT; 1181f0477f1SLinus Walleij default: 1191f0477f1SLinus Walleij return -EINVAL; 1201f0477f1SLinus Walleij } 1211f0477f1SLinus Walleij case IIO_CHAN_INFO_INT_TIME: 1221f0477f1SLinus Walleij *val = 0; 1231f0477f1SLinus Walleij *val2 = BH1780_INTERVAL * 1000; 1241f0477f1SLinus Walleij return IIO_VAL_INT_PLUS_MICRO; 1251f0477f1SLinus Walleij default: 1261f0477f1SLinus Walleij return -EINVAL; 1271f0477f1SLinus Walleij } 1281f0477f1SLinus Walleij } 1291f0477f1SLinus Walleij 1301f0477f1SLinus Walleij static const struct iio_info bh1780_info = { 1311f0477f1SLinus Walleij .driver_module = THIS_MODULE, 1321f0477f1SLinus Walleij .read_raw = bh1780_read_raw, 1331f0477f1SLinus Walleij .debugfs_reg_access = bh1780_debugfs_reg_access, 1341f0477f1SLinus Walleij }; 1351f0477f1SLinus Walleij 1361f0477f1SLinus Walleij static const struct iio_chan_spec bh1780_channels[] = { 1371f0477f1SLinus Walleij { 1381f0477f1SLinus Walleij .type = IIO_LIGHT, 1391f0477f1SLinus Walleij .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 1401f0477f1SLinus Walleij BIT(IIO_CHAN_INFO_INT_TIME) 1411f0477f1SLinus Walleij } 1421f0477f1SLinus Walleij }; 1431f0477f1SLinus Walleij 1441f0477f1SLinus Walleij static int bh1780_probe(struct i2c_client *client, 1451f0477f1SLinus Walleij const struct i2c_device_id *id) 1461f0477f1SLinus Walleij { 1471f0477f1SLinus Walleij int ret; 1481f0477f1SLinus Walleij struct bh1780_data *bh1780; 1491f0477f1SLinus Walleij struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 1501f0477f1SLinus Walleij struct iio_dev *indio_dev; 1511f0477f1SLinus Walleij 1521f0477f1SLinus Walleij if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) 1531f0477f1SLinus Walleij return -EIO; 1541f0477f1SLinus Walleij 1551f0477f1SLinus Walleij indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1780)); 1561f0477f1SLinus Walleij if (!indio_dev) 1571f0477f1SLinus Walleij return -ENOMEM; 1581f0477f1SLinus Walleij 1591f0477f1SLinus Walleij bh1780 = iio_priv(indio_dev); 1601f0477f1SLinus Walleij bh1780->client = client; 1611f0477f1SLinus Walleij i2c_set_clientdata(client, indio_dev); 1621f0477f1SLinus Walleij 1631f0477f1SLinus Walleij /* Power up the device */ 1641f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); 1651f0477f1SLinus Walleij if (ret < 0) 1661f0477f1SLinus Walleij return ret; 1671f0477f1SLinus Walleij msleep(BH1780_PON_DELAY); 1681f0477f1SLinus Walleij pm_runtime_get_noresume(&client->dev); 1691f0477f1SLinus Walleij pm_runtime_set_active(&client->dev); 1701f0477f1SLinus Walleij pm_runtime_enable(&client->dev); 1711f0477f1SLinus Walleij 1721f0477f1SLinus Walleij ret = bh1780_read(bh1780, BH1780_REG_PARTID); 1731f0477f1SLinus Walleij if (ret < 0) 1741f0477f1SLinus Walleij goto out_disable_pm; 1751f0477f1SLinus Walleij dev_info(&client->dev, 1761f0477f1SLinus Walleij "Ambient Light Sensor, Rev : %lu\n", 1771f0477f1SLinus Walleij (ret & BH1780_REVMASK)); 1781f0477f1SLinus Walleij 1791f0477f1SLinus Walleij /* 1801f0477f1SLinus Walleij * As the device takes 250 ms to even come up with a fresh 1811f0477f1SLinus Walleij * measurement after power-on, do not shut it down unnecessarily. 1821f0477f1SLinus Walleij * Set autosuspend to a five seconds. 1831f0477f1SLinus Walleij */ 1841f0477f1SLinus Walleij pm_runtime_set_autosuspend_delay(&client->dev, 5000); 1851f0477f1SLinus Walleij pm_runtime_use_autosuspend(&client->dev); 1861f0477f1SLinus Walleij pm_runtime_put(&client->dev); 1871f0477f1SLinus Walleij 1881f0477f1SLinus Walleij indio_dev->dev.parent = &client->dev; 1891f0477f1SLinus Walleij indio_dev->info = &bh1780_info; 1901f0477f1SLinus Walleij indio_dev->name = id->name; 1911f0477f1SLinus Walleij indio_dev->channels = bh1780_channels; 1921f0477f1SLinus Walleij indio_dev->num_channels = ARRAY_SIZE(bh1780_channels); 1931f0477f1SLinus Walleij indio_dev->modes = INDIO_DIRECT_MODE; 1941f0477f1SLinus Walleij 1951f0477f1SLinus Walleij ret = iio_device_register(indio_dev); 1961f0477f1SLinus Walleij if (ret) 1971f0477f1SLinus Walleij goto out_disable_pm; 1981f0477f1SLinus Walleij return 0; 1991f0477f1SLinus Walleij 2001f0477f1SLinus Walleij out_disable_pm: 2011f0477f1SLinus Walleij pm_runtime_put_noidle(&client->dev); 2021f0477f1SLinus Walleij pm_runtime_disable(&client->dev); 2031f0477f1SLinus Walleij return ret; 2041f0477f1SLinus Walleij } 2051f0477f1SLinus Walleij 2061f0477f1SLinus Walleij static int bh1780_remove(struct i2c_client *client) 2071f0477f1SLinus Walleij { 2081f0477f1SLinus Walleij struct iio_dev *indio_dev = i2c_get_clientdata(client); 2091f0477f1SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 2101f0477f1SLinus Walleij int ret; 2111f0477f1SLinus Walleij 2121f0477f1SLinus Walleij iio_device_unregister(indio_dev); 2131f0477f1SLinus Walleij pm_runtime_get_sync(&client->dev); 2141f0477f1SLinus Walleij pm_runtime_put_noidle(&client->dev); 2151f0477f1SLinus Walleij pm_runtime_disable(&client->dev); 2161f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); 2171f0477f1SLinus Walleij if (ret < 0) { 2181f0477f1SLinus Walleij dev_err(&client->dev, "failed to power off\n"); 2191f0477f1SLinus Walleij return ret; 2201f0477f1SLinus Walleij } 2211f0477f1SLinus Walleij 2221f0477f1SLinus Walleij return 0; 2231f0477f1SLinus Walleij } 2241f0477f1SLinus Walleij 2251f0477f1SLinus Walleij #ifdef CONFIG_PM 2261f0477f1SLinus Walleij static int bh1780_runtime_suspend(struct device *dev) 2271f0477f1SLinus Walleij { 2281f0477f1SLinus Walleij struct i2c_client *client = to_i2c_client(dev); 229*13c27e94SLinus Walleij struct iio_dev *indio_dev = i2c_get_clientdata(client); 230*13c27e94SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 2311f0477f1SLinus Walleij int ret; 2321f0477f1SLinus Walleij 2331f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); 2341f0477f1SLinus Walleij if (ret < 0) { 2351f0477f1SLinus Walleij dev_err(dev, "failed to runtime suspend\n"); 2361f0477f1SLinus Walleij return ret; 2371f0477f1SLinus Walleij } 2381f0477f1SLinus Walleij 2391f0477f1SLinus Walleij return 0; 2401f0477f1SLinus Walleij } 2411f0477f1SLinus Walleij 2421f0477f1SLinus Walleij static int bh1780_runtime_resume(struct device *dev) 2431f0477f1SLinus Walleij { 2441f0477f1SLinus Walleij struct i2c_client *client = to_i2c_client(dev); 245*13c27e94SLinus Walleij struct iio_dev *indio_dev = i2c_get_clientdata(client); 246*13c27e94SLinus Walleij struct bh1780_data *bh1780 = iio_priv(indio_dev); 2471f0477f1SLinus Walleij int ret; 2481f0477f1SLinus Walleij 2491f0477f1SLinus Walleij ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); 2501f0477f1SLinus Walleij if (ret < 0) { 2511f0477f1SLinus Walleij dev_err(dev, "failed to runtime resume\n"); 2521f0477f1SLinus Walleij return ret; 2531f0477f1SLinus Walleij } 2541f0477f1SLinus Walleij 2551f0477f1SLinus Walleij /* Wait for power on, then for a value to be available */ 2561f0477f1SLinus Walleij msleep(BH1780_PON_DELAY + BH1780_INTERVAL); 2571f0477f1SLinus Walleij 2581f0477f1SLinus Walleij return 0; 2591f0477f1SLinus Walleij } 2601f0477f1SLinus Walleij #endif /* CONFIG_PM */ 2611f0477f1SLinus Walleij 2621f0477f1SLinus Walleij static const struct dev_pm_ops bh1780_dev_pm_ops = { 2631f0477f1SLinus Walleij SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 2641f0477f1SLinus Walleij pm_runtime_force_resume) 2651f0477f1SLinus Walleij SET_RUNTIME_PM_OPS(bh1780_runtime_suspend, 2661f0477f1SLinus Walleij bh1780_runtime_resume, NULL) 2671f0477f1SLinus Walleij }; 2681f0477f1SLinus Walleij 2691f0477f1SLinus Walleij static const struct i2c_device_id bh1780_id[] = { 2701f0477f1SLinus Walleij { "bh1780", 0 }, 2711f0477f1SLinus Walleij { }, 2721f0477f1SLinus Walleij }; 2731f0477f1SLinus Walleij 2741f0477f1SLinus Walleij MODULE_DEVICE_TABLE(i2c, bh1780_id); 2751f0477f1SLinus Walleij 2761f0477f1SLinus Walleij #ifdef CONFIG_OF 2771f0477f1SLinus Walleij static const struct of_device_id of_bh1780_match[] = { 2781f0477f1SLinus Walleij { .compatible = "rohm,bh1780gli", }, 2791f0477f1SLinus Walleij {}, 2801f0477f1SLinus Walleij }; 2811f0477f1SLinus Walleij MODULE_DEVICE_TABLE(of, of_bh1780_match); 2821f0477f1SLinus Walleij #endif 2831f0477f1SLinus Walleij 2841f0477f1SLinus Walleij static struct i2c_driver bh1780_driver = { 2851f0477f1SLinus Walleij .probe = bh1780_probe, 2861f0477f1SLinus Walleij .remove = bh1780_remove, 2871f0477f1SLinus Walleij .id_table = bh1780_id, 2881f0477f1SLinus Walleij .driver = { 2891f0477f1SLinus Walleij .name = "bh1780", 2901f0477f1SLinus Walleij .pm = &bh1780_dev_pm_ops, 2911f0477f1SLinus Walleij .of_match_table = of_match_ptr(of_bh1780_match), 2921f0477f1SLinus Walleij }, 2931f0477f1SLinus Walleij }; 2941f0477f1SLinus Walleij 2951f0477f1SLinus Walleij module_i2c_driver(bh1780_driver); 2961f0477f1SLinus Walleij 2971f0477f1SLinus Walleij MODULE_DESCRIPTION("ROHM BH1780GLI Ambient Light Sensor Driver"); 2981f0477f1SLinus Walleij MODULE_LICENSE("GPL"); 2991f0477f1SLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 300