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