Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1507966 > unrolled thread
| Started by | tnhuynh@apm.com |
|---|---|
| First post | 2016-10-25 06:40 +0200 |
| Last post | 2016-10-26 11:40 +0200 |
| Articles | 6 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH v1] I2C Designware Core Supports SMBUS BLOCK tnhuynh@apm.com - 2016-10-25 06:40 +0200
Re: [PATCH v1] I2C Designware Core Supports SMBUS BLOCK Jarkko Nikula <jarkko.nikula@linux.intel.com> - 2016-10-25 10:00 +0200
Re: [PATCH v1] I2C Designware Core Supports SMBUS BLOCK Mika Westerberg <mika.westerberg@linux.intel.com> - 2016-10-25 14:00 +0200
Re: [PATCH v1] I2C Designware Core Supports SMBUS BLOCK Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2016-10-25 14:50 +0200
Re: [PATCH v1] I2C Designware Core Supports SMBUS BLOCK Mika Westerberg <mika.westerberg@linux.intel.com> - 2016-10-26 10:30 +0200
Re: [PATCH v1] I2C Designware Core Supports SMBUS BLOCK Mika Westerberg <mika.westerberg@linux.intel.com> - 2016-10-26 11:40 +0200
| From | tnhuynh@apm.com |
|---|---|
| Date | 2016-10-25 06:40 +0200 |
| Subject | [PATCH v1] I2C Designware Core Supports SMBUS BLOCK |
| Message-ID | <sw1GN-Jo-1@gated-at.bofh.it> |
From: Tin Huynh <tnhuynh@apm.com>
Free and Open IPMI use SMBUS BLOCK Read/Write to support SSIF protocol.
However, I2C Designwave Core Driver doesn't handle the case at the moment.
The below patch supports this feature.
Signed-off-by: Tin Huynh <tnhuynh@apm.com>
---
drivers/i2c/busses/i2c-designware-core.c | 42 +++++++++++++++++++++++++--
drivers/i2c/busses/i2c-designware-platdrv.c | 1 +
2 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 1fe93c4..3abf0e5 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -588,8 +588,17 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
* detected from the registers so we set it always
* when writing/reading the last byte.
*/
+
+ /*
+ * i2c-core.c always set the buffer length of
+ * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
+ * be adjusted when receiving the first byte.
+ * Thus we can't stop the transaction here.
+ */
+
if (dev->msg_write_idx == dev->msgs_num - 1 &&
- buf_len == 1)
+ buf_len == 1 &&
+ !(msgs[dev->msg_write_idx].flags & I2C_M_RECV_LEN))
cmd |= BIT(9);
if (need_restart) {
@@ -614,7 +623,14 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
dev->tx_buf = buf;
dev->tx_buf_len = buf_len;
- if (buf_len > 0) {
+ /*
+ * Because we don't know the buffer length in the
+ * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
+ * the transcation here.
+ */
+
+ if (buf_len > 0 ||
+ msgs[dev->msg_write_idx].flags & I2C_M_RECV_LEN) {
/* more bytes to be written */
dev->status |= STATUS_WRITE_IN_PROGRESS;
break;
@@ -659,7 +675,27 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
rx_valid = dw_readl(dev, DW_IC_RXFLR);
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
- *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+ *buf = dw_readl(dev, DW_IC_DATA_CMD);
+ /* ensure length byte is a valid value */
+ if (msgs[dev->msg_read_idx].flags & I2C_M_RECV_LEN
+ && *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
+ /*
+ * Adjust the buffer length and mask the flag
+ * after receiving the first byte
+ */
+ msgs[dev->msg_read_idx].flags &=
+ ~I2C_M_RECV_LEN;
+ len = *buf + 1;
+ /* Increase one with PEC flag */
+ if (msgs[dev->msg_read_idx].flags &
+ I2C_CLIENT_PEC)
+ len++;
+
+ dev->tx_buf_len = len > dev->rx_outstanding ?
+ len - dev->rx_outstanding : 0;
+ msgs[dev->msg_read_idx].len = len;
+ }
+ buf++;
dev->rx_outstanding--;
}
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0b42a12..886fb62 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -220,6 +220,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
--
1.7.1
--
CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is
for the sole use of the intended recipient(s) and contains information that
is confidential and proprietary to Applied Micro Circuits Corporation or
its subsidiaries. It is to be used solely for the purpose of furthering the
parties' business relationship. All unauthorized review, use, disclosure or
distribution is prohibited. If you are not the intended recipient, please
contact the sender by reply e-mail and destroy all copies of the original
message.
[toc] | [next] | [standalone]
| From | Jarkko Nikula <jarkko.nikula@linux.intel.com> |
|---|---|
| Date | 2016-10-25 10:00 +0200 |
| Message-ID | <sw4Om-2CC-19@gated-at.bofh.it> |
| In reply to | #1507966 |
Hi On 10/25/2016 07:35 AM, tnhuynh@apm.com wrote: > --- a/drivers/i2c/busses/i2c-designware-platdrv.c > +++ b/drivers/i2c/busses/i2c-designware-platdrv.c > @@ -220,6 +220,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) > I2C_FUNC_SMBUS_BYTE | > I2C_FUNC_SMBUS_BYTE_DATA | > I2C_FUNC_SMBUS_WORD_DATA | > + I2C_FUNC_SMBUS_BLOCK_DATA | > I2C_FUNC_SMBUS_I2C_BLOCK; > I guess you need to add the same to DW_DEFAULT_FUNCTIONALITY in drivers/i2c/busses/i2c-designware-pcidrv.c too. -- Jarkko
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2016-10-25 14:00 +0200 |
| Message-ID | <sw8yB-56M-3@gated-at.bofh.it> |
| In reply to | #1507966 |
On Tue, Oct 25, 2016 at 11:35:13AM +0700, tnhuynh@apm.com wrote:
> From: Tin Huynh <tnhuynh@apm.com>
>
> Free and Open IPMI use SMBUS BLOCK Read/Write to support SSIF protocol.
> However, I2C Designwave Core Driver doesn't handle the case at the moment.
> The below patch supports this feature.
>
> Signed-off-by: Tin Huynh <tnhuynh@apm.com>
> ---
> drivers/i2c/busses/i2c-designware-core.c | 42 +++++++++++++++++++++++++--
> drivers/i2c/busses/i2c-designware-platdrv.c | 1 +
> 2 files changed, 40 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
> index 1fe93c4..3abf0e5 100644
> --- a/drivers/i2c/busses/i2c-designware-core.c
> +++ b/drivers/i2c/busses/i2c-designware-core.c
> @@ -588,8 +588,17 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
> * detected from the registers so we set it always
> * when writing/reading the last byte.
> */
> +
> + /*
> + * i2c-core.c always set the buffer length of
> + * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
> + * be adjusted when receiving the first byte.
> + * Thus we can't stop the transaction here.
> + */
> +
No empty line here.
> if (dev->msg_write_idx == dev->msgs_num - 1 &&
> - buf_len == 1)
> + buf_len == 1 &&
> + !(msgs[dev->msg_write_idx].flags & I2C_M_RECV_LEN))
Why not store flags somewhere in local variable. Then you do not need
the ugly line splitting above.
So instead
if (dev->msg_write_idx == dev->msgs_num -1 &&
buf_len == 1 && !(flags & I2C_M_RECV_LEN))
but even that starts to require small helper function, I think.
> cmd |= BIT(9);
>
> if (need_restart) {
> @@ -614,7 +623,14 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
> dev->tx_buf = buf;
> dev->tx_buf_len = buf_len;
>
> - if (buf_len > 0) {
> + /*
> + * Because we don't know the buffer length in the
> + * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
> + * the transcation here.
^^^^^^^^^^^
transaction
> + */
> +
No empty line here.
> + if (buf_len > 0 ||
> + msgs[dev->msg_write_idx].flags & I2C_M_RECV_LEN) {
Here also same comments about "flags".
> /* more bytes to be written */
> dev->status |= STATUS_WRITE_IN_PROGRESS;
> break;
> @@ -659,7 +675,27 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
> rx_valid = dw_readl(dev, DW_IC_RXFLR);
>
> for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
> - *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
> + *buf = dw_readl(dev, DW_IC_DATA_CMD);
> + /* ensure length byte is a valid value */
> + if (msgs[dev->msg_read_idx].flags & I2C_M_RECV_LEN
> + && *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
And here. Also you have " " between I2C_SMBUS_BLOCK_MAX and &&.
> + /*
> + * Adjust the buffer length and mask the flag
> + * after receiving the first byte
> + */
> + msgs[dev->msg_read_idx].flags &=
> + ~I2C_M_RECV_LEN;
And here.
Actually you should move the whole block into a helper function.
> + len = *buf + 1;
> + /* Increase one with PEC flag */
> + if (msgs[dev->msg_read_idx].flags &
> + I2C_CLIENT_PEC)
> + len++;
> +
> + dev->tx_buf_len = len > dev->rx_outstanding ?
> + len - dev->rx_outstanding : 0;
> + msgs[dev->msg_read_idx].len = len;
> + }
> + buf++;
> dev->rx_outstanding--;
> }
>
> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
> index 0b42a12..886fb62 100644
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> @@ -220,6 +220,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
> I2C_FUNC_SMBUS_BYTE |
> I2C_FUNC_SMBUS_BYTE_DATA |
> I2C_FUNC_SMBUS_WORD_DATA |
> + I2C_FUNC_SMBUS_BLOCK_DATA |
> I2C_FUNC_SMBUS_I2C_BLOCK;
>
> dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
> --
> 1.7.1
>
>
> --
> CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is
> for the sole use of the intended recipient(s) and contains information that
> is confidential and proprietary to Applied Micro Circuits Corporation or
> its subsidiaries. It is to be used solely for the purpose of furthering the
> parties' business relationship. All unauthorized review, use, disclosure or
> distribution is prohibited. If you are not the intended recipient, please
> contact the sender by reply e-mail and destroy all copies of the original
> message.
Yeah, right.
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
|---|---|
| Date | 2016-10-25 14:50 +0200 |
| Message-ID | <sw9kZ-5I1-13@gated-at.bofh.it> |
| In reply to | #1508230 |
On Tue, 2016-10-25 at 14:50 +0300, Mika Westerberg wrote: > On Tue, Oct 25, 2016 at 11:35:13AM +0700, tnhuynh@apm.com wrote: > > -- > > CONFIDENTIALITY NOTICE: This e-mail message, including any > > attachments, is > > for the sole use of the intended recipient(s) and contains > > information that > > is confidential and proprietary to Applied Micro Circuits > > Corporation or > > its subsidiaries. It is to be used solely for the purpose of > > furthering the > > parties' business relationship. All unauthorized review, use, > > disclosure or > > distribution is prohibited. If you are not the intended recipient, > > please > > contact the sender by reply e-mail and destroy all copies of the > > original > > message. Tin Huynh, if you want to continue, you *have to* get rid of this footer, otherwise no one is going to commit even *the best feature ever*. Perhaps you need to talk to your lawyers first. -- Andy Shevchenko <andriy.shevchenko@linux.intel.com> Intel Finland Oy
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2016-10-26 10:30 +0200 |
| Message-ID | <swrKW-14e-11@gated-at.bofh.it> |
| In reply to | #1508230 |
On Wed, Oct 26, 2016 at 02:26:05PM +0700, Tin Huynh wrote: > But can you explain more about 'but even that starts to require small > helper function'? So you could add a small function i2c_dw_xfer_need_stop() that returns true if you need to set the stop bit.
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2016-10-26 11:40 +0200 |
| Message-ID | <swsQG-1Lu-7@gated-at.bofh.it> |
| In reply to | #1508926 |
On Wed, Oct 26, 2016 at 04:20:57PM +0700, Tin Huynh wrote: > We need to set stop bit if three conditions are true : The latest > bytes , the latest msg_write_ids and after receiving the buffer length. > If we use i2c_dw_xfer_need_stop , arguments of function are complex. OK, so you would need to pass dev and buf_len to that. > Can i use i2c_dw_xfer_receive_length() function ? > Thank you and best regards > Tin > if (dev->msg_write_idx == dev->msgs_num - 1 && > - buf_len == 1) > + buf_len == 1 && !(flags & I2C_M_RECV_LEN)) > cmd |= BIT(9); Maybe it is better if you just do it like the above then.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web