iio: add driver for Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X
Subsystems (2)
PATCH v3 1/1 iio: add driver for Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X
The following functionalities are supported:
- write, read from volatile memory
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
---
Changes since v2:
- Removed unnecessary parentheses in MCP4131_WIPER_SHIFT macro
- Replaced the rx and tx SPI buffers with one buf that is ____cacheline_aligned
- Changed mutex locking position
- Replaced the devid with pointer to model configuration
- Removed positive ("Registered" & "Unregistered") dev_info prints
- Removed the mcp4131_remove callback
Changes since v1:
- One line summary changed
- Fixed module name and OF compatible
- Based code on Peter Rosin's code from mcp4531.c
- No additional sysfs attributes
- Deleted not used devid struct memeber
- Changed mcp4131_exec function arguments:
- write value is now u16
- no need to pass return buffer array - rx array from mcp4131_data is used
- Added missing new line characters to dev_info
--- .../bindings/iio/potentiometer/mcp4131.txt | 84 ++++ drivers/iio/potentiometer/Kconfig | 18 + drivers/iio/potentiometer/Makefile | 1 + drivers/iio/potentiometer/mcp4131.c | 520 +++++++++++++++++++++ 4 files changed, 623 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/potentiometer/mcp4131.txt create mode 100644 drivers/iio/potentiometer/mcp4131.c
Documentation/devicetree/bindings/iio/potentiometer/mcp4131.txt new file +84 -0
@@ -0,0 +1,84 @@ +* Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer + driver + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "microchip,mcp4131-502" + "microchip,mcp4131-103" + "microchip,mcp4131-503" + "microchip,mcp4131-104" + "microchip,mcp4132-502" + "microchip,mcp4132-103" + "microchip,mcp4132-503" + "microchip,mcp4132-104" + "microchip,mcp4141-502" + "microchip,mcp4141-103" + "microchip,mcp4141-503" + "microchip,mcp4141-104" + "microchip,mcp4142-502" + "microchip,mcp4142-103" + "microchip,mcp4142-503" + "microchip,mcp4142-104" + "microchip,mcp4151-502" + "microchip,mcp4151-103" + "microchip,mcp4151-503" + "microchip,mcp4151-104" + "microchip,mcp4152-502" + "microchip,mcp4152-103" + "microchip,mcp4152-503" + "microchip,mcp4152-104" + "microchip,mcp4161-502" + "microchip,mcp4161-103" + "microchip,mcp4161-503" + "microchip,mcp4161-104" + "microchip,mcp4162-502" + "microchip,mcp4162-103" + "microchip,mcp4162-503" + "microchip,mcp4162-104" + "microchip,mcp4231-502" + "microchip,mcp4231-103" + "microchip,mcp4231-503" + "microchip,mcp4231-104" + "microchip,mcp4232-502" + "microchip,mcp4232-103" + "microchip,mcp4232-503" + "microchip,mcp4232-104" + "microchip,mcp4241-502" + "microchip,mcp4241-103" + "microchip,mcp4241-503" + "microchip,mcp4241-104" + "microchip,mcp4242-502" + "microchip,mcp4242-103" + "microchip,mcp4242-503" + "microchip,mcp4242-104" + "microchip,mcp4251-502" + "microchip,mcp4251-103" + "microchip,mcp4251-503" + "microchip,mcp4251-104" + "microchip,mcp4252-502" + "microchip,mcp4252-103" + "microchip,mcp4252-503" + "microchip,mcp4252-104" + "microchip,mcp4261-502" + "microchip,mcp4261-103" + "microchip,mcp4261-503" + "microchip,mcp4261-104" + "microchip,mcp4262-502" + "microchip,mcp4262-103" + "microchip,mcp4262-503" + "microchip,mcp4262-104" + +Example: +mcp4131: mcp4131@0 { + compatible = "mcp4131-502"; + reg = <0>; + spi-max-frequency = <500000>; +};
drivers/iio/potentiometer/Kconfig +18 -0
@@ -5,6 +5,24 @@ menu "Digital potentiometers" +config MCP4131 + tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver" + depends on SPI + help + Say yes here to build support for the Microchip + MCP4131, MCP4132, + MCP4141, MCP4142, + MCP4151, MCP4152, + MCP4161, MCP4162, + MCP4231, MCP4232, + MCP4241, MCP4242, + MCP4251, MCP4252, + MCP4261, MCP4262, + digital potentiomenter chips. + + To compile this driver as a module, choose M here: the + module will be called mcp4131. + config MCP4531 tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver" depends on I2C
drivers/iio/potentiometer/Makefile +1 -0
@@ -3,4 +3,5 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_MCP4131) += mcp4131.o obj-$(CONFIG_MCP4531) += mcp4531.o
drivers/iio/potentiometer/mcp4131.c new file +520 -0
520 lines not on this page · raw message
Signature · 1 line
2.7.3
Hi Slawomir,
Quoted 2 lines · Slawomir Stepien
The following functionalities are supported:
- write, read from volatile memory
I think it would be useful if you could put 'potentiometer' either in the subject and/or commit text so it is more obvious what this driver is for.
Quoted 57 lines
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
Signed-off-by Slawomir Stepien <[email protected]>drivers/iio/potentiometer/mcp4131.c new file +53
-0+ +struct mcp4131_data { +struct spi_device *spi; +const struct mcp4131_cfg *cfg; +struct mutex lock; +struct spi_transfer xfer; +struct spi_message msg; +u8 buf[2 ]____cacheline_aligned ; +}; + +#define MCP4131_CHANNEL (ch) { \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec mcp4131_channels[] = { +MCP4131_CHANNEL (0 ), +MCP4131_CHANNEL (1 ), +}; + +static int mcp4131_exec (struct mcp4131_data *data, +u8 addr,u8 cmd, +u16 val) +{ +int err; +struct spi_device *spi = data->spi; + + data->xfer.tx_buf = data->buf; + data->xfer.rx_buf = data->buf; + +switch (cmd) { +case MCP4131_READ : + data->xfer.len =2 ;/* Two bytes transfer for this command */ + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) |MCP4131_READ ; + data->buf[1 ] =0 ; +break ; + +case MCP4131_WRITE : + data->xfer.len =2 ; + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) | +MCP4131_WRITE | (val >>8 ); + data->buf[1 ] = val &0xFF ;/* 8 bits here */ +break ; + +default : +return -EINVAL ; + } + + dev_dbg(&spi->dev, "mcp4131_exec: tx0: 0x%x tx1: 0x%x\n",
drivers/iio/potentiometer/mcp4131.c line 187
Quoted 10 lines
drivers/iio/potentiometer/mcp4131.c new file +10
-0+ data->buf[0], data->buf[1]); + +spi_message_init (&data->msg); +spi_message_add_tail (&data->xfer, &data->msg); + + err =spi_sync (spi, &data->msg); +if (err) { +dev_err (&spi->dev,"spi_sync(): %d\n" , err); +return err; + }
Isn't this init, add, sync sequence basically open coding of what spi_write/spi_read does?
If you could use those you could also get rid transfer/message structs in priv data.
Also it these any reason why the data buffer can just be a local variable in mcp4131_read_raw/mcp4131_write_raw?
If it could be I think it should be possible to move the lock into the mcp4131_exec function.
Quoted 29 lines
drivers/iio/potentiometer/mcp4131.c new file +29
-0+ +dev_dbg (&spi->dev,"mcp4131_exec: rx0: 0x%x rx1: 0x%x\n" , + data->buf[0 ], data->buf[1 ]); + +return 0 ; +} + +static int mcp4131_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int *val,int *val2,long mask) +{ +int err; +struct mcp4131_data *data =iio_priv (indio_dev); +int address = chan->channel; + +mutex_lock (&data->lock); + +switch (mask) { +case IIO_CHAN_INFO_RAW : + err =mcp4131_exec (data, address,MCP4131_READ ,0 ); +if (err) { +mutex_unlock (&data->lock); +return err; + } + +/* Error, bad address/command combination */ +if (!MCP4131_CMDERR (data->buf)) { +mutex_unlock (&data->lock); +return -EIO ;
drivers/iio/potentiometer/mcp4131.c line 226
Quoted 10 lines
drivers/iio/potentiometer/mcp4131.c new file +10
-0+ } + + *val =MCP4131_RAW (data->buf); +mutex_unlock (&data->lock); +return IIO_VAL_INT ; + +case IIO_CHAN_INFO_SCALE : + *val =1000 * data->cfg->kohms; + *val2 = data->cfg->max_pos; +mutex_unlock (&data->lock);
Is locking really necessary for IIO_CHAN_INFO_SCALE? Isn't all data->cfg stuff constant?
Quoted 22 lines
drivers/iio/potentiometer/mcp4131.c new file +22
-0+return IIO_VAL_FRACTIONAL ; + } + +mutex_unlock (&data->lock); + +return -EINVAL ; +} + +static int mcp4131_write_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int val,int val2,long mask) +{ +int err; +struct mcp4131_data *data =iio_priv (indio_dev); +int address = chan->channel <<MCP4131_WIPER_SHIFT ; + +mutex_lock (&data->lock); + +switch (mask) { +case IIO_CHAN_INFO_RAW : +if (val > data->cfg->max_pos || val <0 ) { +mutex_unlock (&data->lock);
drivers/iio/potentiometer/mcp4131.c line 258
Quoted 10 lines
drivers/iio/potentiometer/mcp4131.c new file +10
-0+return -EINVAL ; + } +break ; +default : +mutex_unlock (&data->lock); +return -EINVAL ; + } + + err =mcp4131_exec (data, address,MCP4131_WRITE , val); +mutex_unlock (&data->lock);
While this is not a huge function it is usually good practice to keep the locking scope as small as possible.
So wouldn't this be sufficient here.
mutex_lock(&data->lock);
err = mcp4131_exec(data, address, MCP4131_WRITE, val);
mutex_unlock(&data->lock);Of course if you are able move the lock into mcp4131_exec this will go away.
regards,
Joachim Eastwood
Quoted 9 lines · Joachim Eastwood
Hi Slawomir,
Quoted 2 lines · Slawomir Stepien
The following functionalities are supported:
- write, read from volatile memoryI think it would be useful if you could put 'potentiometer' either in the subject and/or commit text so it is more obvious what this driver is for.
Ok
Quoted 9 lines
drivers/iio/potentiometer/mcp4131.c line 187
Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c new file +8
-0+spi_message_init (&data->msg); +spi_message_add_tail (&data->xfer, &data->msg); + + err =spi_sync (spi, &data->msg); +if (err) { +dev_err (&spi->dev,"spi_sync(): %d\n" , err); +return err; + }
Quoted 8 lines
Isn't this init, add, sync sequence basically open coding of what spi_write/spi_read does?
If you could use those you could also get rid transfer/message structs in priv data.
Also it these any reason why the data buffer can just be a local variable in mcp4131_read_raw/mcp4131_write_raw?
If it could be I think it should be possible to move the lock into themcp4131_execfunction.
Ok I'll try that.
Quoted 7 lines
drivers/iio/potentiometer/mcp4131.c line 226
Quoted 4 lines
drivers/iio/potentiometer/mcp4131.c new file +4
-0+case IIO_CHAN_INFO_SCALE : + *val =1000 * data->cfg->kohms; + *val2 = data->cfg->max_pos; +mutex_unlock (&data->lock);Is locking really necessary for
IIO_CHAN_INFO_SCALE? Isn't alldata->cfgstuff constant?
Yes you're right here. Didn't see it like that.
Quoted 28 lines
Quoted 14 lines
drivers/iio/potentiometer/mcp4131.c new file +14
-0+static int mcp4131_write_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int val,int val2,long mask) +{ +int err; +struct mcp4131_data *data =iio_priv (indio_dev); +int address = chan->channel <<MCP4131_WIPER_SHIFT ; + +mutex_lock (&data->lock); + +switch (mask) { +case IIO_CHAN_INFO_RAW : +if (val > data->cfg->max_pos || val <0 ) { +mutex_unlock (&data->lock);drivers/iio/potentiometer/mcp4131.c line 258
Quoted 10 lines
drivers/iio/potentiometer/mcp4131.c new file +10
-0+return -EINVAL ; + } +break ; +default : +mutex_unlock (&data->lock); +return -EINVAL ; + } + + err =mcp4131_exec (data, address,MCP4131_WRITE , val); +mutex_unlock (&data->lock);While this is not a huge function it is usually good practice to keep the locking scope as small as possible.
Quoted 6 lines
So wouldn't this be sufficient here.
mutex_lock(&data->lock); err = mcp4131_exec(data, address, MCP4131_WRITE, val); mutex_unlock(&data->lock);Of course if you are able move the lock into
mcp4131_execthis will go away.
I'll see if it's possible to move the whole locking into this function.
Thank you for comments.
Quoted 2 lines
regards,
Joachim Eastwood
Signature · 1 line
Slawomir Stepien
Jonathan Cameron
maintainerQuoted 74 lines · Joachim Eastwood
Hi Slawomir,
Quoted 2 lines · Slawomir Stepien
The following functionalities are supported:
- write, read from volatile memoryI think it would be useful if you could put 'potentiometer' either in the subject and/or commit text so it is more obvious what this driver is for.
Quoted 64 lines
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
Signed-off-by Slawomir Stepien <[email protected]>drivers/iio/potentiometer/mcp4131.c new file +60
-0+ +struct mcp4131_data { +struct spi_device *spi; +const struct mcp4131_cfg *cfg; +struct mutex lock; +struct spi_transfer xfer; +struct spi_message msg; +u8 buf[2 ]____cacheline_aligned ; +}; + +#define MCP4131_CHANNEL (ch) { \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec mcp4131_channels[] = { +MCP4131_CHANNEL (0 ), +MCP4131_CHANNEL (1 ), +}; + +static int mcp4131_exec (struct mcp4131_data *data, +u8 addr,u8 cmd, +u16 val) +{ +int err; +struct spi_device *spi = data->spi; + + data->xfer.tx_buf = data->buf; + data->xfer.rx_buf = data->buf; + +switch (cmd) { +case MCP4131_READ : + data->xfer.len =2 ;/* Two bytes transfer for this command */ + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) |MCP4131_READ ; + data->buf[1 ] =0 ; +break ; + +case MCP4131_WRITE : + data->xfer.len =2 ; + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) | +MCP4131_WRITE | (val >>8 ); + data->buf[1 ] = val &0xFF ;/* 8 bits here */ +break ; + +default : +return -EINVAL ; + } + +dev_dbg (&spi->dev,"mcp4131_exec: tx0: 0x%x tx1: 0x%x\n" , + data->buf[0 ], data->buf[1 ]); + +spi_message_init (&data->msg); +spi_message_add_tail (&data->xfer, &data->msg); + + err =spi_sync (spi, &data->msg); +if (err) {
Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c line 187
Quoted 3 lines
drivers/iio/potentiometer/mcp4131.c new file +3
-0+dev_err (&spi->dev,"spi_sync(): %d\n" , err); +return err; + }Isn't this init, add, sync sequence basically open coding of what spi_write/spi_read does?
If you could use those you could also get rid transfer/message structs in priv data.
I initially wrote the same comment, then realised it's more nuanced than that. Whilst this initially looks like an w8r8 type cycle it's actually something like w4r12 in the read case anyway. The write case could indeed be done with spi_write.
Quoted 3 lines
Also it these any reason why the data buffer can just be a local variable in mcp4131_read_raw/mcp4131_write_raw?
Only with if it is allocated on the heap as required to enforce the rule it is on a separate cache line. Much easier to do that once!
Quoted 94 lines
If it could be I think it should be possible to move the lock into the
mcp4131_execfunction.Quoted 29 lines
drivers/iio/potentiometer/mcp4131.c new file +29
-0+ +dev_dbg (&spi->dev,"mcp4131_exec: rx0: 0x%x rx1: 0x%x\n" , + data->buf[0 ], data->buf[1 ]); + +return 0 ; +} + +static int mcp4131_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int *val,int *val2,long mask) +{ +int err; +struct mcp4131_data *data =iio_priv (indio_dev); +int address = chan->channel; + +mutex_lock (&data->lock); + +switch (mask) { +case IIO_CHAN_INFO_RAW : + err =mcp4131_exec (data, address,MCP4131_READ ,0 ); +if (err) { +mutex_unlock (&data->lock); +return err; + } + +/* Error, bad address/command combination */ +if (!MCP4131_CMDERR (data->buf)) { +mutex_unlock (&data->lock); +return -EIO ;drivers/iio/potentiometer/mcp4131.c line 226
Quoted 10 lines
drivers/iio/potentiometer/mcp4131.c new file +10
-0+ } + + *val =MCP4131_RAW (data->buf); +mutex_unlock (&data->lock); +return IIO_VAL_INT ; + +case IIO_CHAN_INFO_SCALE : + *val =1000 * data->cfg->kohms; + *val2 = data->cfg->max_pos; +mutex_unlock (&data->lock);Is locking really necessary for
IIO_CHAN_INFO_SCALE? Isn't alldata->cfgstuff constant?Quoted 22 lines
drivers/iio/potentiometer/mcp4131.c new file +22
-0+return IIO_VAL_FRACTIONAL ; + } + +mutex_unlock (&data->lock); + +return -EINVAL ; +} + +static int mcp4131_write_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int val,int val2,long mask) +{ +int err; +struct mcp4131_data *data =iio_priv (indio_dev); +int address = chan->channel <<MCP4131_WIPER_SHIFT ; + +mutex_lock (&data->lock); + +switch (mask) { +case IIO_CHAN_INFO_RAW : +if (val > data->cfg->max_pos || val <0 ) { +mutex_unlock (&data->lock);drivers/iio/potentiometer/mcp4131.c line 258
Quoted 10 lines
drivers/iio/potentiometer/mcp4131.c new file +10
-0+return -EINVAL ; + } +break ; +default : +mutex_unlock (&data->lock); +return -EINVAL ; + } + + err =mcp4131_exec (data, address,MCP4131_WRITE , val); +mutex_unlock (&data->lock);While this is not a huge function it is usually good practice to keep the locking scope as small as possible.
So wouldn't this be sufficient here.
mutex_lock(&data->lock); err = mcp4131_exec(data, address, MCP4131_WRITE, val); mutex_unlock(&data->lock);Of course if you are able move the lock into
mcp4131_execthis will go away.regards,
Joachim Eastwood
Hi Jonathan,
Quoted 45 lines · Jonathan Cameron
Quoted 36 lines · Joachim Eastwood
Quoted 36 lines
drivers/iio/potentiometer/mcp4131.c new file +36
-0+static int mcp4131_exec (struct mcp4131_data *data, +u8 addr,u8 cmd, +u16 val) +{ +int err; +struct spi_device *spi = data->spi; + + data->xfer.tx_buf = data->buf; + data->xfer.rx_buf = data->buf; + +switch (cmd) { +case MCP4131_READ : + data->xfer.len =2 ;/* Two bytes transfer for this command */ + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) |MCP4131_READ ; + data->buf[1 ] =0 ; +break ; + +case MCP4131_WRITE : + data->xfer.len =2 ; + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) | +MCP4131_WRITE | (val >>8 ); + data->buf[1 ] = val &0xFF ;/* 8 bits here */ +break ; + +default : +return -EINVAL ; + } + +dev_dbg (&spi->dev,"mcp4131_exec: tx0: 0x%x tx1: 0x%x\n" , + data->buf[0 ], data->buf[1 ]); + +spi_message_init (&data->msg); +spi_message_add_tail (&data->xfer, &data->msg); + + err =spi_sync (spi, &data->msg); +if (err) {Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c line 187
Quoted 3 lines
drivers/iio/potentiometer/mcp4131.c new file +3
-0+dev_err (&spi->dev,"spi_sync(): %d\n" , err); +return err; + }Isn't this init, add, sync sequence basically open coding of what spi_write/spi_read does?
If you could use those you could also get rid transfer/message structs in priv data.
Quoted 4 lines
I initially wrote the same comment, then realised it's more nuanced than that. Whilst this initially looks like an w8r8 type cycle it's actually something like w4r12 in the read case anyway. The write case could indeed be done with
spi_write.
Indeed. I didn't notice that for the read case.
The read case could almost be copy of spi_read, though. One would only need to add ".tx_buf = buf" when setting up the transfer struct, I think. Having it in its a own function with a comment would make it easier to spot the difference.
regards,
Joachim Eastwood
Quoted 57 lines · Joachim Eastwood
Hi Jonathan,
Quoted 14 lines · Jonathan Cameron
Quoted 5 lines · Joachim Eastwood
Quoted 5 lines
drivers/iio/potentiometer/mcp4131.c new file +5
-0+static int mcp4131_exec (struct mcp4131_data *data, +u8 addr,u8 cmd, +u16 val) +{ +int err;Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c
Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c new file +8
-0+struct spi_device *spi = data->spi; + + data->xfer.tx_buf = data->buf; + data->xfer.rx_buf = data->buf; + +switch (cmd) { +case MCP4131_READ : + data->xfer.len =2 ;/* Two bytes transfer for this command */
Quoted 1 line
Quoted 1 line
Quoted 1 line
+ data->buf[0] = (addr <<
MCP4131_WIPER_SHIFT) |
MCP4131_READ;Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
drivers/iio/potentiometer/mcp4131.c new file +21
-0+ data->buf[1 ] =0 ; +break ; + +case MCP4131_WRITE : + data->xfer.len =2 ; + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) | +MCP4131_WRITE | (val >>8 ); + data->buf[1 ] = val &0xFF ;/* 8 bits here */ +break ; + +default : +return -EINVAL ; + } + +dev_dbg (&spi->dev,"mcp4131_exec: tx0: 0x%x tx1: 0x%x\n" , + data->buf[0 ], data->buf[1 ]); + +spi_message_init (&data->msg); +spi_message_add_tail (&data->xfer, &data->msg); + + err =spi_sync (spi, &data->msg);Quoted 8 lines
Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c line 187
Quoted 4 lines
drivers/iio/potentiometer/mcp4131.c new file +4
-0+if (err) { +dev_err (&spi->dev,"spi_sync(): %d\n" , err); +return err; + }Isn't this init, add, sync sequence basically open coding of what spi_write/spi_read does?
If you could use those you could also get rid transfer/messagestructs
Quoted 2 lines
Quoted 1 line
in priv data.
I initially wrote the same comment, then realised it's more nuanced
than
Quoted 1 line
that. Whilst this initially looks like an w8r8 type cycle it's
actually
Quoted 1 line
something like w4r12 in the read case anyway. The write case could
indeed
Quoted 8 lines
Quoted 1 line
be done with
spi_write.Indeed. I didn't notice that for the read case.
The read case could almost be copy of
spi_read, though. One would only need to add ".tx_buf = buf" when setting up the transfer struct, I think. Having it in its a own function with a comment would make it easier to spot the difference.
Agreed
Quoted 4 lines
regards,
Joachim Eastwood
Signature · 1 line
Sent from my Android device with K-9 Mail. Please excuse my brevity.
Quoted 53 lines · Joachim Eastwood
Hi Jonathan,
Quoted 45 lines · Jonathan Cameron
Quoted 36 lines · Joachim Eastwood
Quoted 36 lines
drivers/iio/potentiometer/mcp4131.c new file +36
-0+static int mcp4131_exec (struct mcp4131_data *data, +u8 addr,u8 cmd, +u16 val) +{ +int err; +struct spi_device *spi = data->spi; + + data->xfer.tx_buf = data->buf; + data->xfer.rx_buf = data->buf; + +switch (cmd) { +case MCP4131_READ : + data->xfer.len =2 ;/* Two bytes transfer for this command */ + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) |MCP4131_READ ; + data->buf[1 ] =0 ; +break ; + +case MCP4131_WRITE : + data->xfer.len =2 ; + data->buf[0 ] = (addr <<MCP4131_WIPER_SHIFT ) | +MCP4131_WRITE | (val >>8 ); + data->buf[1 ] = val &0xFF ;/* 8 bits here */ +break ; + +default : +return -EINVAL ; + } + +dev_dbg (&spi->dev,"mcp4131_exec: tx0: 0x%x tx1: 0x%x\n" , + data->buf[0 ], data->buf[1 ]); + +spi_message_init (&data->msg); +spi_message_add_tail (&data->xfer, &data->msg); + + err =spi_sync (spi, &data->msg); +if (err) {Quoted 8 lines
drivers/iio/potentiometer/mcp4131.c line 187
Quoted 3 lines
drivers/iio/potentiometer/mcp4131.c new file +3
-0+dev_err (&spi->dev,"spi_sync(): %d\n" , err); +return err; + }Isn't this init, add, sync sequence basically open coding of what spi_write/spi_read does?
If you could use those you could also get rid transfer/message structs in priv data.Quoted 4 lines
I initially wrote the same comment, then realised it's more nuanced than that. Whilst this initially looks like an w8r8 type cycle it's actually something like w4r12 in the read case anyway. The write case could indeed be done with
spi_write.
Quoted 6 lines
Indeed. I didn't notice that for the read case.
The read case could almost be copy of
spi_read, though. One would only need to add ".tx_buf = buf" when setting up the transfer struct, I think. Having it in its a own function with a comment would make it easier to spot the difference.
Just to see if I get it.
For write case I should use the spi_write as it is:
case MCP4131_WRITE:
spi_write(...);
For read case I should create new function (e.g. mcp4131_read) that will look like spi_read but with additional tx_buf content so I can read the data on miso?
case MCP4131_READ:
mcp4131_read(...)
Keep the needed buffers (transfer/message) local.
Signature · 1 line
Slawomir Stepien