cregit-Linux how code gets into the kernel

Release 4.11 drivers/iio/light/bh1780.c

/*
 * ROHM 1780GLI Ambient Light Sensor Driver
 *
 * Copyright (C) 2016 Linaro Ltd.
 * Author: Linus Walleij <linus.walleij@linaro.org>
 * Loosely based on the previous BH1780 ALS misc driver
 * Copyright (C) 2010 Texas Instruments
 * Author: Hemanth V <hemanthv@ti.com>
 */
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/bitops.h>


#define BH1780_CMD_BIT		BIT(7)

#define BH1780_REG_CONTROL	0x00

#define BH1780_REG_PARTID	0x0A

#define BH1780_REG_MANFID	0x0B

#define BH1780_REG_DLOW		0x0C

#define BH1780_REG_DHIGH	0x0D


#define BH1780_REVMASK		GENMASK(3,0)

#define BH1780_POWMASK		GENMASK(1,0)

#define BH1780_POFF		(0x0)

#define BH1780_PON		(0x3)

/* power on settling time in ms */

#define BH1780_PON_DELAY	2
/* max time before value available in ms */

#define BH1780_INTERVAL		250


struct bh1780_data {
	
struct i2c_client *client;
};


static int bh1780_write(struct bh1780_data *bh1780, u8 reg, u8 val) { int ret = i2c_smbus_write_byte_data(bh1780->client, BH1780_CMD_BIT | reg, val); if (ret < 0) dev_err(&bh1780->client->dev, "i2c_smbus_write_byte_data failed error " "%d, register %01x\n", ret, reg); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij59100.00%1100.00%
Total59100.00%1100.00%


static int bh1780_read(struct bh1780_data *bh1780, u8 reg) { int ret = i2c_smbus_read_byte_data(bh1780->client, BH1780_CMD_BIT | reg); if (ret < 0) dev_err(&bh1780->client->dev, "i2c_smbus_read_byte_data failed error " "%d, register %01x\n", ret, reg); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij54100.00%1100.00%
Total54100.00%1100.00%


static int bh1780_read_word(struct bh1780_data *bh1780, u8 reg) { int ret = i2c_smbus_read_word_data(bh1780->client, BH1780_CMD_BIT | reg); if (ret < 0) dev_err(&bh1780->client->dev, "i2c_smbus_read_word_data failed error " "%d, register %01x\n", ret, reg); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij54100.00%1100.00%
Total54100.00%1100.00%


static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { struct bh1780_data *bh1780 = iio_priv(indio_dev); int ret; if (!readval) return bh1780_write(bh1780, (u8)reg, (u8)writeval); ret = bh1780_read(bh1780, (u8)reg); if (ret < 0) return ret; *readval = ret; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij87100.00%2100.00%
Total87100.00%2100.00%


static int bh1780_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct bh1780_data *bh1780 = iio_priv(indio_dev); int value; switch (mask) { case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_LIGHT: pm_runtime_get_sync(&bh1780->client->dev); value = bh1780_read_word(bh1780, BH1780_REG_DLOW); if (value < 0) return value; pm_runtime_mark_last_busy(&bh1780->client->dev); pm_runtime_put_autosuspend(&bh1780->client->dev); *val = value; return IIO_VAL_INT; default: return -EINVAL; } case IIO_CHAN_INFO_INT_TIME: *val = 0; *val2 = BH1780_INTERVAL * 1000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij145100.00%1100.00%
Total145100.00%1100.00%

static const struct iio_info bh1780_info = { .driver_module = THIS_MODULE, .read_raw = bh1780_read_raw, .debugfs_reg_access = bh1780_debugfs_reg_access, }; static const struct iio_chan_spec bh1780_channels[] = { { .type = IIO_LIGHT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_INT_TIME) } };
static int bh1780_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; struct bh1780_data *bh1780; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct iio_dev *indio_dev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1780)); if (!indio_dev) return -ENOMEM; bh1780 = iio_priv(indio_dev); bh1780->client = client; i2c_set_clientdata(client, indio_dev); /* Power up the device */ ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); if (ret < 0) return ret; msleep(BH1780_PON_DELAY); pm_runtime_get_noresume(&client->dev); pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); ret = bh1780_read(bh1780, BH1780_REG_PARTID); if (ret < 0) goto out_disable_pm; dev_info(&client->dev, "Ambient Light Sensor, Rev : %lu\n", (ret & BH1780_REVMASK)); /* * As the device takes 250 ms to even come up with a fresh * measurement after power-on, do not shut it down unnecessarily. * Set autosuspend to a five seconds. */ pm_runtime_set_autosuspend_delay(&client->dev, 5000); pm_runtime_use_autosuspend(&client->dev); pm_runtime_put(&client->dev); indio_dev->dev.parent = &client->dev; indio_dev->info = &bh1780_info; indio_dev->name = "bh1780"; indio_dev->channels = bh1780_channels; indio_dev->num_channels = ARRAY_SIZE(bh1780_channels); indio_dev->modes = INDIO_DIRECT_MODE; ret = iio_device_register(indio_dev); if (ret) goto out_disable_pm; return 0; out_disable_pm: pm_runtime_put_noidle(&client->dev); pm_runtime_disable(&client->dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij297100.00%2100.00%
Total297100.00%2100.00%


static int bh1780_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct bh1780_data *bh1780 = iio_priv(indio_dev); int ret; iio_device_unregister(indio_dev); pm_runtime_get_sync(&client->dev); pm_runtime_put_noidle(&client->dev); pm_runtime_disable(&client->dev); ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); if (ret < 0) { dev_err(&client->dev, "failed to power off\n"); return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij98100.00%1100.00%
Total98100.00%1100.00%

#ifdef CONFIG_PM
static int bh1780_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct iio_dev *indio_dev = i2c_get_clientdata(client); struct bh1780_data *bh1780 = iio_priv(indio_dev); int ret; ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); if (ret < 0) { dev_err(dev, "failed to runtime suspend\n"); return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij76100.00%2100.00%
Total76100.00%2100.00%


static int bh1780_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct iio_dev *indio_dev = i2c_get_clientdata(client); struct bh1780_data *bh1780 = iio_priv(indio_dev); int ret; ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); if (ret < 0) { dev_err(dev, "failed to runtime resume\n"); return ret; } /* Wait for power on, then for a value to be available */ msleep(BH1780_PON_DELAY + BH1780_INTERVAL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij84100.00%2100.00%
Total84100.00%2100.00%

#endif /* CONFIG_PM */ static const struct dev_pm_ops bh1780_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(bh1780_runtime_suspend, bh1780_runtime_resume, NULL) }; static const struct i2c_device_id bh1780_id[] = { { "bh1780", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, bh1780_id); #ifdef CONFIG_OF static const struct of_device_id of_bh1780_match[] = { { .compatible = "rohm,bh1780gli", }, {}, }; MODULE_DEVICE_TABLE(of, of_bh1780_match); #endif static struct i2c_driver bh1780_driver = { .probe = bh1780_probe, .remove = bh1780_remove, .id_table = bh1780_id, .driver = { .name = "bh1780", .pm = &bh1780_dev_pm_ops, .of_match_table = of_match_ptr(of_bh1780_match), }, }; module_i2c_driver(bh1780_driver); MODULE_DESCRIPTION("ROHM BH1780GLI Ambient Light Sensor Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Walleij1246100.00%4100.00%
Total1246100.00%4100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.