* [PATCH] aiodev: add ST L3GD20 Gyroscope and temperature sensor support
@ 2022-07-08 5:55 Ahmad Fatoum
2022-07-11 10:41 ` Sascha Hauer
0 siblings, 1 reply; 2+ messages in thread
From: Ahmad Fatoum @ 2022-07-08 5:55 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The L3GD0 is an on-board peripheral of the STM32F429-DISCOVERY and as
such a good target to test out SPI driver support. Add a simple aiodev
driver to interface with it. It can read the chip's angular rate in
three dimensions as well as the temperature sensor embedded in it.
Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
drivers/aiodev/Kconfig | 6 ++
drivers/aiodev/Makefile | 1 +
drivers/aiodev/st_gyro.c | 122 +++++++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+)
create mode 100644 drivers/aiodev/st_gyro.c
diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig
index 88a3b9a3431c..6bd697702ecf 100644
--- a/drivers/aiodev/Kconfig
+++ b/drivers/aiodev/Kconfig
@@ -30,6 +30,12 @@ config LM75
help
Support for LM75 and similar devices
+config ST_GYRO
+ tristate "ST L3GD20 SPI gyro driver"
+ depends on SPI
+ help
+ Support for L3GD20 three-axis angular rate sensor.
+
config MC13XXX_ADC
tristate "MC13XXX ADC driver"
depends on MFD_MC13XXX
diff --git a/drivers/aiodev/Makefile b/drivers/aiodev/Makefile
index 4c92a403a293..06a63b0d2d78 100644
--- a/drivers/aiodev/Makefile
+++ b/drivers/aiodev/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_AIODEV) += core.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_LM75) += lm75.o
+obj-$(CONFIG_ST_GYRO) += st_gyro.o
obj-$(CONFIG_MC13XXX_ADC) += mc13xxx_adc.o
obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
obj-$(CONFIG_AM335X_ADC) += am335x_adc.o
diff --git a/drivers/aiodev/st_gyro.c b/drivers/aiodev/st_gyro.c
new file mode 100644
index 000000000000..3938d8239e4b
--- /dev/null
+++ b/drivers/aiodev/st_gyro.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2022 Ahmad Fatoum
+
+#include <common.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <spi/spi.h>
+#include <aiodev.h>
+
+#define ST_GYRO_WHO_AM_I 0x0F
+#define ST_GYRO_CTRL_REG1 0x20
+
+#define ST_GYRO_DEFAULT_OUT_TEMP_ADDR 0x26
+#define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x28
+#define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a
+#define ST_GYRO_DEFAULT_OUT_Z_L_ADDR 0x2c
+
+#define ST_GYRO_OUT_L_ADDR(idx) \
+ (ST_GYRO_DEFAULT_OUT_X_L_ADDR + 2 * (idx))
+
+#define ST_GYRO_OUT_H_ADDR(idx) \
+ (ST_GYRO_OUT_L_ADDR(idx) + 1)
+
+#define ST_GYRO_READ 0x80
+#define ST_GYRO_WRITE 0x00
+#define ST_GYRO_MULTI 0x40
+
+struct st_gyro {
+ struct aiodevice aiodev;
+ struct aiochannel aiochan[4];
+ struct spi_device *spi;
+};
+#define to_st_gyro(chan) container_of(chan->aiodev, struct st_gyro, aiodev)
+
+static int st_gyro_read(struct aiochannel *chan, int *val)
+{
+ struct st_gyro *gyro = to_st_gyro(chan);
+ int ret;
+ u8 tx;
+ u8 rx_h, rx_l;
+
+ if (chan->index == 3) {
+ tx = ST_GYRO_DEFAULT_OUT_TEMP_ADDR | ST_GYRO_READ;
+ ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_l, 1);
+ if (ret)
+ return ret;
+
+ *val = (s8)rx_l;
+ return 0;
+ }
+
+ tx = ST_GYRO_OUT_H_ADDR(chan->index) | ST_GYRO_READ;
+ ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_h, 1);
+ if (ret)
+ return ret;
+
+ tx = ST_GYRO_OUT_L_ADDR(chan->index) | ST_GYRO_READ;
+ ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_l, 1);
+ if (ret)
+ return ret;
+
+ *val = (s16)((rx_h << 8) | rx_l);
+ *val *= 250;
+ *val >>= 16;
+
+ return 0;
+}
+
+static int st_gyro_probe(struct device_d *dev)
+{
+ u8 tx[2], rx[2];
+ struct st_gyro *gyro;
+ int ret, i;
+
+ gyro = xzalloc(sizeof(*gyro));
+ gyro->spi = to_spi_device(dev);
+
+ tx[0] = ST_GYRO_WHO_AM_I | ST_GYRO_READ;
+ ret = spi_write_then_read(gyro->spi, tx, 1, rx, 1);
+ if (ret)
+ return -EIO;
+ if (rx[0] != 0xD4)
+ return dev_err_probe(dev, -ENODEV, "unexpected device WAI: %02x\n", rx[0]);
+
+ /* initialize device */
+ tx[0] = ST_GYRO_CTRL_REG1 | ST_GYRO_WRITE;
+ tx[1] = 0xF; /* normal mode, 3 channels */
+ ret = spi_write(gyro->spi, tx, 2);
+ if (ret)
+ return -EIO;
+
+ gyro->aiodev.num_channels = 4;
+ gyro->aiodev.hwdev = dev;
+ gyro->aiodev.read = st_gyro_read;
+ gyro->aiodev.name = "gyroscope";
+ gyro->aiodev.channels =
+ xmalloc(gyro->aiodev.num_channels *
+ sizeof(gyro->aiodev.channels[0]));
+ for (i = 0; i < 3; i++) {
+ gyro->aiodev.channels[i] = &gyro->aiochan[i];
+ gyro->aiochan[i].unit = "dps";
+ gyro->aiochan[i].index = i;
+ }
+
+ gyro->aiodev.channels[3] = &gyro->aiochan[3];
+ gyro->aiochan[3].unit = "C";
+ gyro->aiochan[3].index = 3;
+
+ return aiodevice_register(&gyro->aiodev);
+}
+
+static const struct of_device_id st_gyro_match[] = {
+ { .compatible = "st,l3gd20-gyro" },
+ { /* sentinel */ }
+};
+
+static struct driver_d st_gyro_driver = {
+ .name = "st_gyro",
+ .probe = st_gyro_probe,
+ .of_compatible = st_gyro_match,
+};
+device_spi_driver(st_gyro_driver);
--
2.34.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] aiodev: add ST L3GD20 Gyroscope and temperature sensor support
2022-07-08 5:55 [PATCH] aiodev: add ST L3GD20 Gyroscope and temperature sensor support Ahmad Fatoum
@ 2022-07-11 10:41 ` Sascha Hauer
0 siblings, 0 replies; 2+ messages in thread
From: Sascha Hauer @ 2022-07-11 10:41 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Fri, Jul 08, 2022 at 07:55:26AM +0200, Ahmad Fatoum wrote:
> The L3GD0 is an on-board peripheral of the STM32F429-DISCOVERY and as
> such a good target to test out SPI driver support. Add a simple aiodev
> driver to interface with it. It can read the chip's angular rate in
> three dimensions as well as the temperature sensor embedded in it.
>
> Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
> ---
> drivers/aiodev/Kconfig | 6 ++
> drivers/aiodev/Makefile | 1 +
> drivers/aiodev/st_gyro.c | 122 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 129 insertions(+)
> create mode 100644 drivers/aiodev/st_gyro.c
Applied, thanks
Sascha
>
> diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig
> index 88a3b9a3431c..6bd697702ecf 100644
> --- a/drivers/aiodev/Kconfig
> +++ b/drivers/aiodev/Kconfig
> @@ -30,6 +30,12 @@ config LM75
> help
> Support for LM75 and similar devices
>
> +config ST_GYRO
> + tristate "ST L3GD20 SPI gyro driver"
> + depends on SPI
> + help
> + Support for L3GD20 three-axis angular rate sensor.
> +
> config MC13XXX_ADC
> tristate "MC13XXX ADC driver"
> depends on MFD_MC13XXX
> diff --git a/drivers/aiodev/Makefile b/drivers/aiodev/Makefile
> index 4c92a403a293..06a63b0d2d78 100644
> --- a/drivers/aiodev/Makefile
> +++ b/drivers/aiodev/Makefile
> @@ -3,6 +3,7 @@
> obj-$(CONFIG_AIODEV) += core.o
> obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
> obj-$(CONFIG_LM75) += lm75.o
> +obj-$(CONFIG_ST_GYRO) += st_gyro.o
> obj-$(CONFIG_MC13XXX_ADC) += mc13xxx_adc.o
> obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
> obj-$(CONFIG_AM335X_ADC) += am335x_adc.o
> diff --git a/drivers/aiodev/st_gyro.c b/drivers/aiodev/st_gyro.c
> new file mode 100644
> index 000000000000..3938d8239e4b
> --- /dev/null
> +++ b/drivers/aiodev/st_gyro.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +// SPDX-FileCopyrightText: 2022 Ahmad Fatoum
> +
> +#include <common.h>
> +#include <driver.h>
> +#include <xfuncs.h>
> +#include <spi/spi.h>
> +#include <aiodev.h>
> +
> +#define ST_GYRO_WHO_AM_I 0x0F
> +#define ST_GYRO_CTRL_REG1 0x20
> +
> +#define ST_GYRO_DEFAULT_OUT_TEMP_ADDR 0x26
> +#define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x28
> +#define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a
> +#define ST_GYRO_DEFAULT_OUT_Z_L_ADDR 0x2c
> +
> +#define ST_GYRO_OUT_L_ADDR(idx) \
> + (ST_GYRO_DEFAULT_OUT_X_L_ADDR + 2 * (idx))
> +
> +#define ST_GYRO_OUT_H_ADDR(idx) \
> + (ST_GYRO_OUT_L_ADDR(idx) + 1)
> +
> +#define ST_GYRO_READ 0x80
> +#define ST_GYRO_WRITE 0x00
> +#define ST_GYRO_MULTI 0x40
> +
> +struct st_gyro {
> + struct aiodevice aiodev;
> + struct aiochannel aiochan[4];
> + struct spi_device *spi;
> +};
> +#define to_st_gyro(chan) container_of(chan->aiodev, struct st_gyro, aiodev)
> +
> +static int st_gyro_read(struct aiochannel *chan, int *val)
> +{
> + struct st_gyro *gyro = to_st_gyro(chan);
> + int ret;
> + u8 tx;
> + u8 rx_h, rx_l;
> +
> + if (chan->index == 3) {
> + tx = ST_GYRO_DEFAULT_OUT_TEMP_ADDR | ST_GYRO_READ;
> + ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_l, 1);
> + if (ret)
> + return ret;
> +
> + *val = (s8)rx_l;
> + return 0;
> + }
> +
> + tx = ST_GYRO_OUT_H_ADDR(chan->index) | ST_GYRO_READ;
> + ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_h, 1);
> + if (ret)
> + return ret;
> +
> + tx = ST_GYRO_OUT_L_ADDR(chan->index) | ST_GYRO_READ;
> + ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_l, 1);
> + if (ret)
> + return ret;
> +
> + *val = (s16)((rx_h << 8) | rx_l);
> + *val *= 250;
> + *val >>= 16;
> +
> + return 0;
> +}
> +
> +static int st_gyro_probe(struct device_d *dev)
> +{
> + u8 tx[2], rx[2];
> + struct st_gyro *gyro;
> + int ret, i;
> +
> + gyro = xzalloc(sizeof(*gyro));
> + gyro->spi = to_spi_device(dev);
> +
> + tx[0] = ST_GYRO_WHO_AM_I | ST_GYRO_READ;
> + ret = spi_write_then_read(gyro->spi, tx, 1, rx, 1);
> + if (ret)
> + return -EIO;
> + if (rx[0] != 0xD4)
> + return dev_err_probe(dev, -ENODEV, "unexpected device WAI: %02x\n", rx[0]);
> +
> + /* initialize device */
> + tx[0] = ST_GYRO_CTRL_REG1 | ST_GYRO_WRITE;
> + tx[1] = 0xF; /* normal mode, 3 channels */
> + ret = spi_write(gyro->spi, tx, 2);
> + if (ret)
> + return -EIO;
> +
> + gyro->aiodev.num_channels = 4;
> + gyro->aiodev.hwdev = dev;
> + gyro->aiodev.read = st_gyro_read;
> + gyro->aiodev.name = "gyroscope";
> + gyro->aiodev.channels =
> + xmalloc(gyro->aiodev.num_channels *
> + sizeof(gyro->aiodev.channels[0]));
> + for (i = 0; i < 3; i++) {
> + gyro->aiodev.channels[i] = &gyro->aiochan[i];
> + gyro->aiochan[i].unit = "dps";
> + gyro->aiochan[i].index = i;
> + }
> +
> + gyro->aiodev.channels[3] = &gyro->aiochan[3];
> + gyro->aiochan[3].unit = "C";
> + gyro->aiochan[3].index = 3;
> +
> + return aiodevice_register(&gyro->aiodev);
> +}
> +
> +static const struct of_device_id st_gyro_match[] = {
> + { .compatible = "st,l3gd20-gyro" },
> + { /* sentinel */ }
> +};
> +
> +static struct driver_d st_gyro_driver = {
> + .name = "st_gyro",
> + .probe = st_gyro_probe,
> + .of_compatible = st_gyro_match,
> +};
> +device_spi_driver(st_gyro_driver);
> --
> 2.34.1
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2022-07-11 10:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-08 5:55 [PATCH] aiodev: add ST L3GD20 Gyroscope and temperature sensor support Ahmad Fatoum
2022-07-11 10:41 ` Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox