summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorentin Teissier <corentinteiss@yahoo.fr>2023-02-23 00:12:17 +0100
committerAndi Shyti <andi.shyti@kernel.org>2023-03-08 22:33:43 +0100
commit8c1f19bc632efef6432e8250b593015c4ddb279b (patch)
tree2d0e5bc70cb29d19242c3d90b720268ed23662ff
parent6a98c9cae232800c319ed69e1063480d31430887 (diff)
iio: light: Add BH1745 RGBc ambient sensor driver
The BH1745 light sensor is a device that can be connected via i2c and used to measure color intensity. It captures data for each color channel, red, blue, and green, as well as clarity, which are then stored in four 16-bit registers. To communicate with userspace, the driver relies on the iio framework. Signed-off-by: Corentin Teissier <corentinteiss@yahoo.fr> Co-developed-by: Andi Shyti <andi.shyti@studenti.polito.it> Signed-off-by: Andi Shyti <andi.shyti@studenti.polito.it>
-rw-r--r--drivers/iio/light/Kconfig7
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/bh1745.c225
3 files changed, 233 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 0d4447df7200..610f465d68aa 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -101,6 +101,13 @@ config AS73211
This driver can also be built as a module. If so, the module
will be called as73211.
+config BH1745
+ tristate "ROHM BH1745 ambient light sensor"
+ depends on I2C
+ help
+ Say Y here to build support for the ROHM BH1745.
+ Driver by Andi and Coco! Vive l'empereur.
+
config BH1750
tristate "ROHM BH1750 ambient light sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index d74d2b5ff14c..04f44d02076b 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_AS73211) += as73211.o
+obj-$(CONFIG_BH1745) += bh1745.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_BH1780) += bh1780.o
obj-$(CONFIG_CM32181) += cm32181.o
diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c
new file mode 100644
index 000000000000..1a579b21661c
--- /dev/null
+++ b/drivers/iio/light/bh1745.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * bh1745.c - Support for Rohm BH1745 light sensor
+ *
+ * Copyright (C) 2022 Corentin Teissier <corentinteiss@yahoo.fr>
+ * Andi Shyti <andi.shyti@studenti.polito.it>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+
+#define BH1745_REG_SYSTEM_CONTROL 0x40
+#define BH1745_REG_MODE_CONTROL2 0x42
+#define BH1745_REG_RED_DATA_LSB 0x50
+#define BH1745_REG_RED_DATA_MSB 0x51
+#define BH1745_REG_GREEN_DATA_LSB 0x52
+#define BH1745_REG_GREEN_DATA_MSB 0x53
+#define BH1745_REG_BLUE_DATA_LSB 0x54
+#define BH1745_REG_BLUE_DATA_MSB 0x55
+#define BH1745_REG_CLEAR_DATA_LSB 0x56
+#define BH1745_REG_CLEAR_DATA_MSB 0x57
+#define BH1745_REG_MANUFACTURER_ID 0x92
+
+#define BH1745_MASK_MODE_CONTROL2_RGBC_ENABLE BIT(4)
+#define BH1745_MASK_SYSTEM_PART_ID GENMASK(5, 0)
+
+#define BH1745_SYSTEM_PART_ID 0x0b
+#define BH1745_MANUFACTURER_ID 0xe0
+
+static const struct iio_chan_spec bh1745_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_RED,
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_GREEN,
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_BLUE,
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_CLEAR,
+ },
+};
+
+struct bh1745_data {
+ struct i2c_client *client;
+};
+
+static int bh1745_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct bh1745_data *data = iio_priv(indio_dev);
+ int ret;
+ u8 reg;
+
+ if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_LIGHT_RED:
+ reg = BH1745_REG_RED_DATA_LSB;
+ break;
+ case IIO_MOD_LIGHT_GREEN:
+ reg = BH1745_REG_GREEN_DATA_LSB;
+ break;
+ case IIO_MOD_LIGHT_BLUE:
+ reg = BH1745_REG_BLUE_DATA_LSB;
+ break;
+ case IIO_MOD_LIGHT_CLEAR:
+ reg = BH1745_REG_CLEAR_DATA_LSB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = i2c_smbus_read_word_data(data->client, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return IIO_VAL_INT;
+}
+
+static int bh1745_init(struct bh1745_data *data)
+{
+ int ret;
+ u8 reg;
+
+ /* Check the manufacturer ID */
+ ret = i2c_smbus_read_byte_data(data->client,
+ BH1745_REG_MANUFACTURER_ID);
+ if (ret < 0)
+ return ret;
+
+ if (ret != BH1745_MANUFACTURER_ID) {
+ dev_err(&data->client->dev, "Unknown device id 0x%x\n", ret);
+ return -ENODEV;
+ }
+
+ dev_dbg(&data->client->dev, "Detected BH1745 device (id 0x%x)\n", ret);
+
+ /* Check System Part ID */
+ ret = i2c_smbus_read_byte_data(data->client, BH1745_REG_SYSTEM_CONTROL);
+ if (ret < 0)
+ return ret;
+
+ ret &= BH1745_MASK_SYSTEM_PART_ID;
+
+ if (ret != BH1745_SYSTEM_PART_ID) {
+ dev_err(&data->client->dev,
+ "BH1745 with wrong part id 0x%x\n", ret);
+ return -ENODEV;
+ }
+
+ /* Enable RGBC Measurement */
+ ret = i2c_smbus_read_byte_data(data->client, BH1745_REG_MODE_CONTROL2);
+ if (ret < 0)
+ return ret;
+
+ reg = ret;
+ reg |= BH1745_MASK_MODE_CONTROL2_RGBC_ENABLE;
+
+ return i2c_smbus_write_byte_data(data->client,
+ BH1745_REG_MODE_CONTROL2, reg);
+};
+
+static const struct iio_info bh1745_info = {
+ .read_raw = bh1745_read_raw,
+};
+
+static int bh1745_probe(struct i2c_client *client)
+{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ struct iio_dev *indio_dev;
+ struct bh1745_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ return -EOPNOTSUPP;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->info = &bh1745_info;
+ indio_dev->name = id->name;
+ indio_dev->channels = bh1745_channels;
+ indio_dev->num_channels = ARRAY_SIZE(bh1745_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = bh1745_init(data);
+ if (ret)
+ return ret;
+
+ return iio_device_register(indio_dev);
+};
+
+static void bh1745_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ int ret;
+ u8 reg;
+
+ iio_device_unregister(indio_dev);
+
+ /* Disable RGBC Measurement */
+ ret = i2c_smbus_read_byte_data(client, BH1745_REG_MODE_CONTROL2);
+ if (ret < 0)
+ return;
+
+ reg = ret & ~BH1745_MASK_MODE_CONTROL2_RGBC_ENABLE;
+
+ i2c_smbus_write_byte_data(client, BH1745_REG_MODE_CONTROL2, reg);
+};
+
+static const struct of_device_id bh1745_of_match[] = {
+ { .compatible = "rohm,bh1745", },
+ { },
+};
+
+static const struct i2c_device_id bh1745_id[] = {
+ { "bh1745", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bh1745_id);
+
+static struct i2c_driver bh1745_driver = {
+ .driver = {
+ .name = "bh1745",
+ .of_match_table = of_match_ptr(bh1745_of_match),
+ },
+ .probe_new = bh1745_probe,
+ .remove = bh1745_remove,
+ .id_table = bh1745_id,
+
+};
+module_i2c_driver(bh1745_driver);
+
+MODULE_AUTHOR("Corentin Teissier <corentinteiss@yahoo.fr>");
+MODULE_AUTHOR("Andi Shyti <andi.shyti@studenti.polito.it>");
+MODULE_LICENSE("GPL v2");