.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * STMicroelectronics sensors spi library driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 2012-2013 STMicroelectronics Inc. |
---|
5 | 6 | * |
---|
6 | 7 | * Denis Ciocca <denis.ciocca@st.com> |
---|
7 | | - * |
---|
8 | | - * Licensed under the GPL-2. |
---|
9 | 8 | */ |
---|
10 | 9 | |
---|
11 | 10 | #include <linux/kernel.h> |
---|
12 | 11 | #include <linux/module.h> |
---|
13 | 12 | #include <linux/slab.h> |
---|
14 | 13 | #include <linux/iio/iio.h> |
---|
| 14 | +#include <linux/property.h> |
---|
| 15 | +#include <linux/regmap.h> |
---|
15 | 16 | |
---|
16 | 17 | #include <linux/iio/common/st_sensors_spi.h> |
---|
17 | | - |
---|
| 18 | +#include "st_sensors_core.h" |
---|
18 | 19 | |
---|
19 | 20 | #define ST_SENSORS_SPI_MULTIREAD 0xc0 |
---|
20 | | -#define ST_SENSORS_SPI_READ 0x80 |
---|
21 | 21 | |
---|
22 | | -static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev) |
---|
23 | | -{ |
---|
24 | | - struct st_sensor_data *sdata = iio_priv(indio_dev); |
---|
25 | | - |
---|
26 | | - return to_spi_device(sdata->dev)->irq; |
---|
27 | | -} |
---|
28 | | - |
---|
29 | | -static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb, |
---|
30 | | - struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit) |
---|
31 | | -{ |
---|
32 | | - int err; |
---|
33 | | - |
---|
34 | | - struct spi_transfer xfers[] = { |
---|
35 | | - { |
---|
36 | | - .tx_buf = tb->tx_buf, |
---|
37 | | - .bits_per_word = 8, |
---|
38 | | - .len = 1, |
---|
39 | | - }, |
---|
40 | | - { |
---|
41 | | - .rx_buf = tb->rx_buf, |
---|
42 | | - .bits_per_word = 8, |
---|
43 | | - .len = len, |
---|
44 | | - } |
---|
45 | | - }; |
---|
46 | | - |
---|
47 | | - mutex_lock(&tb->buf_lock); |
---|
48 | | - if ((multiread_bit) && (len > 1)) |
---|
49 | | - tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD; |
---|
50 | | - else |
---|
51 | | - tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ; |
---|
52 | | - |
---|
53 | | - err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers)); |
---|
54 | | - if (err) |
---|
55 | | - goto acc_spi_read_error; |
---|
56 | | - |
---|
57 | | - memcpy(data, tb->rx_buf, len); |
---|
58 | | - mutex_unlock(&tb->buf_lock); |
---|
59 | | - return len; |
---|
60 | | - |
---|
61 | | -acc_spi_read_error: |
---|
62 | | - mutex_unlock(&tb->buf_lock); |
---|
63 | | - return err; |
---|
64 | | -} |
---|
65 | | - |
---|
66 | | -static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb, |
---|
67 | | - struct device *dev, u8 reg_addr, u8 *res_byte) |
---|
68 | | -{ |
---|
69 | | - return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false); |
---|
70 | | -} |
---|
71 | | - |
---|
72 | | -static int st_sensors_spi_read_multiple_byte( |
---|
73 | | - struct st_sensor_transfer_buffer *tb, struct device *dev, |
---|
74 | | - u8 reg_addr, int len, u8 *data, bool multiread_bit) |
---|
75 | | -{ |
---|
76 | | - return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit); |
---|
77 | | -} |
---|
78 | | - |
---|
79 | | -static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb, |
---|
80 | | - struct device *dev, u8 reg_addr, u8 data) |
---|
81 | | -{ |
---|
82 | | - int err; |
---|
83 | | - |
---|
84 | | - struct spi_transfer xfers = { |
---|
85 | | - .tx_buf = tb->tx_buf, |
---|
86 | | - .bits_per_word = 8, |
---|
87 | | - .len = 2, |
---|
88 | | - }; |
---|
89 | | - |
---|
90 | | - mutex_lock(&tb->buf_lock); |
---|
91 | | - tb->tx_buf[0] = reg_addr; |
---|
92 | | - tb->tx_buf[1] = data; |
---|
93 | | - |
---|
94 | | - err = spi_sync_transfer(to_spi_device(dev), &xfers, 1); |
---|
95 | | - mutex_unlock(&tb->buf_lock); |
---|
96 | | - |
---|
97 | | - return err; |
---|
98 | | -} |
---|
99 | | - |
---|
100 | | -static const struct st_sensor_transfer_function st_sensors_tf_spi = { |
---|
101 | | - .read_byte = st_sensors_spi_read_byte, |
---|
102 | | - .write_byte = st_sensors_spi_write_byte, |
---|
103 | | - .read_multiple_byte = st_sensors_spi_read_multiple_byte, |
---|
| 22 | +static const struct regmap_config st_sensors_spi_regmap_config = { |
---|
| 23 | + .reg_bits = 8, |
---|
| 24 | + .val_bits = 8, |
---|
104 | 25 | }; |
---|
105 | 26 | |
---|
106 | | -void st_sensors_spi_configure(struct iio_dev *indio_dev, |
---|
107 | | - struct spi_device *spi, struct st_sensor_data *sdata) |
---|
| 27 | +static const struct regmap_config st_sensors_spi_regmap_multiread_bit_config = { |
---|
| 28 | + .reg_bits = 8, |
---|
| 29 | + .val_bits = 8, |
---|
| 30 | + .read_flag_mask = ST_SENSORS_SPI_MULTIREAD, |
---|
| 31 | +}; |
---|
| 32 | + |
---|
| 33 | +/* |
---|
| 34 | + * st_sensors_is_spi_3_wire() - check if SPI 3-wire mode has been selected |
---|
| 35 | + * @spi: spi device reference. |
---|
| 36 | + * |
---|
| 37 | + * Return: true if SPI 3-wire mode is selected, false otherwise. |
---|
| 38 | + */ |
---|
| 39 | +static bool st_sensors_is_spi_3_wire(struct spi_device *spi) |
---|
108 | 40 | { |
---|
| 41 | + struct st_sensors_platform_data *pdata; |
---|
| 42 | + struct device *dev = &spi->dev; |
---|
| 43 | + |
---|
| 44 | + if (device_property_read_bool(dev, "spi-3wire")) |
---|
| 45 | + return true; |
---|
| 46 | + |
---|
| 47 | + pdata = dev_get_platdata(dev); |
---|
| 48 | + if (pdata && pdata->spi_3wire) |
---|
| 49 | + return true; |
---|
| 50 | + |
---|
| 51 | + return false; |
---|
| 52 | +} |
---|
| 53 | + |
---|
| 54 | +/* |
---|
| 55 | + * st_sensors_configure_spi_3_wire() - configure SPI 3-wire if needed |
---|
| 56 | + * @spi: spi device reference. |
---|
| 57 | + * @settings: sensor specific settings reference. |
---|
| 58 | + * |
---|
| 59 | + * Return: 0 on success, else a negative error code. |
---|
| 60 | + */ |
---|
| 61 | +static int st_sensors_configure_spi_3_wire(struct spi_device *spi, |
---|
| 62 | + struct st_sensor_settings *settings) |
---|
| 63 | +{ |
---|
| 64 | + if (settings->sim.addr) { |
---|
| 65 | + u8 buffer[] = { |
---|
| 66 | + settings->sim.addr, |
---|
| 67 | + settings->sim.value |
---|
| 68 | + }; |
---|
| 69 | + |
---|
| 70 | + return spi_write(spi, buffer, 2); |
---|
| 71 | + } |
---|
| 72 | + |
---|
| 73 | + return 0; |
---|
| 74 | +} |
---|
| 75 | + |
---|
| 76 | +/* |
---|
| 77 | + * st_sensors_spi_configure() - configure SPI interface |
---|
| 78 | + * @indio_dev: IIO device reference. |
---|
| 79 | + * @spi: spi device reference. |
---|
| 80 | + * |
---|
| 81 | + * Return: 0 on success, else a negative error code. |
---|
| 82 | + */ |
---|
| 83 | +int st_sensors_spi_configure(struct iio_dev *indio_dev, |
---|
| 84 | + struct spi_device *spi) |
---|
| 85 | +{ |
---|
| 86 | + struct st_sensor_data *sdata = iio_priv(indio_dev); |
---|
| 87 | + const struct regmap_config *config; |
---|
| 88 | + int err; |
---|
| 89 | + |
---|
| 90 | + if (st_sensors_is_spi_3_wire(spi)) { |
---|
| 91 | + err = st_sensors_configure_spi_3_wire(spi, |
---|
| 92 | + sdata->sensor_settings); |
---|
| 93 | + if (err < 0) |
---|
| 94 | + return err; |
---|
| 95 | + } |
---|
| 96 | + |
---|
| 97 | + if (sdata->sensor_settings->multi_read_bit) |
---|
| 98 | + config = &st_sensors_spi_regmap_multiread_bit_config; |
---|
| 99 | + else |
---|
| 100 | + config = &st_sensors_spi_regmap_config; |
---|
| 101 | + |
---|
| 102 | + sdata->regmap = devm_regmap_init_spi(spi, config); |
---|
| 103 | + if (IS_ERR(sdata->regmap)) { |
---|
| 104 | + dev_err(&spi->dev, "Failed to register spi regmap (%ld)\n", |
---|
| 105 | + PTR_ERR(sdata->regmap)); |
---|
| 106 | + return PTR_ERR(sdata->regmap); |
---|
| 107 | + } |
---|
| 108 | + |
---|
109 | 109 | spi_set_drvdata(spi, indio_dev); |
---|
110 | 110 | |
---|
111 | | - indio_dev->dev.parent = &spi->dev; |
---|
112 | 111 | indio_dev->name = spi->modalias; |
---|
113 | 112 | |
---|
114 | 113 | sdata->dev = &spi->dev; |
---|
115 | | - sdata->tf = &st_sensors_tf_spi; |
---|
116 | | - sdata->get_irq_data_ready = st_sensors_spi_get_irq; |
---|
| 114 | + sdata->irq = spi->irq; |
---|
| 115 | + |
---|
| 116 | + return 0; |
---|
117 | 117 | } |
---|
118 | 118 | EXPORT_SYMBOL(st_sensors_spi_configure); |
---|
119 | 119 | |
---|