Re: [PATCH 1/3] i3c: master: Add driver for Synopsys DesignWare IP
Hi Andy, Às 4:35 PM de 7/21/2018, Andy Shevchenko escreveu: > On Fri, Jul 20, 2018 at 11:57 PM, Vitor soares > wrote: >> This patch add driver for Synopsys DesignWare IP on top of >> I3C subsystem patchset proposal V6 > Some of comments below related to style. > But unaligned helpers I think is good to use. > >> +#include Bit operations API eg: GENMASK... >> +#include Clock API eg: master->core_clk = devm_clk_get(&pdev->dev, "core_clk"); >> +#include Completion API eg: struct completion >> +#include Check kernel pointer eg: return PTR_ERR(master->regs); >> +#include Error codes eg: return -ENOTSUPP; >> +#include I3C Master API eg: i3c_master_register() >> +#include Not needed. >> +#include Interrupt API eg: devm_request_irq(). >> +#include >> +#include Used to get io resource. >> +#include this function: readl_poll_timeout_atomic(). >> +#include Module API. >> +#include Platform driver API. >> +#include Reset API. > All of them required? Why? There is some header files that are already included by others header files. Should I add them too? it there any rule for that? Thank for the advice. >> + default: > Just return false here? Yes, it makes more sense. >> + break; >> + } >> + >> + return false; >> + for (i = 0; i < nbytes; i += 4) { >> + u32 data = 0; >> + >> + for (j = 0; j < 4 && (i + j) < nbytes; j++) >> + data |= (u32)bytes[i + j] << (j * 8); > NIH of get_unaligned_le32() > >> + >> + writel(data, master->regs + RX_TX_DATA_PORT); >> + } >> +} >> + >> +static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, >> + u8 *bytes, int nbytes) >> +{ >> + int i, j; >> + >> + for (i = 0; i < nbytes; i += 4) { >> + u32 data; >> + >> + data = readl(master->regs + RX_TX_DATA_PORT); >> + >> + for (j = 0; j < 4 && (i + j) < nbytes; j++) >> + bytes[i + j] = data >> (j * 8); > Ditto put_unaligned_le32() ? > >> + } >> +} > I'm wondering what else you open coded instead of using helpers we already > have. I will see how it works to implement. >> + writel(cmd->cmd_hi, master->regs + COMMAND_QUEUE_PORT); >> + writel(cmd->cmd_lo, master->regs + COMMAND_QUEUE_PORT); > hmm... writesl()? Is there any advantage here? Probably I can use it to fill the TX buffer with this. >> + info->pid = (u64)readl(master->regs + SLV_PID_VALUE); > Why explicit casting? info->pid is u64 size. > >> + u32 r; >> + >> + >> + core_rate = clk_get_rate(master->core_clk); > Too many blank lines in between. For me in that way it's better to filter code parts. Do you think that is not readable? >> + >> + > Ditto. > >> + /* Prepare DAT before launching DAA. */ >> + for (pos = 0; pos < master->maxdevs; pos++) { >> + if (olddevs & BIT(pos)) >> + continue; >> + >> + ret = i3c_master_get_free_addr(m, last_addr + 1); >> + if (ret < 0) >> + return -ENOSPC; >> + master->addrs[pos] = ret; >> + p = (ret >> 6) ^ (ret >> 5) ^ (ret >> 4) ^ (ret >> 3) ^ >> + (ret >> 2) ^ (ret >> 1) ^ ret ^ 1; >> + p = p & 1; > Is it parity calculus? Do we have something implemented in kernel already? > > Btw, > https://urldefense.proofpoint.com/v2/url?u=https-3A__graphics.stanford.edu_-7Eseander_bithacks.html-23ParityNaive&d=DwIBaQ&c=DPL6_X_6JkXFx7AXWqB0tg&r=qVuU64u9x77Y0Kd0PhDK_lpxFgg6PK9PateHwjb_DY0&m=5FpGHBbT8tYA6PB4RT_9O6PJk3v-wYcy1MV59xoqK4I&s=FSJ3EcuoxPtRJWmsk9Yt4s_UH9kxFBam01Xvas2ZFdo&e= > offered this > > v ^= v >> 4; > v &= 0xf; > v = (0x6996 >> v) & 1; I search into the kernel and I didn't find any function for that. In your opinion what shoud I use? Thanks for your feedback. Regards, Vitor Soares
[PATCH v3 1/3] i3c: master: Add driver for Synopsys DesignWare IP
Add driver for Synopsys DesignWare I3C master IP Signed-off-by: Vitor soares --- Change in v3: - Use struct_size() (suggested by Matthew) Change in v2: - Rename some variables - Remove dw_i3c_master_dev_set_info() - Ajust code to match the changes made of i3c subsystem - Use readsl/writesl() to populate TX/RX buffers drivers/i3c/master/Kconfig | 15 + drivers/i3c/master/Makefile|1 + drivers/i3c/master/dw-i3c-master.c | 1216 3 files changed, 1232 insertions(+) create mode 100644 drivers/i3c/master/dw-i3c-master.c diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig index 959b837..2702751 100644 --- a/drivers/i3c/master/Kconfig +++ b/drivers/i3c/master/Kconfig @@ -4,3 +4,18 @@ config CDNS_I3C_MASTER depends on !(ALPHA || PARISC) help Enable this driver if you want to support Cadence I3C master block. + +config DW_I3C_MASTER + tristate "Synospsys DesignWare I3C master driver" + depends on I3C + depends on !(ALPHA || PARISC) + # ALPHA and PARISC needs {read,write}sl() + help + Support for Synopsys DesignWare MIPI I3C Controller. + + For details please see + https://www.synopsys.com/dw/ipdir.php?ds=mipi_i3c + + This driver can also be built as a module. If so, the module + will be called dw-i3c-master. diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile index 4c4304a..fc53939 100644 --- a/drivers/i3c/master/Makefile +++ b/drivers/i3c/master/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_CDNS_I3C_MASTER) += i3c-master-cdns.o +obj-$(CONFIG_DW_I3C_MASTER)+= dw-i3c-master.o diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c new file mode 100644 index 000..a436d0d --- /dev/null +++ b/drivers/i3c/master/dw-i3c-master.c @@ -0,0 +1,1216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_CTRL0x0 +#define DEV_CTRL_ENABLEBIT(31) +#define DEV_CTRL_RESUMEBIT(30) +#define DEV_CTRL_HOT_JOIN_NACK BIT(8) +#define DEV_CTRL_I2C_SLAVE_PRESENT BIT(7) + +#define DEVICE_ADDR0x4 +#define DEV_ADDR_DYNAMIC_ADDR_VALIDBIT(31) +#define DEV_ADDR_DYNAMIC(x)(((x) << 16) & GENMASK(22, 16)) + +#define HW_CAPABILITY 0x8 +#define COMMAND_QUEUE_PORT 0xc +#define COMMAND_PORT_TOC BIT(30) +#define COMMAND_PORT_READ_TRANSFER BIT(28) +#define COMMAND_PORT_SDAP BIT(27) +#define COMMAND_PORT_ROC BIT(26) +#define COMMAND_PORT_SPEED(x) (((x) << 21) & GENMASK(23, 21)) +#define COMMAND_PORT_DEV_INDEX(x) (((x) << 16) & GENMASK(20, 16)) +#define COMMAND_PORT_CPBIT(15) +#define COMMAND_PORT_CMD(x)(((x) << 7) & GENMASK(14, 7)) +#define COMMAND_PORT_TID(x)(((x) << 3) & GENMASK(6, 3)) + +#define COMMAND_PORT_ARG_DATA_LEN(x) (((x) << 16) & GENMASK(31, 16)) +#define COMMAND_PORT_ARG_DATA_LEN_MAX 65536 +#define COMMAND_PORT_TRANSFER_ARG 0x01 + +#define COMMAND_PORT_SDA_DATA_BYTE_3(x)(((x) << 24) & GENMASK(31, 24)) +#define COMMAND_PORT_SDA_DATA_BYTE_2(x)(((x) << 16) & GENMASK(23, 16)) +#define COMMAND_PORT_SDA_DATA_BYTE_1(x)(((x) << 8) & GENMASK(15, 8)) +#define COMMAND_PORT_SDA_BYTE_STRB_3 BIT(5) +#define COMMAND_PORT_SDA_BYTE_STRB_2 BIT(4) +#define COMMAND_PORT_SDA_BYTE_STRB_1 BIT(3) +#define COMMAND_PORT_SHORT_DATA_ARG0x02 + +#define COMMAND_PORT_DEV_COUNT(x) (((x) << 21) & GENMASK(25, 21)) +#define COMMAND_PORT_ADDR_ASSGN_CMD0x03 + +#define RESPONSE_QUEUE_PORT0x10 +#define RESPONSE_PORT_ERR_STATUS(x)(((x) & GENMASK(31, 28)) >> 28) +#define RESPONSE_NO_ERROR 0 +#define RESPONSE_ERROR_CRC 1 +#define RESPONSE_ERROR_PARITY 2 +#define RESPONSE_ERROR_FRAME 3 +#define RESPONSE_ERROR_IBA_NACK4 +#define RESPONSE_ERROR_ADDRESS_NACK5 +#define RESPONSE_ERROR_OVER_UNDER_FLOW 6 +#define RESPONSE_ERROR_TRANSF_ABORT8 +#define RESPONSE_ERROR_I2C_W_NACK_ERR 9 +#define RESPONSE_PORT_TID(x) (((x) & GENMASK(27, 24)) >> 24) +#define RESPONSE_PORT_DATA_LEN(x) ((x) & GENMASK(15, 0)) + +#define RX_TX_DATA_PORT0x14 +#define IBI_QUEUE_STATUS 0x18 +#define QUEUE_THLD_CTRL0x1c +#define QUEUE_THLD_CTRL_RESP_BUF_MASK GENMASK(15, 8) +#define QUEUE_THLD_CTRL_RESP_BUF(x)(((x) - 1)
[PATCH 0/3] Add ST lsm6dso i3c suppport
Vitor Soares (3): remap: Add i3c bus support i3c: Add i3c_get_device_id helper iio: imu: st_lsm6dsx: Add i3c basic support drivers/base/regmap/Kconfig | 6 ++- drivers/base/regmap/Makefile| 1 + drivers/base/regmap/regmap-i3c.c| 62 ++ drivers/i3c/device.c| 8 drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 67 + include/linux/i3c/device.h | 1 + include/linux/regmap.h | 20 + 9 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 drivers/base/regmap/regmap-i3c.c create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c -- 2.7.4
[PATCH 1/3] remap: Add I3C bus support
Add basic support for I3C bus. This is a simple implementation that only give support for Read and Write commands. Signed-off-by: Vitor Soares --- drivers/base/regmap/Kconfig | 6 +++- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-i3c.c | 62 include/linux/regmap.h | 20 + 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-i3c.c diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 6ad5ef4..c8bbf53 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,7 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_I3C) select IRQ_DOMAIN if REGMAP_IRQ bool @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE config REGMAP_SCCB tristate depends on I2C + +config REGMAP_I3C + tristate + depends on I3C diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index f5b4e88..ff6c7d8 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_W1) += regmap-w1.o obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o diff --git a/drivers/base/regmap/regmap-i3c.c b/drivers/base/regmap/regmap-i3c.c new file mode 100644 index 000..565997b --- /dev/null +++ b/drivers/base/regmap/regmap-i3c.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include + +static int regmap_i3c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = count, + .data.out = data, + }, + }; + + return i3c_device_do_priv_xfers(i3c, xfers, 1); +} + +static int regmap_i3c_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[2]; + + xfers[0].rnw = false; + xfers[0].len = reg_size; + xfers[0].data.out = reg; + + xfers[1].rnw = true; + xfers[1].len = val_size; + xfers[1].data.in = val; + + return i3c_device_do_priv_xfers(i3c, xfers, 2); +} + +static struct regmap_bus regmap_i3c = { + .write = regmap_i3c_write, + .read = regmap_i3c_read, +}; + +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); + +MODULE_LICENSE("GPL"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index daeec7d..f65984d 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -25,6 +25,7 @@ struct module; struct clk; struct device; struct i2c_client; +struct i3c_device; struct irq_domain; struct slim_device; struct spi_device; @@ -624,6 +625,10 @@ struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, +const struct regmap_config *config, +struct lock_class_key *lock_key, +const char *lock_name); /* * Wrapper for regmap_init macros to include a unique lockdep key and name * for each call. No-op if CONFIG_LOCKDEP is not set. @@ -982,6 +987,21 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); #define devm_regmap_init_slimbus(slimbus, config) \ __regmap_lockdep_wrapper(__devm_regmap_init_slimbus, #config, \ slimbus, config) + +/** + * devm_regmap_init_i3c() - Initialise managed register map + * + * @i3c: Device that will be interacted with + * @c
[PATCH 2/3] i3c: Add i3c_get_device_id helper
This helper return the i3c_device_id structure in order the client have access to the driver data. Signed-off-by: Vitor Soares --- drivers/i3c/device.c | 8 include/linux/i3c/device.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 472be99..8ab8e4c 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -235,6 +235,14 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) } EXPORT_SYMBOL_GPL(dev_to_i3cdev); +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev) +{ + const struct i3c_driver *i3cdrv = drv_to_i3cdrv(i3cdev->dev.driver); + + return i3cdrv->id_table; +} +EXPORT_SYMBOL_GPL(i3c_get_device_id); + /** * i3c_driver_register_with_owner() - register an I3C device driver * diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index 7ee7e30..ee48886 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -211,6 +211,7 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv) struct device *i3cdev_to_dev(struct i3c_device *i3cdev); struct i3c_device *dev_to_i3cdev(struct device *dev); +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev); static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev, void *data) -- 2.7.4
[PATCH 3/3] iio: imu: st_lsm6dsx: Add i3c basic support
For today the st_lsm6dsx driver support lsm6dso sensor only in spi and i2c mode. The lsm6dso is also i3c capable so lets give i3c support to it. Signed-off-by: Vitor Soares --- drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 67 + 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 094fd00..1ab9bbf 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -1,11 +1,12 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index e5f733c..c676965 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000..2df5e70 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +#define NAME_SIZE 32 + +struct st_lsm6dsx_i3c_data { + char name[NAME_SIZE]; + enum st_lsm6dsx_hw_id id; +}; + +static const struct st_lsm6dsx_i3c_data hw_data[] = { + { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, +}; + +static const struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + const struct i3c_device_id *id = i3c_get_device_id(i3cdev); + const struct st_lsm6dsx_i3c_data *hw_data = id->data; + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, hw_data->id, + hw_data->name, regmap); +} + + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, &hw_data[0]), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static struct i3c_driver st_lsm6dsx_driver = { + .driver.name = "st_lsm6dsx_i3c", + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); + -- 2.7.4
RE: [PATCH 1/3] i3c: fix i2c and i3c scl rate by bus mode
Hi Boris, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 06:50:41 > On Mon, 15 Apr 2019 20:46:41 +0200 > Vitor Soares wrote: > > > Currently in case of mixed slow bus topologie and all i2c devices > > support FM+ speed, the i3c subsystem limite the SCL to FM speed. > I will it replace with your message below. > " > Currently the I3C framework limits SCL frequency to FM speed when > dealing with a mixed slow bus, even if all I2C devices are FM+ capable. > " > > > Also in case on mixed slow bus mode the max speed for both > > i2c or i3c transfers is FM or FM+. > > Looks like you're basically repeating what you said above. What I meant was that I3C framework isn't limiting the I3C speed in case of mixed slow bus. > > > > > This patch fix the definition of i2c and i3c scl rate based on bus > >^fixes on the bus > > > topologie and LVR[4] if no user input. > > ^topology ^if the rate is not already specified by the user. > > > In case of mixed slow mode the i3c scl rate is overridden. > > ^ with the max > I2C rate. > > > > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > Signed-off-by: Vitor Soares > > Cc: Boris Brezillon > > Cc: > > Cc: > > --- > > drivers/i3c/master.c | 39 +-- > > 1 file changed, 25 insertions(+), 14 deletions(-) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 909c2ad..1c4a86a 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -564,20 +564,30 @@ static const struct device_type i3c_masterdev_type = { > > .groups = i3c_masterdev_groups, > > }; > > > > -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) > > +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, > > +unsigned long i2c_scl_rate) > > > Can we rename the last arg into max_i2c_scl_rate? The i2c_scl_rate is base on LVR[4] bit and the user can set a higher scl rate, this is reason I didn't named it to max_i2c_scl_rate. But if you think that make more sense I'm ok with that. > > > { > > i3cbus->mode = mode; > > > > - if (!i3cbus->scl_rate.i3c) > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > - > > - if (!i3cbus->scl_rate.i2c) { > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > - else > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > + switch (i3cbus->mode) { > > + case I3C_BUS_MODE_PURE: > > + if (!i3cbus->scl_rate.i3c) > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + break; > > + case I3C_BUS_MODE_MIXED_FAST: > > + if (!i3cbus->scl_rate.i3c) > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + if (!i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i2c = i2c_scl_rate; > > + break; > > + case I3C_BUS_MODE_MIXED_SLOW: > > + if (!i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i2c = i2c_scl_rate; > > + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > Maybe we should do > > if (!i3cbus->scl_rate.i3c || > i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) > i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > Just in case the I3C rate forced by the user is lower than the max I2C > rate. That was something that I considered but TBH it isn't a real use case. > > The patch looks good otherwise. Thanks. > > > + break; > > + default: > > + return -EINVAL; > > } > > - > > /* > > * I3C/I2C frequency may have been overridden, check that user-provided > > * values are not exceeding max possible frequency. > > @@ -1980,9 +1990,6 @@ of_i3c_master_add_i2c_boardinfo(struct > > i3c_master_controller *master, > > /* LVR is encoded in reg[2]. */ > > boardinfo->lvr = reg[2]; > > > > - if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) > > - master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > - > > list_add_tail(&am
RE: [PATCH 2/3] i3c: add mixed limited bus mode
Hi Boris, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 07:00:49 > Hi Vitor, > > On Mon, 15 Apr 2019 20:46:42 +0200 > Vitor Soares wrote: > > > The i3c bus spec define a bus configuration where the i2c devices > > ^defines I2C devices... > > > doesn't have the 50ns filter yet they allow the SDR max speed. > > ^don't ^ a 50ns filter but support SCL running at SDR max > rate (12MHz). > > > > > This patch introduce the limited bus mode so the users can use > >^introduces^ so that users > > > a higher speed on presence of i2c devices index 1. > >^in > > > > > Signed-off-by: Vitor Soares > > Cc: Boris Brezillon > > Cc: > > --- > > drivers/i3c/master.c | 5 + > > include/linux/i3c/master.h | 5 + > > 2 files changed, 10 insertions(+) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 1c4a86a..46d3774 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -463,6 +463,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) > > static const char * const i3c_bus_mode_strings[] = { > > [I3C_BUS_MODE_PURE] = "pure", > > [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", > > + [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", > > [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", > > }; > > > > @@ -575,6 +576,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum > > i3c_bus_mode mode, > > i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > break; > > case I3C_BUS_MODE_MIXED_FAST: > > + case I3C_BUS_MODE_MIXED_LIMITED: > > if (!i3cbus->scl_rate.i3c) > > i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > if (!i3cbus->scl_rate.i2c) > > @@ -2481,6 +2483,9 @@ int i3c_master_register(struct i3c_master_controller > > *master, > > mode = I3C_BUS_MODE_MIXED_FAST; > > break; > > case I3C_LVR_I2C_INDEX(1): > > + if (mode < I3C_BUS_MODE_MIXED_LIMITED) > > + mode = I3C_BUS_MODE_MIXED_LIMITED; > > + break; > > case I3C_LVR_I2C_INDEX(2): > > if (mode < I3C_BUS_MODE_MIXED_SLOW) > > mode = I3C_BUS_MODE_MIXED_SLOW; > > diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h > > index 44fb3cf..740235e 100644 > > --- a/include/linux/i3c/master.h > > +++ b/include/linux/i3c/master.h > > @@ -250,12 +250,17 @@ struct i3c_device { > > * the bus. The only impact in this mode is that the > > * high SCL pulse has to stay below 50ns to trick I2C > > * devices when transmitting I3C frames > > + * @I3C_BUS_MODE_MIXED_LIMITED: I2C devices without 50ns spike filter are > > + * present on the bus. However they allows > > + * compliance up to the maximum SDR SCL clock > > + * frequency. > > However they support > SCL clock running at maximum SDR rate > (12.5MHz). > > > * @I3C_BUS_MODE_MIXED_SLOW: I2C devices without 50ns spike filter are > > present > > * on the bus > > */ > > enum i3c_bus_mode { > > I3C_BUS_MODE_PURE, > > I3C_BUS_MODE_MIXED_FAST, > > + I3C_BUS_MODE_MIXED_LIMITED, > > I3C_BUS_MODE_MIXED_SLOW, > > }; > > > > The code itself looks good. > > Thanks, > > Boris Thanks for your feedback I will address the fixes next version. Best regards, Vitor Soares
RE: [PATCH 1/3] remap: Add I3C bus support
Hi Boris, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 07:15:51 > Typo in the subject: s/remap/regmap/ > > On Mon, 15 Apr 2019 21:19:39 +0200 > Vitor Soares wrote: > > > Add basic support for I3C bus. > > This is a simple implementation that only give support > > for Read and Write commands. > > > > Signed-off-by: Vitor Soares > > --- > > drivers/base/regmap/Kconfig | 6 +++- > > drivers/base/regmap/Makefile | 1 + > > drivers/base/regmap/regmap-i3c.c | 62 > > > > include/linux/regmap.h | 20 + > > 4 files changed, 88 insertions(+), 1 deletion(-) > > create mode 100644 drivers/base/regmap/regmap-i3c.c > > > > diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig > > index 6ad5ef4..c8bbf53 100644 > > --- a/drivers/base/regmap/Kconfig > > +++ b/drivers/base/regmap/Kconfig > > @@ -4,7 +4,7 @@ > > # subsystems should select the appropriate symbols. > > > > config REGMAP > > - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || > > REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) > > + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || > > REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_I3C) > > select IRQ_DOMAIN if REGMAP_IRQ > > bool > > > > @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE > > config REGMAP_SCCB > > tristate > > depends on I2C > > + > > +config REGMAP_I3C > > + tristate > > + depends on I3C > > diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile > > index f5b4e88..ff6c7d8 100644 > > --- a/drivers/base/regmap/Makefile > > +++ b/drivers/base/regmap/Makefile > > @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o > > obj-$(CONFIG_REGMAP_W1) += regmap-w1.o > > obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o > > obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o > > +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o > > diff --git a/drivers/base/regmap/regmap-i3c.c > > b/drivers/base/regmap/regmap-i3c.c > > new file mode 100644 > > index 000..565997b > > --- /dev/null > > +++ b/drivers/base/regmap/regmap-i3c.c > > @@ -0,0 +1,62 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > + * > > + * Author: Vitor Soares > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > + > > +static int regmap_i3c_write(void *context, const void *data, size_t count) > > +{ > > + struct device *dev = context; > > + struct i3c_device *i3c = dev_to_i3cdev(dev); > > + struct i3c_priv_xfer xfers[] = { > > + { > > + .rnw = false, > > + .len = count, > > + .data.out = data, > > + }, > > + }; > > + > > + return i3c_device_do_priv_xfers(i3c, xfers, 1); > > +} > > + > > +static int regmap_i3c_read(void *context, > > + const void *reg, size_t reg_size, > > + void *val, size_t val_size) > > +{ > > + struct device *dev = context; > > + struct i3c_device *i3c = dev_to_i3cdev(dev); > > + struct i3c_priv_xfer xfers[2]; > > + > > + xfers[0].rnw = false; > > + xfers[0].len = reg_size; > > + xfers[0].data.out = reg; > > + > > + xfers[1].rnw = true; > > + xfers[1].len = val_size; > > + xfers[1].data.in = val; > > + > > + return i3c_device_do_priv_xfers(i3c, xfers, 2); > > +} > > + > > +static struct regmap_bus regmap_i3c = { > > + .write = regmap_i3c_write, > > + .read = regmap_i3c_read, > > +}; > > + > > +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, > > + const struct regmap_config *config, > > + struct lock_class_key *lock_key, > > + const char *lock_name) > > +{ > > + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, > > + lock_key, lock_name); > > +} > > +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); > > + > > +MODULE_LICENSE("GPL"); > > diff --git a/include/linux/regmap.h b/include/linux/regmap.h > > index daeec7d..f65984d 100644 > > --- a/include/linux/regmap.h > > +++ b/include/linux/regmap.h > > @@ -25,6 +2
RE: [PATCH 2/3] i3c: Add i3c_get_device_id helper
Hi Boris, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 07:18:25 > On Mon, 15 Apr 2019 21:19:40 +0200 > Vitor Soares wrote: > > > This helper return the i3c_device_id structure in order the client > > have access to the driver data. > > > > Signed-off-by: Vitor Soares > > --- > > drivers/i3c/device.c | 8 > > include/linux/i3c/device.h | 1 + > > 2 files changed, 9 insertions(+) > > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c > > index 472be99..8ab8e4c 100644 > > --- a/drivers/i3c/device.c > > +++ b/drivers/i3c/device.c > > @@ -235,6 +235,14 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) > > } > > EXPORT_SYMBOL_GPL(dev_to_i3cdev); > > > > +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev) > > +{ > > + const struct i3c_driver *i3cdrv = drv_to_i3cdrv(i3cdev->dev.driver); > > + > > + return i3cdrv->id_table; > > +} > > +EXPORT_SYMBOL_GPL(i3c_get_device_id); > > I think what you want is i3c_device_match_id(). I want the i3c_device_id struct of an i3c_device. What is the name that you suggest? >Just move the function > to drivers/i3c/device.c, export it and define its prototype in > include/i3c/device.h. You are right, this should go for the device side. > > > + > > /** > > * i3c_driver_register_with_owner() - register an I3C device driver > > * > > diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h > > index 7ee7e30..ee48886 100644 > > --- a/include/linux/i3c/device.h > > +++ b/include/linux/i3c/device.h > > @@ -211,6 +211,7 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct > > device_driver *drv) > > > > struct device *i3cdev_to_dev(struct i3c_device *i3cdev); > > struct i3c_device *dev_to_i3cdev(struct device *dev); > > +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev); > > > > static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev, > > void *data) Best regards, Vitor Soares
RE: [PATCH 3/3] iio: imu: st_lsm6dsx: Add i3c basic support
Hi Boris and Lorenzo, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 09:05:40 > On Tue, 16 Apr 2019 09:58:33 +0200 > Lorenzo Bianconi wrote: > > > > > > > On Mon, 15 Apr 2019 21:19:41 +0200 > > > Vitor Soares wrote: > > > > > > > For today the st_lsm6dsx driver support lsm6dso sensor only in > > > > spi and i2c mode. > > > > > > > > The lsm6dso is also i3c capable so lets give i3c support to it. > > > > > > > > Signed-off-by: Vitor Soares > > > > --- > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 67 > > > > + > > > > 3 files changed, 75 insertions(+), 1 deletion(-) > > > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > b/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > index 094fd00..1ab9bbf 100644 > > > > --- a/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > @@ -1,11 +1,12 @@ > > > > > > > > config IIO_ST_LSM6DSX > > > > tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" > > > > - depends on (I2C || SPI) > > > > + depends on (I2C || SPI || I3C) > > > > select IIO_BUFFER > > > > select IIO_KFIFO_BUF > > > > select IIO_ST_LSM6DSX_I2C if (I2C) > > > > select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) > > > > + select IIO_ST_LSM6DSX_I3C if (I3C) > > > > help > > > > Say yes here to build support for STMicroelectronics LSM6DSx imu > > > > sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, > > > > @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI > > > > tristate > > > > depends on IIO_ST_LSM6DSX > > > > select REGMAP_SPI > > > > + > > > > +config IIO_ST_LSM6DSX_I3C > > > > + tristate > > > > + depends on IIO_ST_LSM6DSX > > > > + select REGMAP_I3C > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile > > > > b/drivers/iio/imu/st_lsm6dsx/Makefile > > > > index e5f733c..c676965 100644 > > > > --- a/drivers/iio/imu/st_lsm6dsx/Makefile > > > > +++ b/drivers/iio/imu/st_lsm6dsx/Makefile > > > > @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ > > > > obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o > > > > obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o > > > > obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o > > > > +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > new file mode 100644 > > > > index 000..2df5e70 > > > > --- /dev/null > > > > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > @@ -0,0 +1,67 @@ > > > > +// SPDX-License-Identifier: GPL-2.0 > > > > +/* > > > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > > > + * > > > > + * Author: Vitor Soares > > > > + */ > > > > + > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > + > > > > +#include "st_lsm6dsx.h" > > > > + > > > > +#define NAME_SIZE32 > > > > + > > > > +struct st_lsm6dsx_i3c_data { > > > > + char name[NAME_SIZE]; > > > > > > const char *name; I will fix this next patch. > > > > > > > + enum st_lsm6dsx_hw_id id; > > > > +}; > > > > + > > > > +static const struct st_lsm6dsx_i3c_data hw_data[] = { > > > > > > No need to make it an array, and it should probably be named > > > st_lsm6dso_data not hw_data. > > > > I guess it will be used even for future devices so I would prefer to > > make it an array with a 'general' name The idea is that one. Are you ok with hw_data name? Should I add the lsm6dsr support h
RE: [PATCH 3/3] iio: imu: st_lsm6dsx: Add i3c basic support
Hi Boris, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 07:25:39 > > +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); > > + > > +static struct i3c_driver st_lsm6dsx_driver = { > > + .driver.name = "st_lsm6dsx_i3c", > > + .probe = st_lsm6dsx_i3c_probe, > > + .id_table = st_lsm6dsx_i3c_ids, > > You should probably set the pm_ops here (st_lsm6dsx_pm_ops). Yes, I missed that. > > > +}; > > +module_i3c_driver(st_lsm6dsx_driver); > > + > > +MODULE_AUTHOR("Vitor Soares "); > > +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); > > +MODULE_LICENSE("GPL v2"); > > + > > You can remove this blank line. Thanks for your feedback. Best regards, Vitor Soares
[PATCH] reset: axs10x: Implement assert and deassert callbacks
Some custom IP-block connected to ARC AXS10x board need assert and deassert functions to control reset signal of selected peripherals. This patch improve AXS10x reset driver by adding assert and deassert callbacks. Signed-off-by: Vitor Soares Cc: Eugeniy Paltsev Cc: Alexey Brodkin Cc: Joao Pinto Cc: Jose Abreu Cc: Luis Oliveira Cc: Gustavo Pimentel Cc: Nelson Costa Cc: Pedro Sousa Cc: Philipp Zabel --- drivers/reset/reset-axs10x.c | 30 +- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-axs10x.c b/drivers/reset/reset-axs10x.c index a854ef41..12dac8b 100644 --- a/drivers/reset/reset-axs10x.c +++ b/drivers/reset/reset-axs10x.c @@ -37,8 +37,36 @@ static int axs10x_reset_reset(struct reset_controller_dev *rcdev, return 0; } +static int axs10x_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct axs10x_rst *rst = to_axs10x_rst(rcdev); + unsigned long flags; + + spin_lock_irqsave(&rst->lock, flags); + writel(readl(rst->regs_rst) & ~BIT(id), rst->regs_rst); + spin_unlock_irqrestore(&rst->lock, flags); + + return 0; +} + +static int axs10x_reset_deassert(struct reset_controller_dev *rcdev, +unsigned long id) +{ + struct axs10x_rst *rst = to_axs10x_rst(rcdev); + unsigned long flags; + + spin_lock_irqsave(&rst->lock, flags); + writel(readl(rst->regs_rst) | BIT(id), rst->regs_rst); + spin_unlock_irqrestore(&rst->lock, flags); + + return 0; +} + static const struct reset_control_ops axs10x_reset_ops = { - .reset = axs10x_reset_reset, + .reset = axs10x_reset_reset, + .assert = axs10x_reset_assert, + .deassert = axs10x_reset_deassert, }; static int axs10x_reset_probe(struct platform_device *pdev) -- 2.7.4
RE: [PATCH] reset: axs10x: Implement assert and deassert callbacks
Hi Eugeniy, From: Eugeniy Paltsev Date: Mon, Apr 08, 2019 at 12:40:00 > Hi Vitor, > > On Mon, 2019-04-08 at 12:31 +0200, Vitor Soares wrote: > > Some custom IP-block connected to ARC AXS10x board need assert and > > deassert functions to control reset signal of selected peripherals. > > > > This patch improve AXS10x reset driver by adding assert and deassert > > callbacks. > > > In the AXS10x reset driver only 'reset' callback is intentionally > > implemented. > AXS10x is FPGA based boards and with our default firmware AXS10x reset > > register is implemented as self-deasserted. > I have another reset block connect through AXI. > Do you have somehow modified AXS10x firmware where reset register is not > > self-deasserted? > In that case "simple-reset" driver will be suitable for you, I guess. I will try it. > Otherwise this implementation is incorrect - there should be no 'assert' for > > reset controller with self-deasserted logic. So the assert and reset callback are mutually exclusive? > > > > > > Signed-off-by: Vitor Soares > > > > Cc: Eugeniy Paltsev > > Cc: Alexey Brodkin > > Cc: Joao Pinto > > Cc: Jose Abreu > > Cc: Luis Oliveira > > Cc: Gustavo Pimentel > > Cc: Nelson Costa > > Cc: Pedro Sousa > > Cc: Philipp Zabel > > --- > > drivers/reset/reset-axs10x.c | 30 +- > > 1 file changed, 29 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/reset/reset-axs10x.c b/drivers/reset/reset-axs10x.c > > index a854ef41..12dac8b 100644 > > --- a/drivers/reset/reset-axs10x.c > > +++ b/drivers/reset/reset-axs10x.c > > @@ -37,8 +37,36 @@ static int axs10x_reset_reset(struct > > reset_controller_dev *rcdev, > > return 0; > > } > > > > +static int axs10x_reset_assert(struct reset_controller_dev *rcdev, > > + unsigned long id) > > +{ > > + struct axs10x_rst *rst = to_axs10x_rst(rcdev); > > + unsigned long flags; > > + > > + spin_lock_irqsave(&rst->lock, flags); > > + writel(readl(rst->regs_rst) & ~BIT(id), rst->regs_rst); > > + spin_unlock_irqrestore(&rst->lock, flags); > > + > > + return 0; > > +} > > + > > +static int axs10x_reset_deassert(struct reset_controller_dev *rcdev, > > +unsigned long id) > > +{ > > + struct axs10x_rst *rst = to_axs10x_rst(rcdev); > > + unsigned long flags; > > + > > + spin_lock_irqsave(&rst->lock, flags); > > + writel(readl(rst->regs_rst) | BIT(id), rst->regs_rst); > > + spin_unlock_irqrestore(&rst->lock, flags); > > + > > + return 0; > > +} > > + > > static const struct reset_control_ops axs10x_reset_ops = { > > - .reset = axs10x_reset_reset, > > + .reset = axs10x_reset_reset, > > + .assert = axs10x_reset_assert, > > + .deassert = axs10x_reset_deassert, > > }; > > > > static int axs10x_reset_probe(struct platform_device *pdev) > -- > Eugeniy Paltsev > Best regards, Vitor Soares
[PATCH 4/4] i3c: master: dw: reattach device on first available location of address table
For today the reattach function only update the device address on the controller. Update the location to the first available too, will optimize the enumeration process avoiding additional checks to keep the available positions on address table consecutive. Signed-off-by: Vitor Soares --- drivers/i3c/master/dw-i3c-master.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97..62261ac 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -898,6 +898,22 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); struct i3c_master_controller *m = i3c_dev_get_master(dev); struct dw_i3c_master *master = to_dw_i3c_master(m); + int pos; + + pos = dw_i3c_master_get_free_pos(master); + + if (data->index > pos && pos > 0) { + writel(0, + master->regs + + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); + + master->addrs[data->index] = 0; + master->free_pos |= BIT(data->index); + + data->index = pos; + master->addrs[pos] = dev->info.dyn_addr; + master->free_pos &= ~BIT(pos); + } writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), master->regs + -- 2.7.4
[PATCH 2/4] i3c: master: Check if devices have i3c_dev_boardinfo on i3c_master_add_i3c_dev_locked()
The I3C devices described in DT might not be attached to the master which doesn't allow to assign a specific dynamic address. This patch check if a device has i3c_dev_boardinfo and add it to i3c_dev_desc structure. In this conditions, the framework will try to assign the i3c_dev_boardinfo->init_dyn_addr even if stactic address = 0. Signed-off-by: Vitor Soares --- drivers/i3c/master.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 4d29e1f..85fbda6 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1795,6 +1795,23 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev) return NULL; } +static struct i3c_dev_boardinfo * +i3c_master_search_i3c_boardinfo(struct i3c_dev_desc *dev) +{ + struct i3c_master_controller *master = i3c_dev_get_master(dev); + struct i3c_dev_boardinfo *boardinfo; + + if (dev->boardinfo) + return NULL; + + list_for_each_entry(boardinfo, &master->boardinfo.i3c, node) { + if (dev->info.pid == boardinfo->pid) + return boardinfo; + } + + return NULL; +} + /** * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus * @master: master used to send frames on the bus @@ -1816,6 +1833,7 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, { struct i3c_device_info info = { .dyn_addr = addr }; struct i3c_dev_desc *newdev, *olddev; + struct i3c_dev_boardinfo *boardinfo; u8 old_dyn_addr = addr, expected_dyn_addr; struct i3c_ibi_setup ibireq = { }; bool enable_ibi = false; @@ -1875,6 +1893,10 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, if (ret) goto err_detach_dev; + boardinfo = i3c_master_search_i3c_boardinfo(newdev); + if (boardinfo) + newdev->boardinfo = boardinfo; + /* * Depending on our previous state, the expected dynamic address might * differ: -- 2.7.4
[PATCH 1/4] i3c: master: detach and free device if pre_assign_dyn_addr() fails
On pre_assing_dyn_addr() the devices that fail: i3c_master_setdasa_locked() i3c_master_reattach_i3c_dev() i3c_master_retrieve_dev_info() are kept in memory and master->bus.devs list. This makes the i3c devices without a dynamic address are sent on DEFSLVS CCC command. Fix this by detaching and freeing the devices that fail on pre_assign_dyn_addr(). Signed-off-by: Vitor Soares --- drivers/i3c/master.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..4d29e1f 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1438,7 +1438,7 @@ static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) ret = i3c_master_setdasa_locked(master, dev->info.static_addr, dev->boardinfo->init_dyn_addr); if (ret) - return; + goto err_detach_dev; dev->info.dyn_addr = dev->boardinfo->init_dyn_addr; ret = i3c_master_reattach_i3c_dev(dev, 0); @@ -1453,6 +1453,10 @@ static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) err_rstdaa: i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr); + +err_detach_dev: + i3c_master_detach_i3c_dev(dev); + i3c_master_free_i3c_dev(dev); } static void @@ -1647,7 +1651,7 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) enum i3c_addr_slot_status status; struct i2c_dev_boardinfo *i2cboardinfo; struct i3c_dev_boardinfo *i3cboardinfo; - struct i3c_dev_desc *i3cdev; + struct i3c_dev_desc *i3cdev, *i3ctmp; struct i2c_dev_desc *i2cdev; int ret; @@ -1746,7 +1750,8 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) * Pre-assign dynamic address and retrieve device information if * needed. */ - i3c_bus_for_each_i3cdev(&master->bus, i3cdev) + list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, +common.node) i3c_master_pre_assign_dyn_addr(i3cdev); ret = i3c_master_do_daa(master); -- 2.7.4
[PATCH 3/4] dt-bindings: i3c: Make 'assigned-address' valid if static address != 0
The I3C devices without a static address can require a specific dynamic address for priority reasons. Let's update the binding document to make the 'assigned-address' property valid if static address != 0 and add an example with this use case. Signed-off-by: Vitor Soares --- Documentation/devicetree/bindings/i3c/i3c.txt | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt b/Documentation/devicetree/bindings/i3c/i3c.txt index ab729a0..c851e75 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.txt +++ b/Documentation/devicetree/bindings/i3c/i3c.txt @@ -98,9 +98,7 @@ Required properties Optional properties --- -- assigned-address: dynamic address to be assigned to this device. This - property is only valid if the I3C device has a static - address (first cell of the reg property != 0). +- assigned-address: dynamic address to be assigned to this device. Example: @@ -129,6 +127,15 @@ Example: /* * I3C device without a static I2C address but requiring +* specific dynamic address. +*/ + sensor@0,39200154004 { + reg = <0x0 0x6072 0x303904d2>; + assigned-address = <0xb>; + }; + + /* +* I3C device without a static I2C address but requiring * resources described in the DT. */ sensor@0,39200154004 { -- 2.7.4
[PATCH 0/4] i3c: remove device if failed on pre_assign_dyn_addr()
This patch series remove the devices that fail during pre_assign_dyn_addr() and were being sent on DEFSVLS command. With the change above, during the i3c_master_add_i3c_dev_locked() is necessary to check if the device has i3c_boardinfo and try to assign the i3c_dev_boardinfo->init_dyn_addr if there no oldev. This change will allow to describe in DT device with preferable dynamic address but without static address. Vitor Soares (4): "i3c: detach and free device if pre_assign_dyn_addr fails " i3c: check i3c_boardinfo during i3c_master_add_i3c_dev_locked update i3c bingins i3c: master: dw: Reattach device on first empty location of DAT Documentation/devicetree/bindings/i3c/i3c.txt | 13 --- drivers/i3c/master.c | 33 --- drivers/i3c/master/dw-i3c-master.c| 16 + 3 files changed, 56 insertions(+), 6 deletions(-) -- 2.7.4
RE: [PATCH 1/4] i3c: master: detach and free device if pre_assign_dyn_addr() fails
Hi Boris, From: Boris Brezillon Date: Thu, Aug 29, 2019 at 11:41:15 > +Przemek > > Please try to Cc active I3C contributors so they get a chance to > comment on your patches. I can do that next time. > > On Thu, 29 Aug 2019 12:19:32 +0200 > Vitor Soares wrote: > > > On pre_assing_dyn_addr() the devices that fail: > > i3c_master_setdasa_locked() > > i3c_master_reattach_i3c_dev() > > i3c_master_retrieve_dev_info() > > > > are kept in memory and master->bus.devs list. This makes the i3c devices > > without a dynamic address are sent on DEFSLVS CCC command. Fix this by > > detaching and freeing the devices that fail on pre_assign_dyn_addr(). > > I don't think removing those entries is a good strategy, as one might > want to try to use a different dynamic address if the requested one > is not available. Do you mean same 'assigned-address' attribute in DT? If so, it is checked here: static int i3c_master_bus_init(struct i3c_master_controller *master) ... list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) { struct i3c_device_info info = { .static_addr = i3cboardinfo->static_addr, }; if (i3cboardinfo->init_dyn_addr) { status = i3c_bus_get_addr_slot_status(&master->bus, ^ i3cboardinfo->init_dyn_addr); if (status != I3C_ADDR_SLOT_FREE) { ret = -EBUSY; goto err_detach_devs; } } i3cdev = i3c_master_alloc_i3c_dev(master, &info); if (IS_ERR(i3cdev)) { ret = PTR_ERR(i3cdev); goto err_detach_devs; } i3cdev->boardinfo = i3cboardinfo; ret = i3c_master_attach_i3c_dev(master, i3cdev); if (ret) { i3c_master_free_i3c_dev(i3cdev); goto err_detach_devs; } } ... and later if it fails i3c_master_pre_assign_dyn_addr(), the device can participate in Enter Dynamic Address Assignment process. I may need to check the boardinfo->init_dyn_addr status on i3c_master_add_i3c_dev_locked before i3c_master_setnewda_locked(). > Why not simply skipping entries that have ->dyn_addr > set to 0 when preparing a DEFSLVS frame I considered that solution too but if the device isn't enumerated why should it be attached and kept in memory? Anyway we have i3c_boardinfo with DT information. > > > > > Signed-off-by: Vitor Soares > > --- > > drivers/i3c/master.c | 11 --- > > 1 file changed, 8 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 5f4bd52..4d29e1f 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -1438,7 +1438,7 @@ static void i3c_master_pre_assign_dyn_addr(struct > > i3c_dev_desc *dev) > > ret = i3c_master_setdasa_locked(master, dev->info.static_addr, > > dev->boardinfo->init_dyn_addr); > > if (ret) > > - return; > > + goto err_detach_dev; > > > > dev->info.dyn_addr = dev->boardinfo->init_dyn_addr; > > ret = i3c_master_reattach_i3c_dev(dev, 0); > > @@ -1453,6 +1453,10 @@ static void i3c_master_pre_assign_dyn_addr(struct > > i3c_dev_desc *dev) > > > > err_rstdaa: > > i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr); > > + > > +err_detach_dev: > > + i3c_master_detach_i3c_dev(dev); > > + i3c_master_free_i3c_dev(dev); > > We certainly shouldn't detach/free the i3c_dev_desc from here. If it > has to be done somewhere (which I'd like to avoid), it should be done > in i3c_master_bus_init() (i3c_master_pre_assign_dyn_addr() should be > converted to return an int in that case). I can change it to return an error. > > > } > > > > static void > > @@ -1647,7 +1651,7 @@ static int i3c_master_bus_init(struct > > i3c_master_controller *master) > > enum i3c_addr_slot_status status; > > struct i2c_dev_boardinfo *i2cboardinfo; > > struct i3c_dev_boardinfo *i3cboardinfo; > > - struct i3c_dev_desc *i3cdev; > > + struct i3c_dev_desc *i3cdev, *i3ctmp; > > struct i2c_dev_desc *i2cdev; > > int ret; > > > > @@ -1746,7 +1750,8 @@ static int i3c_master_bus_init(struct > > i3c_master_controller *master) > > * Pre-assign dynamic address and retrieve device information if > > * needed. > > */ > > - i3c_bus_for_each_i3cdev(&master->bus, i3cdev) > > + list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, > > +common.node) > > i3c_master_pre_assign_dyn_addr(i3cdev); > > > > ret = i3c_master_do_daa(master); Thank for your feedback. Best regards, Vitor Soares
RE: [PATCH 2/4] i3c: master: Check if devices have i3c_dev_boardinfo on i3c_master_add_i3c_dev_locked()
Hi Boris, From: Boris Brezillon Date: Thu, Aug 29, 2019 at 11:44:57 > On Thu, 29 Aug 2019 12:19:33 +0200 > Vitor Soares wrote: > > > The I3C devices described in DT might not be attached to the master which > > doesn't allow to assign a specific dynamic address. > > I remember testing this when developing the framework, so, unless > another patch regressed it, it should already work. I suspect patch 1 > is actually the regressing this use case. For today it doesn't address the case where the device is described with static address = 0, which isn't attached to the controller. With this change both cases are covered. > > > > > This patch check if a device has i3c_dev_boardinfo and add it to > > i3c_dev_desc structure. In this conditions, the framework will try to > > assign the i3c_dev_boardinfo->init_dyn_addr even if stactic address = 0. > > > > Signed-off-by: Vitor Soares > > --- > > drivers/i3c/master.c | 22 ++ > > 1 file changed, 22 insertions(+) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 4d29e1f..85fbda6 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -1795,6 +1795,23 @@ i3c_master_search_i3c_dev_duplicate(struct > > i3c_dev_desc *refdev) > > return NULL; > > } > > > > +static struct i3c_dev_boardinfo * > > +i3c_master_search_i3c_boardinfo(struct i3c_dev_desc *dev) > > +{ > > + struct i3c_master_controller *master = i3c_dev_get_master(dev); > > + struct i3c_dev_boardinfo *boardinfo; > > + > > + if (dev->boardinfo) > > + return NULL; > > + > > + list_for_each_entry(boardinfo, &master->boardinfo.i3c, node) { > > + if (dev->info.pid == boardinfo->pid) > > + return boardinfo; > > + } > > + > > + return NULL; > > +} > > + > > /** > > * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus > > * @master: master used to send frames on the bus > > @@ -1816,6 +1833,7 @@ int i3c_master_add_i3c_dev_locked(struct > > i3c_master_controller *master, > > { > > struct i3c_device_info info = { .dyn_addr = addr }; > > struct i3c_dev_desc *newdev, *olddev; > > + struct i3c_dev_boardinfo *boardinfo; > > u8 old_dyn_addr = addr, expected_dyn_addr; > > struct i3c_ibi_setup ibireq = { }; > > bool enable_ibi = false; > > @@ -1875,6 +1893,10 @@ int i3c_master_add_i3c_dev_locked(struct > > i3c_master_controller *master, > > if (ret) > > goto err_detach_dev; > > > > + boardinfo = i3c_master_search_i3c_boardinfo(newdev); > > + if (boardinfo) > > + newdev->boardinfo = boardinfo; > > + > > /* > > * Depending on our previous state, the expected dynamic address might > > * differ: Best regards, Vitor Soares
RE: [PATCH 3/4] dt-bindings: i3c: Make 'assigned-address' valid if static address != 0
Hi Boris, From: Boris Brezillon Date: Thu, Aug 29, 2019 at 11:51:38 > On Thu, 29 Aug 2019 12:19:34 +0200 > Vitor Soares wrote: > > > The I3C devices without a static address can require a specific dynamic > > address for priority reasons. > > > > Let's update the binding document to make the 'assigned-address' property > > valid if static address != 0 and add an example with this use case. > >^ you mean static address == 0, right? Indeed. > > Yes, it makes sense to support that case and do our best to assign the > requested address after DAA has taken place by explicitly executing > SETDA. > > > > > Signed-off-by: Vitor Soares > > --- > > Documentation/devicetree/bindings/i3c/i3c.txt | 13 ++--- > > 1 file changed, 10 insertions(+), 3 deletions(-) > > > > diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt > > b/Documentation/devicetree/bindings/i3c/i3c.txt > > index ab729a0..c851e75 100644 > > --- a/Documentation/devicetree/bindings/i3c/i3c.txt > > +++ b/Documentation/devicetree/bindings/i3c/i3c.txt > > @@ -98,9 +98,7 @@ Required properties > > > > Optional properties > > --- > > -- assigned-address: dynamic address to be assigned to this device. This > > - property is only valid if the I3C device has a static > > - address (first cell of the reg property != 0). > > +- assigned-address: dynamic address to be assigned to this device. > > We should probably mention that we don't provide strong guarantees > here. We will try to assign this dynamic address to the device, but if > something fails (like another device owning the address and refusing to > give it up), the actual dynamic address will be different. > This clarification can be done in a separate patch. So, another patch on top of this one explaining that, right? I would suggest to use a dynamic address, like 0x40 (mid priority), on ENTDAA so lowers addresses (High Priority) can be used in DT or another method. What do you think about this? > > > > > > > Example: > > @@ -129,6 +127,15 @@ Example: > > > > /* > > * I3C device without a static I2C address but requiring > > +* specific dynamic address. > > +*/ > > + sensor@0,39200154004 { > > + reg = <0x0 0x6072 0x303904d2>; > > + assigned-address = <0xb>; > > + }; > > + > > + /* > > +* I3C device without a static I2C address but requiring > > * resources described in the DT. > > */ > > sensor@0,39200154004 { Best regards, Vitor Soares
RE: [PATCH 4/4] i3c: master: dw: reattach device on first available location of address table
Hi Boris, From: Boris Brezillon Date: Thu, Aug 29, 2019 at 12:15:19 > On Thu, 29 Aug 2019 12:19:35 +0200 > Vitor Soares wrote: > > > For today the reattach function only update the device address on the > > controller. > > > > Update the location to the first available too, will optimize the > > enumeration process avoiding additional checks to keep the available > > positions on address table consecutive. > > Given the number of available slots I honestly don't think it makes a > difference, but I also don't mind this change, so The slots are HW dependent. The point is, I need to guarantee the available slot are consecutives. If you have any suggestion I appreciate. > > Reviewed-by: Boris Brezillon > > > > > Signed-off-by: Vitor Soares > > --- > > drivers/i3c/master/dw-i3c-master.c | 16 > > 1 file changed, 16 insertions(+) > > > > diff --git a/drivers/i3c/master/dw-i3c-master.c > > b/drivers/i3c/master/dw-i3c-master.c > > index 1d83c97..62261ac 100644 > > --- a/drivers/i3c/master/dw-i3c-master.c > > +++ b/drivers/i3c/master/dw-i3c-master.c > > @@ -898,6 +898,22 @@ static int dw_i3c_master_reattach_i3c_dev(struct > > i3c_dev_desc *dev, > > struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); > > struct i3c_master_controller *m = i3c_dev_get_master(dev); > > struct dw_i3c_master *master = to_dw_i3c_master(m); > > + int pos; > > + > > + pos = dw_i3c_master_get_free_pos(master); > > + > > + if (data->index > pos && pos > 0) { > > + writel(0, > > + master->regs + > > + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); > > + > > + master->addrs[data->index] = 0; > > + master->free_pos |= BIT(data->index); > > + > > + data->index = pos; > > + master->addrs[pos] = dev->info.dyn_addr; > > + master->free_pos &= ~BIT(pos); > > + } > > > > writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), > >master->regs + Best regards, Vitor Soares
RE: [PATCH 2/4] i3c: master: Check if devices have i3c_dev_boardinfo on i3c_master_add_i3c_dev_locked()
From: Boris Brezillon Date: Thu, Aug 29, 2019 at 15:39:41 > On Thu, 29 Aug 2019 16:39:18 +0200 > Boris Brezillon wrote: > > > On Thu, 29 Aug 2019 14:00:44 + > > Vitor Soares wrote: > > > > > Hi Boris, > > > > > > From: Boris Brezillon > > > Date: Thu, Aug 29, 2019 at 11:44:57 > > > > > > > On Thu, 29 Aug 2019 12:19:33 +0200 > > > > Vitor Soares wrote: > > > > > > > > > The I3C devices described in DT might not be attached to the master > > > > > which > > > > > doesn't allow to assign a specific dynamic address. > > > > > > > > I remember testing this when developing the framework, so, unless > > > > another patch regressed it, it should already work. I suspect patch 1 > > > > is actually the regressing this use case. > > > > > > For today it doesn't address the case where the device is described with > > > static address = 0, which isn't attached to the controller. > > > > Hm, I'm pretty sure I had designed the code to support that case (see > > [1]). It might be buggy, but nothing we can't fix I guess. > > > > [1]https://urldefense.proofpoint.com/v2/url?u=https-3A__elixir.bootlin.com_linux_v5.3-2Drc6_source_drivers_i3c_master.c-23L1898&d=DwICAg&c=DPL6_X_6JkXFx7AXWqB0tg&r=qVuU64u9x77Y0Kd0PhDK_lpxFgg6PK9PateHwjb_DY0&m=IXS1ygIgEo5vwajk0iwd5aBDVBzRnVTjO3cg4iBmGNc&s=HC-AcYm-AZPrUBoALioej_BDnqOtJHltr39Z2yPkuU4&e= > That is only valid if you have olddev which will only exist if static address != 0.
RE: [PATCH 1/4] i3c: master: detach and free device if pre_assign_dyn_addr() fails
From: Boris Brezillon Date: Thu, Aug 29, 2019 at 15:35:20 > On Thu, 29 Aug 2019 13:53:24 + > Vitor Soares wrote: > > > Hi Boris, > > > > From: Boris Brezillon > > Date: Thu, Aug 29, 2019 at 11:41:15 > > > > > +Przemek > > > > > > Please try to Cc active I3C contributors so they get a chance to > > > comment on your patches. > > > > I can do that next time. > > > > > > > > On Thu, 29 Aug 2019 12:19:32 +0200 > > > Vitor Soares wrote: > > > > > > > On pre_assing_dyn_addr() the devices that fail: > > > > i3c_master_setdasa_locked() > > > > i3c_master_reattach_i3c_dev() > > > > i3c_master_retrieve_dev_info() > > > > > > > > are kept in memory and master->bus.devs list. This makes the i3c devices > > > > without a dynamic address are sent on DEFSLVS CCC command. Fix this by > > > > detaching and freeing the devices that fail on pre_assign_dyn_addr(). > > > > > > I don't think removing those entries is a good strategy, as one might > > > want to try to use a different dynamic address if the requested one > > > is not available. > > > > Do you mean same 'assigned-address' attribute in DT? > > Yes, or say it's another device that got the address we want and this > device doesn't want to release the address (I'm assuming the !SA case). > > > > > If so, it is checked here: > > > > static int i3c_master_bus_init(struct i3c_master_controller *master) > > ... > > list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) { > > struct i3c_device_info info = { > > .static_addr = i3cboardinfo->static_addr, > > }; > > > > if (i3cboardinfo->init_dyn_addr) { > > status = i3c_bus_get_addr_slot_status(&master->bus, > > ^ > > i3cboardinfo->init_dyn_addr); > > if (status != I3C_ADDR_SLOT_FREE) { > > ret = -EBUSY; > > goto err_detach_devs; > > } > > } > > > > i3cdev = i3c_master_alloc_i3c_dev(master, &info); > > if (IS_ERR(i3cdev)) { > > ret = PTR_ERR(i3cdev); > > goto err_detach_devs; > > } > > > > i3cdev->boardinfo = i3cboardinfo; > > > > ret = i3c_master_attach_i3c_dev(master, i3cdev); > > if (ret) { > > i3c_master_free_i3c_dev(i3cdev); > > goto err_detach_devs; > > } > > } > > ... > > > > and later if it fails i3c_master_pre_assign_dyn_addr(), the device can > > participate in Enter Dynamic Address Assignment process. > > I may need to check the boardinfo->init_dyn_addr status on > > i3c_master_add_i3c_dev_locked before i3c_master_setnewda_locked(). > > I need to double check but I thought we were already handling that case > properly. Yes, it is handled in the code above. > > > > > > Why not simply skipping entries that have ->dyn_addr > > > set to 0 when preparing a DEFSLVS frame > > > > I considered that solution too but if the device isn't enumerated why > > should it be attached and kept in memory? > > Might be a device that supports HJ, and in that case we might want the > controller to reserve a slot in its device table for that device. > Anyway, it doesn't hurt to have it around as long as we don't pass the > device through DEFSLVS if it doesn't have a dynamic address. I really > prefer to keep the logic unchanged and fix it if it needs to be fixed. Well, we aren't reserving a slot because we need another one to attach the device when it is enumerated and hence a device may be using 2 slots in the controller. It may cause problems in HC with reduced slots and it is another reason why I think we should detach device without dynamic address after the enumeration phase. > > > Anyway we have i3c_boardinfo > > with DT information. > > > > > > > > > > > > > Signed-off-by: Vitor Soares > > > > --- > > > > drivers/i3c/master.c | 11 --- > > > > 1 file changed, 8 insertions(+), 3 deletions(-) > > > > > > > > diff
RE: [PATCH 2/4] i3c: master: Check if devices have i3c_dev_boardinfo on i3c_master_add_i3c_dev_locked()
-Original Message- From: Boris Brezillon Sent: Thursday, August 29, 2019 4:25 PM To: Vitor Soares Cc: linux-kernel@vger.kernel.org; devicet...@vger.kernel.org; linux-...@lists.infradead.org; bbrezil...@kernel.org; robh...@kernel.org; mark.rutl...@arm.com; joao.pi...@synopsys.com Subject: Re: [PATCH 2/4] i3c: master: Check if devices have i3c_dev_boardinfo on i3c_master_add_i3c_dev_locked() On Thu, 29 Aug 2019 15:07:08 + Vitor Soares wrote: > From: Boris Brezillon > Date: Thu, Aug 29, 2019 at 15:39:41 > > > On Thu, 29 Aug 2019 16:39:18 +0200 > > Boris Brezillon wrote: > > > > > On Thu, 29 Aug 2019 14:00:44 + > > > Vitor Soares wrote: > > > > > > > Hi Boris, > > > > > > > > From: Boris Brezillon > > > > Date: Thu, Aug 29, 2019 at 11:44:57 > > > > > > > > > On Thu, 29 Aug 2019 12:19:33 +0200 > > > > > Vitor Soares wrote: > > > > > > > > > > > The I3C devices described in DT might not be attached to the master > > > > > > which > > > > > > doesn't allow to assign a specific dynamic address. > > > > > > > > > > I remember testing this when developing the framework, so, unless > > > > > another patch regressed it, it should already work. I suspect patch 1 > > > > > is actually the regressing this use case. > > > > > > > > For today it doesn't address the case where the device is described > > > > with > > > > static address = 0, which isn't attached to the controller. > > > > > > Hm, I'm pretty sure I had designed the code to support that case (see > > > [1]). It might be buggy, but nothing we can't fix I guess. > > > > > > > [1]https://urldefense.proofpoint.com/v2/url?u=https-3A__elixir.bootlin.com_linux_v5.3-2Drc6_source_drivers_i3c_master.c-23L1898&d=DwICAg&c=DPL6_X_6JkXFx7AXWqB0tg&r=qVuU64u9x77Y0Kd0PhDK_lpxFgg6PK9PateHwjb_DY0&m=IXS1ygIgEo5vwajk0iwd5aBDVBzRnVTjO3cg4iBmGNc&s=HC-AcYm-AZPrUBoALioej_BDnqOtJHltr39Z2yPkuU4&e= > > > > That is only valid if you have olddev which will only exist if static > address != 0. Hm, if you revert patch 1 (and assuming the device is properly defined in the DT), you should have olddev != NULL when reaching that point. If that's not the case there's a bug somewhere that should be fixed. No, because the device is not attached.
RE: [PATCH 1/4] i3c: master: detach and free device if pre_assign_dyn_addr() fails
From: Boris Brezillon Date: Thu, Aug 29, 2019 at 16:37:09 > On Thu, 29 Aug 2019 15:23:30 + > Vitor Soares wrote: > > > From: Boris Brezillon > > Date: Thu, Aug 29, 2019 at 15:35:20 > > > > > On Thu, 29 Aug 2019 13:53:24 + > > > Vitor Soares wrote: > > > > > > > Hi Boris, > > > > > > > > From: Boris Brezillon > > > > Date: Thu, Aug 29, 2019 at 11:41:15 > > > > > > > > > +Przemek > > > > > > > > > > Please try to Cc active I3C contributors so they get a chance to > > > > > comment on your patches. > > > > > > > > I can do that next time. > > > > > > > > > > > > > > On Thu, 29 Aug 2019 12:19:32 +0200 > > > > > Vitor Soares wrote: > > > > > > > > > > > On pre_assing_dyn_addr() the devices that fail: > > > > > > i3c_master_setdasa_locked() > > > > > > i3c_master_reattach_i3c_dev() > > > > > > i3c_master_retrieve_dev_info() > > > > > > > > > > > > are kept in memory and master->bus.devs list. This makes the i3c > > > > > > devices > > > > > > without a dynamic address are sent on DEFSLVS CCC command. Fix this > > > > > > by > > > > > > detaching and freeing the devices that fail on > > > > > > pre_assign_dyn_addr(). > > > > > > > > > > I don't think removing those entries is a good strategy, as one might > > > > > want to try to use a different dynamic address if the requested one > > > > > is not available. > > > > > > > > Do you mean same 'assigned-address' attribute in DT? > > > > > > Yes, or say it's another device that got the address we want and this > > > device doesn't want to release the address (I'm assuming the !SA case). > > > > > > > > > > > If so, it is checked here: > > > > > > > > static int i3c_master_bus_init(struct i3c_master_controller *master) > > > > ... > > > > list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) > > > > { > > > > struct i3c_device_info info = { > > > > .static_addr = i3cboardinfo->static_addr, > > > > }; > > > > > > > > if (i3cboardinfo->init_dyn_addr) { > > > > status = > > > > i3c_bus_get_addr_slot_status(&master->bus, > > > > ^ > > > > > > > > i3cboardinfo->init_dyn_addr); > > > > if (status != I3C_ADDR_SLOT_FREE) { > > > > ret = -EBUSY; > > > > goto err_detach_devs; > > > > } > > > > } > > > > > > > > i3cdev = i3c_master_alloc_i3c_dev(master, &info); > > > > if (IS_ERR(i3cdev)) { > > > > ret = PTR_ERR(i3cdev); > > > > goto err_detach_devs; > > > > } > > > > > > > > i3cdev->boardinfo = i3cboardinfo; > > > > > > > > ret = i3c_master_attach_i3c_dev(master, i3cdev); > > > > if (ret) { > > > > i3c_master_free_i3c_dev(i3cdev); > > > > goto err_detach_devs; > > > > } > > > > } > > > > ... > > > > > > > > and later if it fails i3c_master_pre_assign_dyn_addr(), the device can > > > > participate in Enter Dynamic Address Assignment process. > > > > I may need to check the boardinfo->init_dyn_addr status on > > > > i3c_master_add_i3c_dev_locked before i3c_master_setnewda_locked(). > > > > > > I need to double check but I thought we were already handling that case > > > properly. > > > > Yes, it is handled in the code above. > > No, I meant the 'assign init_dyn_addr even if !SA', and the code I > pointed in my other reply tends to confirm that this is something we
RE: [PATCH 2/4] i3c: master: Check if devices have i3c_dev_boardinfo on i3c_master_add_i3c_dev_locked()
From: Boris Brezillon Date: Thu, Aug 29, 2019 at 17:15:20 > On Thu, 29 Aug 2019 15:57:32 + > Vitor Soares wrote: > > > -Original Message- > > From: Boris Brezillon > > > > Sent: Thursday, August 29, 2019 4:25 > > PM > > To: Vitor Soares > > Cc: > > linux-kernel@vger.kernel.org; devicet...@vger.kernel.org; > > linux-...@lists.infradead.org; bbrezil...@kernel.org; robh...@kernel.org; > > mark.rutl...@arm.com; joao.pi...@synopsys.com > > Subject: Re: [PATCH 2/4] > > i3c: master: Check if devices have i3c_dev_boardinfo on > > i3c_master_add_i3c_dev_locked() > > > > On Thu, 29 Aug 2019 15:07:08 + > > Vitor Soares wrote: > > > > > From: Boris Brezillon > > > > > Date: Thu, Aug 29, 2019 at 15:39:41 > > > > > > > > > On Thu, 29 Aug 2019 16:39:18 +0200 > > > > Boris Brezillon wrote: > > > > > > > > > On Thu, 29 Aug 2019 14:00:44 + > > > > > Vitor Soares wrote: > > > > > > > > > > > Hi Boris, > > > > > > > > > > > > From: Boris Brezillon > > > > > > Date: Thu, Aug 29, 2019 at 11:44:57 > > > > > > > > > > > > > On Thu, 29 Aug 2019 12:19:33 +0200 > > > > > > > Vitor Soares wrote: > > > > > > > > > > > > > > > The I3C devices described in DT might not be attached to the > > > > > > > > master which > > > > > > > > doesn't allow to assign a specific dynamic address. > > > > > > > > > > > > > > I remember testing this when developing the framework, so, unless > > > > > > > another patch regressed it, it should already work. I suspect > > > > > > > patch 1 > > > > > > > is actually the regressing this use case. > > > > > > > > > > > > For today it doesn't address the case where the device is described > > > > > > with > > > > > > static address = 0, which isn't attached to the controller. > > > > > > > > > > Hm, I'm pretty sure I had designed the code to support that case (see > > > > > [1]). It might be buggy, but nothing we can't fix I guess. > > > > > > > > > > > > > [1]https://urldefense.proofpoint.com/v2/url?u=https-3A__elixir.bootlin.com_linux_v5.3-2Drc6_source_drivers_i3c_master.c-23L1898&d=DwICAg&c=DPL6_X_6JkXFx7AXWqB0tg&r=qVuU64u9x77Y0Kd0PhDK_lpxFgg6PK9PateHwjb_DY0&m=IXS1ygIgEo5vwajk0iwd5aBDVBzRnVTjO3cg4iBmGNc&s=HC-AcYm-AZPrUBoALioej_BDnqOtJHltr39Z2yPkuU4&e= > > > > > > > > > > That is only valid if you have olddev which will only exist if static > > > address != 0. > > > > Hm, if you revert patch 1 (and assuming the device is properly defined > > in the DT), you should have olddev != NULL when reaching that point. If > > that's not the case there's a bug somewhere that should be fixed. > > > > No, because the device is not attached. > > Oh, my bad, I see what you mean now. This is definitely a bug and should > have the Fixes tags. I mean, even if we don't care about dynamic > address assignment, I3C drivers might care about the ->of_node that's > attached to the device. I didn't consider a bug because in dt-bindings says to not use 'assigned address' if SA = 0. Do you think there is a better way to solve it? Best regards, Vitor Soares
[PATCH v2 4/5] dt-bindings: i3c: add a note for no guarantee of 'assigned-address' use
By default, the framework will try to assign the 'assigned-address' to the device but if the address is already in use the device dynamic address will be different. Signed-off-by: Vitor Soares --- Documentation/devicetree/bindings/i3c/i3c.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt b/Documentation/devicetree/bindings/i3c/i3c.txt index c851e75..e777f09 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.txt +++ b/Documentation/devicetree/bindings/i3c/i3c.txt @@ -98,7 +98,9 @@ Required properties Optional properties --- -- assigned-address: dynamic address to be assigned to this device. +- assigned-address: dynamic address to be assigned to this device. The framework + will try to assign this dynamic address but if something + fails the device dynamic address will be different. Example: -- 2.7.4
[PATCH v2 5/5] i3c: master: dw: reattach device on first available location of address table
For today the reattach function only update the device address on the controller. Update the location to the first available too, will optimize the enumeration process avoiding additional checks to keep the available positions on address table consecutive. Signed-off-by: Vitor Soares Reviewed-by: Boris Brezillon --- Change in v2: - Add Boris rb-tag drivers/i3c/master/dw-i3c-master.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97..62261ac 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -898,6 +898,22 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); struct i3c_master_controller *m = i3c_dev_get_master(dev); struct dw_i3c_master *master = to_dw_i3c_master(m); + int pos; + + pos = dw_i3c_master_get_free_pos(master); + + if (data->index > pos && pos > 0) { + writel(0, + master->regs + + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); + + master->addrs[data->index] = 0; + master->free_pos |= BIT(data->index); + + data->index = pos; + master->addrs[pos] = dev->info.dyn_addr; + master->free_pos &= ~BIT(pos); + } writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), master->regs + -- 2.7.4
[PATCH v2 0/5] i3c: remove device if failed on pre_assign_dyn_addr()
This patch series remove the devices that fail during pre_assign_dyn_addr() and were being sent on DEFSVLS command. With the change above, during the i3c_master_add_i3c_dev_locked() is necessary to check if the device has i3c_boardinfo and try to assign the i3c_dev_boardinfo->init_dyn_addr if there no oldev. This change will allow to describe in DT device with preferable dynamic address but without static address. Change in v2: - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() - Change i3c_master_search_i3c_boardinfo(newdev) to i3c_master_init_i3c_dev_boardinfo(newdev) - Add fixes, stable tags on patch 2 - Add a note for no guarantee of 'assigned-address' use Vitor Soares (5): i3c: master: detach and free device if pre_assign_dyn_addr() fails i3c: master: make sure ->boardinfo is initialized in add_i3c_dev_locked() dt-bindings: i3c: make 'assigned-address' valid if static address == 0 dt-bindings: i3c: add a note for no guarantee of 'assigned-address' use i3c: master: dw: reattach device on first available location of address table Documentation/devicetree/bindings/i3c/i3c.txt | 15 ++-- drivers/i3c/master.c | 49 ++- drivers/i3c/master/dw-i3c-master.c| 16 + 3 files changed, 68 insertions(+), 12 deletions(-) -- 2.7.4
[PATCH v2 2/5] i3c: master: make sure ->boardinfo is initialized in add_i3c_dev_locked()
The newdev->boardinfo assignment was missing in i3c_master_add_i3c_dev_locked() and hence the ->of_node info isn't propagated to i3c_dev_desc. Fix this by trying to initialize device i3c_dev_boardinfo if available. Cc: Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Vitor Soares --- Changes in v2: - Change commit message - Change i3c_master_search_i3c_boardinfo(newdev) to i3c_master_init_i3c_dev_boardinfo(newdev) - Add fixes, stable tags drivers/i3c/master.c | 27 +-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 586e34f..9fb99bc 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1798,6 +1798,22 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev) return NULL; } +static void i3c_master_init_i3c_dev_boardinfo(struct i3c_dev_desc *dev) +{ + struct i3c_master_controller *master = i3c_dev_get_master(dev); + struct i3c_dev_boardinfo *boardinfo; + + if (dev->boardinfo) + return; + + list_for_each_entry(boardinfo, &master->boardinfo.i3c, node) { + if (dev->info.pid == boardinfo->pid) { + dev->boardinfo = boardinfo; + return; + } + } +} + /** * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus * @master: master used to send frames on the bus @@ -1818,8 +1834,9 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, u8 addr) { struct i3c_device_info info = { .dyn_addr = addr }; - struct i3c_dev_desc *newdev, *olddev; u8 old_dyn_addr = addr, expected_dyn_addr; + enum i3c_addr_slot_status addrstatus; + struct i3c_dev_desc *newdev, *olddev; struct i3c_ibi_setup ibireq = { }; bool enable_ibi = false; int ret; @@ -1878,6 +1895,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, if (ret) goto err_detach_dev; + i3c_master_init_i3c_dev_boardinfo(newdev); + /* * Depending on our previous state, the expected dynamic address might * differ: @@ -1895,7 +1914,11 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, else expected_dyn_addr = newdev->info.dyn_addr; - if (newdev->info.dyn_addr != expected_dyn_addr) { + addrstatus = i3c_bus_get_addr_slot_status(&master->bus, + expected_dyn_addr); + + if (newdev->info.dyn_addr != expected_dyn_addr && + addrstatus == I3C_ADDR_SLOT_FREE) { /* * Try to apply the expected dynamic address. If it fails, keep * the address assigned by the master. -- 2.7.4
[PATCH v2 3/5] dt-bindings: i3c: Make 'assigned-address' valid if static address == 0
The I3C devices without a static address can require a specific dynamic address for priority reasons. Let's update the binding document to make the 'assigned-address' property valid if static address == 0 and add an example with this use case. Signed-off-by: Vitor Soares --- Documentation/devicetree/bindings/i3c/i3c.txt | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt b/Documentation/devicetree/bindings/i3c/i3c.txt index ab729a0..c851e75 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.txt +++ b/Documentation/devicetree/bindings/i3c/i3c.txt @@ -98,9 +98,7 @@ Required properties Optional properties --- -- assigned-address: dynamic address to be assigned to this device. This - property is only valid if the I3C device has a static - address (first cell of the reg property != 0). +- assigned-address: dynamic address to be assigned to this device. Example: @@ -129,6 +127,15 @@ Example: /* * I3C device without a static I2C address but requiring +* specific dynamic address. +*/ + sensor@0,39200154004 { + reg = <0x0 0x6072 0x303904d2>; + assigned-address = <0xb>; + }; + + /* +* I3C device without a static I2C address but requiring * resources described in the DT. */ sensor@0,39200154004 { -- 2.7.4
[PATCH v2 1/5] i3c: master: detach and free device if pre_assign_dyn_addr() fails
On pre_assing_dyn_addr() the devices that fail: i3c_master_setdasa_locked() i3c_master_reattach_i3c_dev() i3c_master_retrieve_dev_info() are kept in memory and master->bus.devs list. This makes the i3c devices without a dynamic address are sent on DEFSLVS CCC command. Fix this by detaching and freeing the devices that fail on pre_assign_dyn_addr(). Signed-off-by: Vitor Soares --- Changes in v2: - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() - Convert i3c_master_pre_assign_dyn_addr() to return an int drivers/i3c/master.c | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..586e34f 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1426,19 +1426,19 @@ static void i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) master->ops->detach_i2c_dev(dev); } -static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) +static int i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) { struct i3c_master_controller *master = i3c_dev_get_master(dev); int ret; if (!dev->boardinfo || !dev->boardinfo->init_dyn_addr || !dev->boardinfo->static_addr) - return; + return 0; ret = i3c_master_setdasa_locked(master, dev->info.static_addr, dev->boardinfo->init_dyn_addr); if (ret) - return; + return ret; dev->info.dyn_addr = dev->boardinfo->init_dyn_addr; ret = i3c_master_reattach_i3c_dev(dev, 0); @@ -1449,10 +1449,12 @@ static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) if (ret) goto err_rstdaa; - return; + return 0; err_rstdaa: i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr); + + return ret; } static void @@ -1647,7 +1649,7 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) enum i3c_addr_slot_status status; struct i2c_dev_boardinfo *i2cboardinfo; struct i3c_dev_boardinfo *i3cboardinfo; - struct i3c_dev_desc *i3cdev; + struct i3c_dev_desc *i3cdev, *i3ctmp; struct i2c_dev_desc *i2cdev; int ret; @@ -1746,8 +1748,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) * Pre-assign dynamic address and retrieve device information if * needed. */ - i3c_bus_for_each_i3cdev(&master->bus, i3cdev) - i3c_master_pre_assign_dyn_addr(i3cdev); + list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, +common.node) { + ret = i3c_master_pre_assign_dyn_addr(i3cdev); + if (ret) { + i3c_master_detach_i3c_dev(i3cdev); + i3c_master_free_i3c_dev(i3cdev); + } + } ret = i3c_master_do_daa(master); if (ret) -- 2.7.4
RE: [PATCH v2 1/5] i3c: master: detach and free device if pre_assign_dyn_addr() fails
Hi Boris, From: Boris Brezillon Date: Tue, Sep 03, 2019 at 11:52:37 > On Tue, 3 Sep 2019 12:35:50 +0200 > Vitor Soares wrote: > > > On pre_assing_dyn_addr() the devices that fail: > > i3c_master_setdasa_locked() > > i3c_master_reattach_i3c_dev() > > i3c_master_retrieve_dev_info() > > > > are kept in memory and master->bus.devs list. This makes the i3c devices > > without a dynamic address are sent on DEFSLVS CCC command. Fix this by > > detaching and freeing the devices that fail on pre_assign_dyn_addr(). > > > > Signed-off-by: Vitor Soares > > --- > > Changes in v2: > > - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() > > So, you decided to ignore my comment about leaving the i3c_dev_desc > allocated and skipping entries that don't have a dynamic address when > forging the DEFSLVS frame instead of doing this > allocate/free/re-allocate dance, and more importantly, you didn't even > bother explaining why. > > I'm not willing to accept this patch unless you come up with solid > reasons. I think I already give a strong reason for my decision. Let say that my controller only has space for 4 devices and one of them is offline during pre_assign_dyn_addr() and hence it fails. When device tries to do the HJ I won't be able to do the enumeration because there is no space left. Anyway, you are right and I need to add this to commit message. BTW, It is not clear to me why should we keep non addressed devices allocated when we have i3c_dev_boardinfo list with ->of_node information and what is the problem with allocate/free/re-allocate dance? Best regards, Vitor Soares
RE: [PATCH v2 1/5] i3c: master: detach and free device if pre_assign_dyn_addr() fails
From: Przemyslaw Gaj Date: Tue, Sep 03, 2019 at 12:13:57 > Hi Vitor, > > I'm sorry for the delay. > > The 09/03/2019 12:35, Vitor Soares wrote: > > EXTERNAL MAIL > > > > > > On pre_assing_dyn_addr() the devices that fail: > > i3c_master_setdasa_locked() > > i3c_master_reattach_i3c_dev() > > i3c_master_retrieve_dev_info() > > > > are kept in memory and master->bus.devs list. This makes the i3c devices > > without a dynamic address are sent on DEFSLVS CCC command. Fix this by > > detaching and freeing the devices that fail on pre_assign_dyn_addr(). > > What is the problem with sending devices without dynamic address in DEFSLVS? How do you address them? For the DA field in DEFSLVS frame, the spec says: "shall contain the current value of the Slave's assigned 7-bit Dynamic address". If the device doesn't have the dynamic address assigned yet why send it? > Shouldn't we still inform rest of the devices about that? About fact that > device with SA without DA exists on the bus? I would like to understand what is the use case for this? On I3C spec table "I3C Devices Roles vs Responsibilities", Secondary Master is not responsible to do Dynamic Address Assignment but it is optional to do Hot-Join Dynamic Address Assignment. > > I think that this is limitation for us. Espacially we have SA and DA fields in > DEFSLVS frame so we are able to distinguish devices with and without Dynamic > Address. I would say the reason behind is regarding how to distinguish i2c from i3c devices. > > > > > Signed-off-by: Vitor Soares > > --- > > Changes in v2: > > - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() > > - Convert i3c_master_pre_assign_dyn_addr() to return an int > > > > drivers/i3c/master.c | 22 +++--- > > 1 file changed, 15 insertions(+), 7 deletions(-) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 5f4bd52..586e34f 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -1426,19 +1426,19 @@ static void i3c_master_detach_i2c_dev(struct > > i2c_dev_desc *dev) > > master->ops->detach_i2c_dev(dev); > > } > > > > -static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) > > +static int i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) > > { > > struct i3c_master_controller *master = i3c_dev_get_master(dev); > > int ret; > > > > if (!dev->boardinfo || !dev->boardinfo->init_dyn_addr || > > !dev->boardinfo->static_addr) > > - return; > > + return 0; > > > > ret = i3c_master_setdasa_locked(master, dev->info.static_addr, > > dev->boardinfo->init_dyn_addr); > > if (ret) > > - return; > > + return ret; > > > > dev->info.dyn_addr = dev->boardinfo->init_dyn_addr; > > ret = i3c_master_reattach_i3c_dev(dev, 0); > > @@ -1449,10 +1449,12 @@ static void i3c_master_pre_assign_dyn_addr(struct > > i3c_dev_desc *dev) > > if (ret) > > goto err_rstdaa; > > > > - return; > > + return 0; > > > > err_rstdaa: > > i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr); > > + > > + return ret; > > } > > > > static void > > @@ -1647,7 +1649,7 @@ static int i3c_master_bus_init(struct > > i3c_master_controller *master) > > enum i3c_addr_slot_status status; > > struct i2c_dev_boardinfo *i2cboardinfo; > > struct i3c_dev_boardinfo *i3cboardinfo; > > - struct i3c_dev_desc *i3cdev; > > + struct i3c_dev_desc *i3cdev, *i3ctmp; > > struct i2c_dev_desc *i2cdev; > > int ret; > > > > @@ -1746,8 +1748,14 @@ static int i3c_master_bus_init(struct > > i3c_master_controller *master) > > * Pre-assign dynamic address and retrieve device information if > > * needed. > > */ > > - i3c_bus_for_each_i3cdev(&master->bus, i3cdev) > > - i3c_master_pre_assign_dyn_addr(i3cdev); > > + list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, > > +common.node) { > > + ret = i3c_master_pre_assign_dyn_addr(i3cdev); > > + if (ret) { > > + i3c_master_detach_i3c_dev(i3cdev); > > + i3c_master_free_i3c_dev(i3cdev); > > + } > > + } > > > > ret = i3c_master_do_daa(master); > > if (ret) > > -- > > 2.7.4 > > > > -- > -- > Przemyslaw Gaj Best regards, Vitor Soares
RE: [PATCH v2 1/5] i3c: master: detach and free device if pre_assign_dyn_addr() fails
From: Przemyslaw Gaj Date: Wed, Sep 04, 2019 at 05:47:18 > The 09/03/2019 11:57, Vitor Soares wrote: > > EXTERNAL MAIL > > > > > > From: Przemyslaw Gaj > > Date: Tue, Sep 03, 2019 at 12:13:57 > > > > > Hi Vitor, > > > > > > I'm sorry for the delay. > > > > > > The 09/03/2019 12:35, Vitor Soares wrote: > > > > EXTERNAL MAIL > > > > > > > > > > > > On pre_assing_dyn_addr() the devices that fail: > > > > i3c_master_setdasa_locked() > > > > i3c_master_reattach_i3c_dev() > > > > i3c_master_retrieve_dev_info() > > > > > > > > are kept in memory and master->bus.devs list. This makes the i3c devices > > > > without a dynamic address are sent on DEFSLVS CCC command. Fix this by > > > > detaching and freeing the devices that fail on pre_assign_dyn_addr(). > > > > > > What is the problem with sending devices without dynamic address in > > > DEFSLVS? > > > > How do you address them? > > For the DA field in DEFSLVS frame, the spec says: "shall contain the > > current value of the Slave's assigned 7-bit Dynamic address". If the > > device doesn't have the dynamic address assigned yet why send it? > > > > What stops us from operating with this device in I2C mode using his SA? So, send it as an I2C device as spec says. > > > > Shouldn't we still inform rest of the devices about that? About fact that > > > device with SA without DA exists on the bus? > > > > I would like to understand what is the use case for this? > > Look above. I2C mode still should be possible IMO. Just consider the case when > you really need some information from that device, main master can assign > dynamic address later but you can make some transfers. It is true, but again it is a I2C device and not I3C device. It won't reply to I3C commands until has a DA. How will you know that the DA sent in DEFSLVS is not assigned yet? > I know our framework > does not support that case but secondary master can be different system which > should know that this device exists and don't have DA yet, so I2C mode is > available. If the HJ happen in secondary master side, there is a change to describe in DT what should be DA. Please check 2nd patch. > > > > > On I3C spec table "I3C Devices Roles vs Responsibilities", Secondary > > Master is not responsible to do Dynamic Address Assignment but it is > > optional to do Hot-Join Dynamic Address Assignment. > > > > Yes, we discussed that few times during the review of Mastership patch series. Hence, based on that table, secondary master won't do DAA just because he want, It needs a HJ to trigger DAA. Sorry, but for me based on what spec says this use case is not feasible. Best regards, Vitor Soares
[PATCH v3 4/5] dt-bindings: i3c: add a note for no guarantee of 'assigned-address' use
By default, the framework will try to assign the 'assigned-address' to the device but if the address is already in use the device dynamic address will be different. Signed-off-by: Vitor Soares Reviewed-by: Rob Herring --- Change in v3: - Add Rob rb-tag Documentation/devicetree/bindings/i3c/i3c.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt b/Documentation/devicetree/bindings/i3c/i3c.txt index c851e75..e777f09 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.txt +++ b/Documentation/devicetree/bindings/i3c/i3c.txt @@ -98,7 +98,9 @@ Required properties Optional properties --- -- assigned-address: dynamic address to be assigned to this device. +- assigned-address: dynamic address to be assigned to this device. The framework + will try to assign this dynamic address but if something + fails the device dynamic address will be different. Example: -- 2.7.4
[PATCH v3 0/5] i3c: detach/free device fail pre_assign_dyn_addr()
As for today, the I3C framework is keeping in memory and master->bus.devs list the devices that fail during pre_assign_dyn_addr() and send them on DEFSLVS command. According to MIPI I3C Bus spec the DEFSLVS command is used to inform any Secondary Master about the Dynamic Addresses that were assigned to I3C devices and the I2C devices present on the bus. This issue could be fixed by changing i3c_master_defslvs_locked() to ignore unaddressed i3c devices but the i3c_dev_desc would be allocated and attached to HC unnecessarily. This can cause that some HC aren't able to do DAA for HJ capable devices due of lack of space. This patch-series propose to detach/free devices that are failing during pre_assign_dyn_addr() and to propagate i3c_boardinfo, if available, to i3c_dev_desc during i3c_master_add_i3c_dev_locked(). Besides the fix for the problem mention above, this change will permit to describe devices with a preferable dynamic address (important due to priority reason) but without a static address in DT. In addition, I'm improving the management of the Data Address Table in DW I3C Master by keeping the free slots consecutive. Change in v3: - Change cover letter - Change commit message for patch 1 - Add Rob rb-tags Change in v2: - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() - Change i3c_master_search_i3c_boardinfo(newdev) to i3c_master_init_i3c_dev_boardinfo(newdev) - Add fixes, stable tags on patch 2 - Add a note for no guarantee of 'assigned-address' use Vitor Soares (5): i3c: master: detach and free device if pre_assign_dyn_addr() fails i3c: master: make sure ->boardinfo is initialized in add_i3c_dev_locked() dt-bindings: i3c: Make 'assigned-address' valid if static address == 0 dt-bindings: i3c: add a note for no guarantee of 'assigned-address' use i3c: master: dw: reattach device on first available location of address table Documentation/devicetree/bindings/i3c/i3c.txt | 15 ++-- drivers/i3c/master.c | 49 ++- drivers/i3c/master/dw-i3c-master.c| 16 + 3 files changed, 68 insertions(+), 12 deletions(-) -- 2.7.4
[PATCH v3 2/5] i3c: master: make sure ->boardinfo is initialized in add_i3c_dev_locked()
The newdev->boardinfo assignment was missing in i3c_master_add_i3c_dev_locked() and hence the ->of_node info isn't propagated to i3c_dev_desc. Fix this by trying to initialize device i3c_dev_boardinfo if available. Cc: Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Vitor Soares --- Change in v3: - None Changes in v2: - Change commit message - Change i3c_master_search_i3c_boardinfo(newdev) to i3c_master_init_i3c_dev_boardinfo(newdev) - Add fixes, stable tags drivers/i3c/master.c | 27 +-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 586e34f..9fb99bc 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1798,6 +1798,22 @@ i3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev) return NULL; } +static void i3c_master_init_i3c_dev_boardinfo(struct i3c_dev_desc *dev) +{ + struct i3c_master_controller *master = i3c_dev_get_master(dev); + struct i3c_dev_boardinfo *boardinfo; + + if (dev->boardinfo) + return; + + list_for_each_entry(boardinfo, &master->boardinfo.i3c, node) { + if (dev->info.pid == boardinfo->pid) { + dev->boardinfo = boardinfo; + return; + } + } +} + /** * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus * @master: master used to send frames on the bus @@ -1818,8 +1834,9 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, u8 addr) { struct i3c_device_info info = { .dyn_addr = addr }; - struct i3c_dev_desc *newdev, *olddev; u8 old_dyn_addr = addr, expected_dyn_addr; + enum i3c_addr_slot_status addrstatus; + struct i3c_dev_desc *newdev, *olddev; struct i3c_ibi_setup ibireq = { }; bool enable_ibi = false; int ret; @@ -1878,6 +1895,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, if (ret) goto err_detach_dev; + i3c_master_init_i3c_dev_boardinfo(newdev); + /* * Depending on our previous state, the expected dynamic address might * differ: @@ -1895,7 +1914,11 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, else expected_dyn_addr = newdev->info.dyn_addr; - if (newdev->info.dyn_addr != expected_dyn_addr) { + addrstatus = i3c_bus_get_addr_slot_status(&master->bus, + expected_dyn_addr); + + if (newdev->info.dyn_addr != expected_dyn_addr && + addrstatus == I3C_ADDR_SLOT_FREE) { /* * Try to apply the expected dynamic address. If it fails, keep * the address assigned by the master. -- 2.7.4
[PATCH v3 5/5] i3c: master: dw: reattach device on first available location of address table
For today the reattach function only update the device address on the controller. Update the location to the first available too, will optimize the enumeration process avoiding additional checks to keep the available positions on address table consecutive. Signed-off-by: Vitor Soares Reviewed-by: Boris Brezillon --- Change in v3: - None Change in v2: - Add Boris rb-tag drivers/i3c/master/dw-i3c-master.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97..62261ac 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -898,6 +898,22 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); struct i3c_master_controller *m = i3c_dev_get_master(dev); struct dw_i3c_master *master = to_dw_i3c_master(m); + int pos; + + pos = dw_i3c_master_get_free_pos(master); + + if (data->index > pos && pos > 0) { + writel(0, + master->regs + + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); + + master->addrs[data->index] = 0; + master->free_pos |= BIT(data->index); + + data->index = pos; + master->addrs[pos] = dev->info.dyn_addr; + master->free_pos &= ~BIT(pos); + } writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), master->regs + -- 2.7.4
[PATCH v3 1/5] i3c: master: detach/free devices fail on pre_assign_dyn_addr()
As for today, the I3C framework is keeping in memory and master->bus.devs list the devices that fail during pre_assign_dyn_addr() and send them on DEFSLVS command. According to MIPI I3C Bus spec the DEFSLVS command is used to inform any Secondary Master about the Dynamic Addresses that were assigned to I3C devices and the I2C devices present on the bus. This issue could be fixed by changing i3c_master_defslvs_locked() to ignore unaddressed i3c devices but the i3c_dev_desc would be allocated and attached to HC unnecessarily. This can cause that some HC aren't able to do DAA for HJ capable devices due to lack of space in controller. Signed-off-by: Vitor Soares --- Changes in v3: - Change commit message Changes in v2: - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() - Convert i3c_master_pre_assign_dyn_addr() to return an int drivers/i3c/master.c | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..586e34f 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1426,19 +1426,19 @@ static void i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) master->ops->detach_i2c_dev(dev); } -static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) +static int i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) { struct i3c_master_controller *master = i3c_dev_get_master(dev); int ret; if (!dev->boardinfo || !dev->boardinfo->init_dyn_addr || !dev->boardinfo->static_addr) - return; + return 0; ret = i3c_master_setdasa_locked(master, dev->info.static_addr, dev->boardinfo->init_dyn_addr); if (ret) - return; + return ret; dev->info.dyn_addr = dev->boardinfo->init_dyn_addr; ret = i3c_master_reattach_i3c_dev(dev, 0); @@ -1449,10 +1449,12 @@ static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) if (ret) goto err_rstdaa; - return; + return 0; err_rstdaa: i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr); + + return ret; } static void @@ -1647,7 +1649,7 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) enum i3c_addr_slot_status status; struct i2c_dev_boardinfo *i2cboardinfo; struct i3c_dev_boardinfo *i3cboardinfo; - struct i3c_dev_desc *i3cdev; + struct i3c_dev_desc *i3cdev, *i3ctmp; struct i2c_dev_desc *i2cdev; int ret; @@ -1746,8 +1748,14 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) * Pre-assign dynamic address and retrieve device information if * needed. */ - i3c_bus_for_each_i3cdev(&master->bus, i3cdev) - i3c_master_pre_assign_dyn_addr(i3cdev); + list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, +common.node) { + ret = i3c_master_pre_assign_dyn_addr(i3cdev); + if (ret) { + i3c_master_detach_i3c_dev(i3cdev); + i3c_master_free_i3c_dev(i3cdev); + } + } ret = i3c_master_do_daa(master); if (ret) -- 2.7.4
[PATCH v3 3/5] dt-bindings: i3c: Make 'assigned-address' valid if static address == 0
The I3C devices without a static address can require a specific dynamic address for priority reasons. Let's update the binding document to make the 'assigned-address' property valid if static address == 0 and add an example with this use case. Signed-off-by: Vitor Soares Reviewed-by: Rob Herring --- Change in v3: - Add Rob rb-tag Change in v2: - Fix typo in commit message Documentation/devicetree/bindings/i3c/i3c.txt | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/i3c/i3c.txt b/Documentation/devicetree/bindings/i3c/i3c.txt index ab729a0..c851e75 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.txt +++ b/Documentation/devicetree/bindings/i3c/i3c.txt @@ -98,9 +98,7 @@ Required properties Optional properties --- -- assigned-address: dynamic address to be assigned to this device. This - property is only valid if the I3C device has a static - address (first cell of the reg property != 0). +- assigned-address: dynamic address to be assigned to this device. Example: @@ -129,6 +127,15 @@ Example: /* * I3C device without a static I2C address but requiring +* specific dynamic address. +*/ + sensor@0,39200154004 { + reg = <0x0 0x6072 0x303904d2>; + assigned-address = <0xb>; + }; + + /* +* I3C device without a static I2C address but requiring * resources described in the DT. */ sensor@0,39200154004 { -- 2.7.4
RE: [PATCH v3 1/5] i3c: master: detach/free devices fail on pre_assign_dyn_addr()
Hi Boris, From: Vitor Soares Date: Thu, Sep 05, 2019 at 11:00:34 > As for today, the I3C framework is keeping in memory and master->bus.devs > list the devices that fail during pre_assign_dyn_addr() and send them on > DEFSLVS command. > > According to MIPI I3C Bus spec the DEFSLVS command is used to inform any > Secondary Master about the Dynamic Addresses that were assigned to I3C > devices and the I2C devices present on the bus. > > This issue could be fixed by changing i3c_master_defslvs_locked() to > ignore unaddressed i3c devices but the i3c_dev_desc would be allocated and > attached to HC unnecessarily. This can cause that some HC aren't able to > do DAA for HJ capable devices due to lack of space in controller. > > Signed-off-by: Vitor Soares > --- > Changes in v3: > - Change commit message > > Changes in v2: > - Move out detach/free the i3c_dev_desc from pre_assign_dyn_addr() > - Convert i3c_master_pre_assign_dyn_addr() to return an int > > drivers/i3c/master.c | 22 +++--- > 1 file changed, 15 insertions(+), 7 deletions(-) > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > index 5f4bd52..586e34f 100644 > --- a/drivers/i3c/master.c > +++ b/drivers/i3c/master.c > @@ -1426,19 +1426,19 @@ static void i3c_master_detach_i2c_dev(struct > i2c_dev_desc *dev) > master->ops->detach_i2c_dev(dev); > } > > -static void i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) > +static int i3c_master_pre_assign_dyn_addr(struct i3c_dev_desc *dev) > { > struct i3c_master_controller *master = i3c_dev_get_master(dev); > int ret; > > if (!dev->boardinfo || !dev->boardinfo->init_dyn_addr || > !dev->boardinfo->static_addr) > - return; > + return 0; > > ret = i3c_master_setdasa_locked(master, dev->info.static_addr, > dev->boardinfo->init_dyn_addr); > if (ret) > - return; > + return ret; > > dev->info.dyn_addr = dev->boardinfo->init_dyn_addr; > ret = i3c_master_reattach_i3c_dev(dev, 0); > @@ -1449,10 +1449,12 @@ static void i3c_master_pre_assign_dyn_addr(struct > i3c_dev_desc *dev) > if (ret) > goto err_rstdaa; > > - return; > + return 0; > > err_rstdaa: > i3c_master_rstdaa_locked(master, dev->boardinfo->init_dyn_addr); > + > + return ret; > } > > static void > @@ -1647,7 +1649,7 @@ static int i3c_master_bus_init(struct > i3c_master_controller *master) > enum i3c_addr_slot_status status; > struct i2c_dev_boardinfo *i2cboardinfo; > struct i3c_dev_boardinfo *i3cboardinfo; > - struct i3c_dev_desc *i3cdev; > + struct i3c_dev_desc *i3cdev, *i3ctmp; > struct i2c_dev_desc *i2cdev; > int ret; > > @@ -1746,8 +1748,14 @@ static int i3c_master_bus_init(struct > i3c_master_controller *master) >* Pre-assign dynamic address and retrieve device information if >* needed. >*/ > - i3c_bus_for_each_i3cdev(&master->bus, i3cdev) > - i3c_master_pre_assign_dyn_addr(i3cdev); > + list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, > + common.node) { > + ret = i3c_master_pre_assign_dyn_addr(i3cdev); > + if (ret) { > + i3c_master_detach_i3c_dev(i3cdev); > + i3c_master_free_i3c_dev(i3cdev); > + } > + } > > ret = i3c_master_do_daa(master); > if (ret) > -- > 2.7.4 I think I clearly explain why the current solution is problematic and my choices for the proposal solution. Please let me know if there is anything else that I can improve in this patch. Best regards, Vitor Soares
RE: [PATCH v6 2/2] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
Hi Jonathan, From: Jonathan Cameron Date: Thu, Oct 03, 2019 at 12:49:02 > On Wed, 25 Sep 2019 15:35:10 + > Vitor Soares wrote: > > > Hi Jonathan, > > > > From: Jonathan Cameron > > Date: Sun, Jul 21, 2019 at 18:16:56 > > > > > On Fri, 19 Jul 2019 15:30:55 +0200 > > > Vitor Soares wrote: > > > > > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only > > > > in > > > > spi and i2c mode. > > > > > > > > The LSM6DSO and LSM6DSR are also i3c capable so let's give i3c support > > > > to > > > > them. > > > > > > > > Signed-off-by: Vitor Soares > > > > Acked-by: Lorenzo Bianconi > > > > Reviewed-by: Boris Brezillon > > > Great. I'll pick this up once Boris has that immutable branch > > > available. Give me a poke if I seem to have lost it! > > > > > > Thanks, > > > > > > Jonathan > > > > I didn't see the i3c support for st_lsm6dsx driver in pull request, could > > you please check it? > Seems to have made it > > https://urldefense.proofpoint.com/v2/url?u=https-3A__git.kernel.org_pub_scm_linux_kernel_git_torvalds_linux.git_tree_drivers_iio_imu_st-5Flsm6dsx_st-5Flsm6dsx-5Fi3c.c-3Fh-3Dv5.4-2Drc1&d=DwICAg&c=DPL6_X_6JkXFx7AXWqB0tg&r=qVuU64u9x77Y0Kd0PhDK_lpxFgg6PK9PateHwjb_DY0&m=RaUb9HXBdF5dxPWn5sdO7gqqaQzqY7UFd8Rcv0ioTx0&s=-Xs5gaN2wau8fXfg5hryTStGMVD8WFA66mX0hCMsmXg&e= > > > I checked back. Was in the first pull request back on the 12th of August. > > Jonathan I confirm that is there. I'm already using it. Thanks a lot. Best regards, Vitor Soares
RE: [PATCH v3 2/5] i3c: master: make sure ->boardinfo is initialized in add_i3c_dev_locked()
Hi Boris, From: Boris Brezillon Date: Thu, Oct 03, 2019 at 15:29:43 > On Thu, 5 Sep 2019 12:00:35 +0200 > Vitor Soares wrote: > > > The newdev->boardinfo assignment was missing in > > i3c_master_add_i3c_dev_locked() and hence the ->of_node info isn't > > propagated to i3c_dev_desc. > > > > Fix this by trying to initialize device i3c_dev_boardinfo if available. > > > > Cc: > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > Signed-off-by: Vitor Soares > > --- > > Change in v3: > > - None > > > > Changes in v2: > > - Change commit message > > - Change i3c_master_search_i3c_boardinfo(newdev) to > > i3c_master_init_i3c_dev_boardinfo(newdev) > > - Add fixes, stable tags > > > > /** > > * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus > > * @master: master used to send frames on the bus > > @@ -1818,8 +1834,9 @@ int i3c_master_add_i3c_dev_locked(struct > > i3c_master_controller *master, > > u8 addr) > > { > > struct i3c_device_info info = { .dyn_addr = addr }; > > - struct i3c_dev_desc *newdev, *olddev; > > u8 old_dyn_addr = addr, expected_dyn_addr; > > + enum i3c_addr_slot_status addrstatus; > > + struct i3c_dev_desc *newdev, *olddev; > > struct i3c_ibi_setup ibireq = { }; > > bool enable_ibi = false; > > int ret; > > @@ -1878,6 +1895,8 @@ int i3c_master_add_i3c_dev_locked(struct > > i3c_master_controller *master, > > if (ret) > > goto err_detach_dev; > > > > + i3c_master_init_i3c_dev_boardinfo(newdev); > > + > > /* > > * Depending on our previous state, the expected dynamic address might > > * differ: > > @@ -1895,7 +1914,11 @@ int i3c_master_add_i3c_dev_locked(struct > > i3c_master_controller *master, > > else > > expected_dyn_addr = newdev->info.dyn_addr; > > > > - if (newdev->info.dyn_addr != expected_dyn_addr) { > > + addrstatus = i3c_bus_get_addr_slot_status(&master->bus, > > + expected_dyn_addr); > > + > > + if (newdev->info.dyn_addr != expected_dyn_addr && > > + addrstatus == I3C_ADDR_SLOT_FREE) { > > First, this change shouldn't be part of this patch, since the commit > message only mentions the boardinfo init stuff, This is not an issue, I can create a patch just for boardinfo init fix. > not the extra 'is slot > free check'. Even ignoring patch 1, it is necessary to check if the slot is free because if SETDASA fails the boardinfo->init_dyn_addr can be assigned to another device. That's why we need to check if expected_dyn_addr is free. > Plus, I want the fix to be backported so we should avoid > any unneeded deps. > > But even with those 2 things addressed, I'm still convinced the > 'free desc when device is not reachable' change you do in patch 1 is > not that great, If I'm doing wrong I really appreciate you tell me the reason. > and the fact that you can't pre-reserve the address to > make sure no one uses it until the device had a chance to show up tends > to prove me right. This is a different corner case and I though we agreed that the framework doesn't provide guarantees to assign boardinfo->init_dyn_addr [1]. Yet, I don't disagree with the idea of pre-reserve the boardinfo->init_dyn_addr. I can do this but we need to align how it should be done. > > Can we please do what I suggest and solve the "not enough dev slots" > problem later on (if we really have to). I have this use case where the HC has only 4 slot for 4 devices. Sometimes the one or more devices can be sleeping and when they trigger HJ there is no space in HC. Best regards, Vitor Soares [1] https://patchwork.kernel.org/patch/11120841/
RE: [PATCH v6 2/2] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
Hi Jonathan, From: Jonathan Cameron Date: Sun, Jul 21, 2019 at 18:16:56 > On Fri, 19 Jul 2019 15:30:55 +0200 > Vitor Soares wrote: > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in > > spi and i2c mode. > > > > The LSM6DSO and LSM6DSR are also i3c capable so let's give i3c support to > > them. > > > > Signed-off-by: Vitor Soares > > Acked-by: Lorenzo Bianconi > > Reviewed-by: Boris Brezillon > Great. I'll pick this up once Boris has that immutable branch > available. Give me a poke if I seem to have lost it! > > Thanks, > > Jonathan I didn't see the i3c support for st_lsm6dsx driver in pull request, could you please check it? Best regards, Vitor Soares > > --- > > Changes in v6: > > none > > > > Changes in v5: > > Move regmap_config declaration inside st_lsm6dsx_i3c_probe() > > Fix warning [-Wint-to-void-pointer-cast] when compiling in 64-bit arch > > > > Changes in v4: > > Remove hw_id variable > > > > Changes in v3: > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name > > Use st_lsm6dsx_probe new form > > > > Changes in v2: > > Add support for LSM6DSR > > Set pm_ops to st_lsm6dsx_pm_ops > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 57 > > + > > 3 files changed, 65 insertions(+), 1 deletion(-) > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig > > b/drivers/iio/imu/st_lsm6dsx/Kconfig > > index 9e59297..6b5a73c 100644 > > --- a/drivers/iio/imu/st_lsm6dsx/Kconfig > > +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig > > @@ -1,11 +1,12 @@ > > > > config IIO_ST_LSM6DSX > > tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" > > - depends on (I2C || SPI) > > + depends on (I2C || SPI || I3C) > > select IIO_BUFFER > > select IIO_KFIFO_BUF > > select IIO_ST_LSM6DSX_I2C if (I2C) > > select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) > > + select IIO_ST_LSM6DSX_I3C if (I3C) > > help > > Say yes here to build support for STMicroelectronics LSM6DSx imu > > sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, > > @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI > > tristate > > depends on IIO_ST_LSM6DSX > > select REGMAP_SPI > > + > > +config IIO_ST_LSM6DSX_I3C > > + tristate > > + depends on IIO_ST_LSM6DSX > > + select REGMAP_I3C > > diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile > > b/drivers/iio/imu/st_lsm6dsx/Makefile > > index e5f733c..c676965 100644 > > --- a/drivers/iio/imu/st_lsm6dsx/Makefile > > +++ b/drivers/iio/imu/st_lsm6dsx/Makefile > > @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ > > obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o > > obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o > > obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o > > +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > new file mode 100644 > > index 000..57e6331 > > --- /dev/null > > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > @@ -0,0 +1,57 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > + * > > + * Author: Vitor Soares > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "st_lsm6dsx.h" > > + > > +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { > > + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), > > + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), > > + { /* sentinel */ }, > > +}; > > +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); > > + > > +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) > > +{ > > + struct regmap_config st_lsm6dsx_i3c_regmap_config = { > > + .reg_bits = 8, > > + .val_bits = 8, > > + }; > > + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, > > + st_lsm6dsx_i3c_ids); >
RE: [PATCH v4 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
Hi Boris, From: Boris Brezillon Date: Fri, Jul 12, 2019 at 21:03:20 > On Fri, 12 Jul 2019 18:40:14 + > Vitor Soares wrote: > > > From: Boris Brezillon > > Date: Fri, Jul 12, 2019 at 17:43:23 > > > > > On Fri, 12 Jul 2019 16:28:02 + > > > Vitor Soares wrote: > > > > > > > From: Boris Brezillon > > > > Date: Fri, Jul 12, 2019 at 17:14:29 > > > > > > > > > On Fri, 12 Jul 2019 13:53:30 +0200 > > > > > Vitor Soares wrote: > > > > > > > > > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor > > > > > > only in > > > > > > spi and i2c mode. > > > > > > > > > > > > The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c > > > > > > support to > > > > > > them. > > > > > > > > > > > > Signed-off-by: Vitor Soares > > > > > > Acked-by: Lorenzo Bianconi > > > > > > --- > > > > > > Changes in v4: > > > > > > Remove hw_id variable > > > > > > > > > > > > Changes in v3: > > > > > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device > > > > > > name > > > > > > Use st_lsm6dsx_probe new form > > > > > > > > > > > > Changes in v2: > > > > > > Add support for LSM6DSR > > > > > > Set pm_ops to st_lsm6dsx_pm_ops > > > > > > > > > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > > > > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > > > > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 58 > > > > > > + > > > > > > 3 files changed, 66 insertions(+), 1 deletion(-) > > > > > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > > > > > > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > > > b/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > > > index 9e59297..6b5a73c 100644 > > > > > > --- a/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > > > +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > > > @@ -1,11 +1,12 @@ > > > > > > > > > > > > config IIO_ST_LSM6DSX > > > > > > tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" > > > > > > - depends on (I2C || SPI) > > > > > > + depends on (I2C || SPI || I3C) > > > > > > select IIO_BUFFER > > > > > > select IIO_KFIFO_BUF > > > > > > select IIO_ST_LSM6DSX_I2C if (I2C) > > > > > > select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) > > > > > > + select IIO_ST_LSM6DSX_I3C if (I3C) > > > > > > help > > > > > > Say yes here to build support for STMicroelectronics LSM6DSx > > > > > > imu > > > > > > sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, > > > > > > lsm6dsm, > > > > > > @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI > > > > > > tristate > > > > > > depends on IIO_ST_LSM6DSX > > > > > > select REGMAP_SPI > > > > > > + > > > > > > +config IIO_ST_LSM6DSX_I3C > > > > > > + tristate > > > > > > + depends on IIO_ST_LSM6DSX > > > > > > + select REGMAP_I3C > > > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile > > > > > > b/drivers/iio/imu/st_lsm6dsx/Makefile > > > > > > index e5f733c..c676965 100644 > > > > > > --- a/drivers/iio/imu/st_lsm6dsx/Makefile > > > > > > +++ b/drivers/iio/imu/st_lsm6dsx/Makefile > > > > > > @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o > > > > > > st_lsm6dsx_buffer.o \ > > > > > > obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o > > > > > > obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o > > > > > > obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o > > > > > > +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o > > > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c &g
RE: [PATCH 1/3] i3c: fix i2c and i3c scl rate by bus mode
Hi Boris, From: Boris Brezillon Date: Tue, Apr 16, 2019 at 15:52:50 > On Tue, 16 Apr 2019 14:24:57 + > Vitor Soares wrote: > > > Hi Boris, > > > > From: Boris Brezillon > > Date: Tue, Apr 16, 2019 at 06:50:41 > > > > > On Mon, 15 Apr 2019 20:46:41 +0200 > > > Vitor Soares wrote: > > > > > > > Currently in case of mixed slow bus topologie and all i2c devices > > > > support FM+ speed, the i3c subsystem limite the SCL to FM speed. > > > > > > > I will it replace with your message below. > > > > > " > > > Currently the I3C framework limits SCL frequency to FM speed when > > > dealing with a mixed slow bus, even if all I2C devices are FM+ capable. > > > " > > > > > > > Also in case on mixed slow bus mode the max speed for both > > > > i2c or i3c transfers is FM or FM+. > > > > > > Looks like you're basically repeating what you said above. > > > > What I meant was that I3C framework isn't limiting the I3C speed in case > > of mixed slow bus. > > Oh, okay, then maybe something like > > " > The core was also not accounting for I3C speed limitations when > operating in mixed slow mode and was erroneously using FM+ speed as the > max I2C speed when operating in mixed fast mode. > " Sounds good to me. Thanks for the advise. > > > > > > > > > > > > > > This patch fix the definition of i2c and i3c scl rate based on bus > > > > > >^fixes on the bus > > > > > > > topologie and LVR[4] if no user input. > > > > > > ^topology ^if the rate is not already specified by the > > > user. > > > > > > > In case of mixed slow mode the i3c scl rate is overridden. > > > > > > ^ with the max > > > I2C rate. > > > > > > > > > > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > > > Signed-off-by: Vitor Soares > > > > Cc: Boris Brezillon > > > > Cc: > > > > Cc: > > > > --- > > > > drivers/i3c/master.c | 39 +-- > > > > 1 file changed, 25 insertions(+), 14 deletions(-) > > > > > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > > > index 909c2ad..1c4a86a 100644 > > > > --- a/drivers/i3c/master.c > > > > +++ b/drivers/i3c/master.c > > > > @@ -564,20 +564,30 @@ static const struct device_type > > > > i3c_masterdev_type = { > > > > .groups = i3c_masterdev_groups, > > > > }; > > > > > > > > -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) > > > > +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, > > > > +unsigned long i2c_scl_rate) > > > > > > > > > Can we rename the last arg into max_i2c_scl_rate? > > > > The i2c_scl_rate is base on LVR[4] bit and the user can set a higher scl > > rate, this is reason I didn't named it to max_i2c_scl_rate. > > But if you think that make more sense I'm ok with that. > > In this context it does encode the maximum rate allowed by the spec > (based on LVR parsing), so max_i2c_rate sounds like a correct name to > me. > > > > > > > > > > { > > > > i3cbus->mode = mode; > > > > > > > > - if (!i3cbus->scl_rate.i3c) > > > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > - > > > > - if (!i3cbus->scl_rate.i2c) { > > > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > > > - else > > > > - i3cbus->scl_rate.i2c = > > > > I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > > > + switch (i3cbus->mode) { > > > > + case I3C_BUS_MODE_PURE: > > > > + if (!i3cbus->scl_rate.i3c) > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + break; > > > > + case I3C_BUS_MODE_MIXED_FAST: > > > > + if (!
RE: [PATCH 1/3] i3c: fix i2c and i3c scl rate by bus mode
From: Boris Brezillon Date: Mon, Apr 22, 2019 at 17:07:15 > On Mon, 22 Apr 2019 15:54:33 + > Vitor Soares wrote: > > > > > > > > > > > > > { > > > > > > i3cbus->mode = mode; > > > > > > > > > > > > - if (!i3cbus->scl_rate.i3c) > > > > > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > > > - > > > > > > - if (!i3cbus->scl_rate.i2c) { > > > > > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > > > > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > > > > > - else > > > > > > - i3cbus->scl_rate.i2c = > > > > > > I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > > > > > + switch (i3cbus->mode) { > > > > > > + case I3C_BUS_MODE_PURE: > > > > > > + if (!i3cbus->scl_rate.i3c) > > > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > > > + break; > > > > > > + case I3C_BUS_MODE_MIXED_FAST: > > > > > > + if (!i3cbus->scl_rate.i3c) > > > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > > > + if (!i3cbus->scl_rate.i2c) > > > > > > + i3cbus->scl_rate.i2c = i2c_scl_rate; > > > > > > + break; > > > > > > + case I3C_BUS_MODE_MIXED_SLOW: > > > > > > + if (!i3cbus->scl_rate.i2c) > > > > > > + i3cbus->scl_rate.i2c = i2c_scl_rate; > > > > > > + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > > > > > > > > > Maybe we should do > > > > > > > > > > if (!i3cbus->scl_rate.i3c || > > > > > i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) > > > > > i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > > > > > > > > > Just in case the I3C rate forced by the user is lower than the max I2C > > > > > rate. > > > > > > > > That was something that I considered but TBH it isn't a real use case. > > > > > > Add a WARN_ON() to at least catch such inconsistencies. And maybe we > > > should add a dev_warn() when the user-defined rates do not match > > > the mode/LVR constraints. It's easy to do a mistake when writing a dts. > > > > I think the WARN_ON() is too evasive on the screen and won't provide the > > information we want. > > The dev_warn() should work perfectly here. > > > > if (i3cbus->scl_rate.i3c < i3cbus->scl_rate.i2c) > > dev_warn(&i3cbus->cur_master->dev->dev, > > "%s: i3c-scl-hz lower then i2c-scl-hz\n", > > __func__); > > Using dev_warn() sounds good, though I don't think you need the > __func__ here. Also, please print the i2c/i3c rates in the message, and > align the second line on the open parens. > > > if (i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_SCL_RATE || > > i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_PLUS_SCL_RATE) > > dev_warn(&i3cbus->cur_master->dev->dev, > > "%s: i2c-scl-hz not defined according MIPI > > I3C spec\n", > > __func__); > > Is that really a problem? Having an i2c rate that is less than FM speed > sounds like a valid case to me. I'm addressing the spec constrains. In the practice it can be SM or even HS, it depends on the interface. > > > > > Maybe it make more sense to do this check on of_populate_i3c_bus(), what > > do you think? > > > > No, we really want to have this check here, because we might support > other HW description formats at some point (board-files, ACPI, ...). Yes, you are right. I forgot that point.
RE: [PATCH 1/3] i3c: fix i2c and i3c scl rate by bus mode
From: Boris Brezillon Date: Mon, Apr 22, 2019 at 19:27:32 > On Mon, 22 Apr 2019 17:54:29 + > Vitor Soares wrote: > > > > > > > > > > > > > > > > { > > > > > > > > i3cbus->mode = mode; > > > > > > > > > > > > > > > > - if (!i3cbus->scl_rate.i3c) > > > > > > > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > > > > > - > > > > > > > > - if (!i3cbus->scl_rate.i2c) { > > > > > > > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > > > > > > > - i3cbus->scl_rate.i2c = > > > > > > > > I3C_BUS_I2C_FM_SCL_RATE; > > > > > > > > - else > > > > > > > > - i3cbus->scl_rate.i2c = > > > > > > > > I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > > > > > > > + switch (i3cbus->mode) { > > > > > > > > + case I3C_BUS_MODE_PURE: > > > > > > > > + if (!i3cbus->scl_rate.i3c) > > > > > > > > + i3cbus->scl_rate.i3c = > > > > > > > > I3C_BUS_TYP_I3C_SCL_RATE; > > > > > > > > + break; > > > > > > > > + case I3C_BUS_MODE_MIXED_FAST: > > > > > > > > + if (!i3cbus->scl_rate.i3c) > > > > > > > > + i3cbus->scl_rate.i3c = > > > > > > > > I3C_BUS_TYP_I3C_SCL_RATE; > > > > > > > > + if (!i3cbus->scl_rate.i2c) > > > > > > > > + i3cbus->scl_rate.i2c = i2c_scl_rate; > > > > > > > > + break; > > > > > > > > + case I3C_BUS_MODE_MIXED_SLOW: > > > > > > > > + if (!i3cbus->scl_rate.i2c) > > > > > > > > + i3cbus->scl_rate.i2c = i2c_scl_rate; > > > > > > > > + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > > > > > > > > > > > > > > > > > > > > > Maybe we should do > > > > > > > > > > > > > > if (!i3cbus->scl_rate.i3c || > > > > > > > i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) > > > > > > > i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > > > > > > > > > > > > > Just in case the I3C rate forced by the user is lower than the > > > > > > > max I2C > > > > > > > rate. > > > > > > > > > > > > That was something that I considered but TBH it isn't a real use > > > > > > case. > > > > > > > > > > Add a WARN_ON() to at least catch such inconsistencies. And maybe we > > > > > should add a dev_warn() when the user-defined rates do not match > > > > > the mode/LVR constraints. It's easy to do a mistake when writing a > > > > > dts. > > > > > > > > I think the WARN_ON() is too evasive on the screen and won't provide > > > > the > > > > information we want. > > > > The dev_warn() should work perfectly here. > > > > > > > > if (i3cbus->scl_rate.i3c < i3cbus->scl_rate.i2c) > > > > dev_warn(&i3cbus->cur_master->dev->dev, > > > > "%s: i3c-scl-hz lower then > > > > i2c-scl-hz\n", __func__); > > > > > > Using dev_warn() sounds good, though I don't think you need the > > > __func__ here. Also, please print the i2c/i3c rates in the message, and > > > align the second line on the open parens. > > > > > > > if (i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_SCL_RATE || > > > > i3cbus->scl_rate.i2c != > > > > I3C_BUS_I2C_FM_PLUS_SCL_RATE) > > > > dev_warn(&i3cbus->cur_master->dev->dev, > > > > "%s: i2
RE: [PATCH 1/3] remap: Add I3C bus support
Hi Mark, From: Mark Brown Date: Tue, Apr 16, 2019 at 16:39:48 > On Mon, Apr 15, 2019 at 09:19:39PM +0200, Vitor Soares wrote: > > > +++ b/drivers/base/regmap/regmap-i3c.c > > @@ -0,0 +1,62 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > Please make the entire header C++ style so it looks more consistent. > Otherwise this looks good modulo I will change it next drop. > Boris' comment; I'm fine with leaving > extra modes for later so long as they can be introduced without > disrupting existing users so the only question there would be if we > should name the init function in some way that's specific to the I/O > mode being used here. My concern is that booth modes (SDR/HDR) might be needed on the device. e.g. use SDR to configure the device and use HDR to send/receive large data. Best regards, Vitor Soares
RE: [PATCH 1/3] remap: Add I3C bus support
Hi Boris, From: Boris Brezillon Date: Tue, Apr 23, 2019 at 16:14:16 > On Tue, 23 Apr 2019 14:58:06 + > Vitor Soares wrote: > > > Hi Mark, > > > > From: Mark Brown > > Date: Tue, Apr 16, 2019 at 16:39:48 > > > > > On Mon, Apr 15, 2019 at 09:19:39PM +0200, Vitor Soares wrote: > > > > > > > +++ b/drivers/base/regmap/regmap-i3c.c > > > > @@ -0,0 +1,62 @@ > > > > +// SPDX-License-Identifier: GPL-2.0 > > > > +/* > > > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > > > > > Please make the entire header C++ style so it looks more consistent. > > > Otherwise this looks good modulo > > > > I will change it next drop. > > > > > Boris' comment; I'm fine with leaving > > > extra modes for later so long as they can be introduced without > > > disrupting existing users so the only question there would be if we > > > should name the init function in some way that's specific to the I/O > > > mode being used here. > > > > My concern is that booth modes (SDR/HDR) might be needed on the device. > > e.g. use SDR to configure the device and use HDR to send/receive large > > data. > > I'd say that we shouldn't use the regmap abstraction in this case or > have a driver-specific backend implementation for it. I guess the > common case is "regs are accessed in SDR mode", so let's keep the name > as it is now and we'll define devm_regmap_init_i3c_hdr() if we ever > need it. Please make it explicit in the kernel-doc that we're using SDR > transfers here. Where should it be documented? Can you give an example? Thanks, Vitor Soares
[PATCH v4 0/3] Add ST lsm6dso i3c support
This patch series add i3c support for STM LSM6DSO and LSM6DSR sensors. It is also introduced i3c support on regmap api. Due the lack of i3c devices HDR capables on the market the support for now is only for i3c sdr mode by using i3c_device_do_priv_xfers() method. The i3c regmap api is already available in the Git repository at: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/regmap-i3c Change in v4: remover hw_id variable from st_lsm6dsx_i3c_probe() Change in v3: Update st_lsm6dsx_probe() call Remove i3c_get_device_id() and use i3c_device_match_id() Changes in v2: Change i3c_get_device_id() to drivers/i3c/device.c Add support for LSM6DSR Vitor Soares (3): regmap: add i3c bus support i3c: add i3c_get_device_id helper iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR drivers/base/regmap/Kconfig | 6 ++- drivers/base/regmap/Makefile| 1 + drivers/base/regmap/regmap-i3c.c| 60 + drivers/i3c/device.c| 46 ++ drivers/i3c/master.c| 45 -- drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 58 include/linux/i3c/device.h | 4 ++ include/linux/regmap.h | 20 ++ 10 files changed, 202 insertions(+), 47 deletions(-) create mode 100644 drivers/base/regmap/regmap-i3c.c create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c -- 2.7.4
[PATCH v4 1/3] regmap: add i3c bus support
Add basic support for i3c bus. This is a simple implementation that only give support for SDR Read and Write commands. Signed-off-by: Vitor Soares --- drivers/base/regmap/Kconfig | 6 +++- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-i3c.c | 60 include/linux/regmap.h | 20 ++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-i3c.c diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 6ad5ef4..c8bbf53 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,7 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_I3C) select IRQ_DOMAIN if REGMAP_IRQ bool @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE config REGMAP_SCCB tristate depends on I2C + +config REGMAP_I3C + tristate + depends on I3C diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index f5b4e88..ff6c7d8 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_W1) += regmap-w1.o obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o diff --git a/drivers/base/regmap/regmap-i3c.c b/drivers/base/regmap/regmap-i3c.c new file mode 100644 index 000..1578fb5 --- /dev/null +++ b/drivers/base/regmap/regmap-i3c.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + +#include +#include +#include +#include + +static int regmap_i3c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = count, + .data.out = data, + }, + }; + + return i3c_device_do_priv_xfers(i3c, xfers, 1); +} + +static int regmap_i3c_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[2]; + + xfers[0].rnw = false; + xfers[0].len = reg_size; + xfers[0].data.out = reg; + + xfers[1].rnw = true; + xfers[1].len = val_size; + xfers[1].data.in = val; + + return i3c_device_do_priv_xfers(i3c, xfers, 2); +} + +static struct regmap_bus regmap_i3c = { + .write = regmap_i3c_write, + .read = regmap_i3c_read, +}; + +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("Regmap I3C Module"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index daeec7d..f65984d 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -25,6 +25,7 @@ struct module; struct clk; struct device; struct i2c_client; +struct i3c_device; struct irq_domain; struct slim_device; struct spi_device; @@ -624,6 +625,10 @@ struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, +const struct regmap_config *config, +struct lock_class_key *lock_key, +const char *lock_name); /* * Wrapper for regmap_init macros to include a unique lockdep key and name * for each call. No-op if CONFIG_LOCKDEP is not set. @@ -982,6 +987,21 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); #define devm_regmap_init_slimbus(slimbus, config) \ __regmap_lockdep_wrapper(__devm_regmap_init_slimbus, #config, \ slimbus, config) + +/** + * devm_regmap_init_i3c() - Initialise managed re
[PATCH v4 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in spi and i2c mode. The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to them. Signed-off-by: Vitor Soares Acked-by: Lorenzo Bianconi --- Changes in v4: Remove hw_id variable Changes in v3: Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name Use st_lsm6dsx_probe new form Changes in v2: Add support for LSM6DSR Set pm_ops to st_lsm6dsx_pm_ops drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 58 + 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 9e59297..6b5a73c 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -1,11 +1,12 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index e5f733c..c676965 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000..2e89524 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static const struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, + st_lsm6dsx_i3c_ids); + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, (int)id->data, regmap); +} + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4
[PATCH v4 2/3] i3c: move i3c_device_match_id to device.c and export it
The i3c device driver needs the i3c_device_id table. Lets move it to device.c and export it to be used. Signed-off-by: Vitor Soares --- Changes in v4: None Changes in v3: Remove i3c_get_device_id Move i3c_device_match_id from drivers/i3c/master.c to drivers/i3c/device.c Export i3c_device_match_id Changes in v2: move this function to drivers/i3c/device.c drivers/i3c/device.c | 46 ++ drivers/i3c/master.c | 45 - include/linux/i3c/device.h | 4 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 69cc040..383df3b 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -200,6 +200,52 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) } EXPORT_SYMBOL_GPL(dev_to_i3cdev); +const struct i3c_device_id * +i3c_device_match_id(struct i3c_device *i3cdev, + const struct i3c_device_id *id_table) +{ + struct i3c_device_info devinfo; + const struct i3c_device_id *id; + + i3c_device_get_info(i3cdev, &devinfo); + + /* +* The lower 32bits of the provisional ID is just filled with a random +* value, try to match using DCR info. +*/ + if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { + u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); + u16 part = I3C_PID_PART_ID(devinfo.pid); + u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); + + /* First try to match by manufacturer/part ID. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != + I3C_MATCH_MANUF_AND_PART) + continue; + + if (manuf != id->manuf_id || part != id->part_id) + continue; + + if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && + ext_info != id->extra_info) + continue; + + return id; + } + } + + /* Fallback to DCR match. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_DCR) && + id->dcr == devinfo.dcr) + return id; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(i3c_device_match_id); + /** * i3c_driver_register_with_owner() - register an I3C device driver * diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..7667f84 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -270,51 +270,6 @@ static const struct device_type i3c_device_type = { .uevent = i3c_device_uevent, }; -static const struct i3c_device_id * -i3c_device_match_id(struct i3c_device *i3cdev, - const struct i3c_device_id *id_table) -{ - struct i3c_device_info devinfo; - const struct i3c_device_id *id; - - i3c_device_get_info(i3cdev, &devinfo); - - /* -* The lower 32bits of the provisional ID is just filled with a random -* value, try to match using DCR info. -*/ - if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { - u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); - u16 part = I3C_PID_PART_ID(devinfo.pid); - u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); - - /* First try to match by manufacturer/part ID. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != - I3C_MATCH_MANUF_AND_PART) - continue; - - if (manuf != id->manuf_id || part != id->part_id) - continue; - - if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && - ext_info != id->extra_info) - continue; - - return id; - } - } - - /* Fallback to DCR match. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_DCR) && - id->dcr == devinfo.dcr) - return id; - } - - return NULL; -} - static int i3c_device_match(struct device *dev, struct device_driver *drv) { struct i3c_device *i3cdev; diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index 5ecb055..de102e4 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -188,6 +188,10 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv) struct device *i3cdev_to_dev(struct i3c_device *i3cdev); struct i3c_dev
RE: [PATCH v4 1/3] regmap: add i3c bus support
Hi Boris, From: Boris Brezillon Date: Fri, Jul 12, 2019 at 16:59:15 > On Fri, 12 Jul 2019 13:53:28 +0200 > Vitor Soares wrote: > > > Add basic support for i3c bus. > > This is a simple implementation that only give support > > for SDR Read and Write commands. > > > > This patch has been applied by Mark already. Please make sure to drop > already applied patches when submitting a new version. I mention that in the cover letter and I kept it for reference. Next time I will drop it. > > > Signed-off-by: Vitor Soares > > --- > > drivers/base/regmap/Kconfig | 6 +++- > > drivers/base/regmap/Makefile | 1 + > > drivers/base/regmap/regmap-i3c.c | 60 > > > > include/linux/regmap.h | 20 ++ > > 4 files changed, 86 insertions(+), 1 deletion(-) > > create mode 100644 drivers/base/regmap/regmap-i3c.c > > > > diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig > > index 6ad5ef4..c8bbf53 100644 > > --- a/drivers/base/regmap/Kconfig > > +++ b/drivers/base/regmap/Kconfig > > @@ -4,7 +4,7 @@ > > # subsystems should select the appropriate symbols. > > > > config REGMAP > > - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || > > REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) > > + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || > > REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_I3C) > > select IRQ_DOMAIN if REGMAP_IRQ > > bool > > > > @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE > > config REGMAP_SCCB > > tristate > > depends on I2C > > + > > +config REGMAP_I3C > > + tristate > > + depends on I3C > > diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile > > index f5b4e88..ff6c7d8 100644 > > --- a/drivers/base/regmap/Makefile > > +++ b/drivers/base/regmap/Makefile > > @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o > > obj-$(CONFIG_REGMAP_W1) += regmap-w1.o > > obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o > > obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o > > +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o > > diff --git a/drivers/base/regmap/regmap-i3c.c > > b/drivers/base/regmap/regmap-i3c.c > > new file mode 100644 > > index 000..1578fb5 > > --- /dev/null > > +++ b/drivers/base/regmap/regmap-i3c.c > > @@ -0,0 +1,60 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > + > > +#include > > +#include > > +#include > > +#include > > + > > +static int regmap_i3c_write(void *context, const void *data, size_t count) > > +{ > > + struct device *dev = context; > > + struct i3c_device *i3c = dev_to_i3cdev(dev); > > + struct i3c_priv_xfer xfers[] = { > > + { > > + .rnw = false, > > + .len = count, > > + .data.out = data, > > + }, > > + }; > > + > > + return i3c_device_do_priv_xfers(i3c, xfers, 1); > > +} > > + > > +static int regmap_i3c_read(void *context, > > + const void *reg, size_t reg_size, > > + void *val, size_t val_size) > > +{ > > + struct device *dev = context; > > + struct i3c_device *i3c = dev_to_i3cdev(dev); > > + struct i3c_priv_xfer xfers[2]; > > + > > + xfers[0].rnw = false; > > + xfers[0].len = reg_size; > > + xfers[0].data.out = reg; > > + > > + xfers[1].rnw = true; > > + xfers[1].len = val_size; > > + xfers[1].data.in = val; > > + > > + return i3c_device_do_priv_xfers(i3c, xfers, 2); > > +} > > + > > +static struct regmap_bus regmap_i3c = { > > + .write = regmap_i3c_write, > > + .read = regmap_i3c_read, > > +}; > > + > > +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, > > + const struct regmap_config *config, > > + struct lock_class_key *lock_key, > > + const char *lock_name) > > +{ > > + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, > > + lock_key, lock_name); > > +} > > +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); > > + > > +MODULE_AUTHOR("Vitor Soares "); > > +MODULE_DESCRIPTION("Regmap I3C Module"); > > +MODULE_LICE
RE: [PATCH v4 2/3] i3c: move i3c_device_match_id to device.c and export it
Hi Boris, From: Boris Brezillon Date: Fri, Jul 12, 2019 at 17:03:38 > On Fri, 12 Jul 2019 13:53:29 +0200 > Vitor Soares wrote: > > > The i3c device driver needs the i3c_device_id table. > > "Some I3C device drivers need to know which entry matches the > i3c_device object passed to the probe function" > > > Lets move to device.c and export it to be used. > > "Let's move i3c_device_match_id() to device.c and export it so it can be > used by drivers." > Fix in next drop. > > > > Signed-off-by: Vitor Soares > > --- > > Changes in v4: > > None > > > > Changes in v3: > > Remove i3c_get_device_id > > Move i3c_device_match_id from drivers/i3c/master.c to drivers/i3c/device.c > > Export i3c_device_match_id > > > > Changes in v2: > > move this function to drivers/i3c/device.c > > > > drivers/i3c/device.c | 46 > > ++ > > drivers/i3c/master.c | 45 > > - > > include/linux/i3c/device.h | 4 > > 3 files changed, 50 insertions(+), 45 deletions(-) > > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c > > index 69cc040..383df3b 100644 > > --- a/drivers/i3c/device.c > > +++ b/drivers/i3c/device.c > > @@ -200,6 +200,52 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) > > } > > EXPORT_SYMBOL_GPL(dev_to_i3cdev); > > > > You're missing a kerneldoc here. I will do that. Can you clarify why we need that? > > > +const struct i3c_device_id * > > +i3c_device_match_id(struct i3c_device *i3cdev, > > + const struct i3c_device_id *id_table) > > +{ > > + struct i3c_device_info devinfo; > > + const struct i3c_device_id *id; > > + > > + i3c_device_get_info(i3cdev, &devinfo); > > + > > + /* > > +* The lower 32bits of the provisional ID is just filled with a random > > +* value, try to match using DCR info. > > +*/ > > + if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { > > + u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); > > + u16 part = I3C_PID_PART_ID(devinfo.pid); > > + u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); > > + > > + /* First try to match by manufacturer/part ID. */ > > + for (id = id_table; id->match_flags != 0; id++) { > > + if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != > > + I3C_MATCH_MANUF_AND_PART) > > + continue; > > + > > + if (manuf != id->manuf_id || part != id->part_id) > > + continue; > > + > > + if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && > > + ext_info != id->extra_info) > > + continue; > > + > > + return id; > > + } > > + } > > + > > + /* Fallback to DCR match. */ > > + for (id = id_table; id->match_flags != 0; id++) { > > + if ((id->match_flags & I3C_MATCH_DCR) && > > + id->dcr == devinfo.dcr) > > + return id; > > + } > > + > > + return NULL; > > +} > > +EXPORT_SYMBOL_GPL(i3c_device_match_id); > > + > > /** > > * i3c_driver_register_with_owner() - register an I3C device driver > > * > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 5f4bd52..7667f84 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -270,51 +270,6 @@ static const struct device_type i3c_device_type = { > > .uevent = i3c_device_uevent, > > }; > > > > -static const struct i3c_device_id * > > -i3c_device_match_id(struct i3c_device *i3cdev, > > - const struct i3c_device_id *id_table) > > -{ > > - struct i3c_device_info devinfo; > > - const struct i3c_device_id *id; > > - > > - i3c_device_get_info(i3cdev, &devinfo); > > - > > - /* > > -* The lower 32bits of the provisional ID is just filled with a random > > -* value, try to match using DCR info. > > -*/ > > - if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { > > - u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); > > - u16 part = I3C_PID_PART_ID(devinfo.pid); > > - u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); > &g
RE: [PATCH v4 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
From: Boris Brezillon Date: Fri, Jul 12, 2019 at 17:14:29 > On Fri, 12 Jul 2019 13:53:30 +0200 > Vitor Soares wrote: > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in > > spi and i2c mode. > > > > The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to > > them. > > > > Signed-off-by: Vitor Soares > > Acked-by: Lorenzo Bianconi > > --- > > Changes in v4: > > Remove hw_id variable > > > > Changes in v3: > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name > > Use st_lsm6dsx_probe new form > > > > Changes in v2: > > Add support for LSM6DSR > > Set pm_ops to st_lsm6dsx_pm_ops > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 58 > > + > > 3 files changed, 66 insertions(+), 1 deletion(-) > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig > > b/drivers/iio/imu/st_lsm6dsx/Kconfig > > index 9e59297..6b5a73c 100644 > > --- a/drivers/iio/imu/st_lsm6dsx/Kconfig > > +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig > > @@ -1,11 +1,12 @@ > > > > config IIO_ST_LSM6DSX > > tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" > > - depends on (I2C || SPI) > > + depends on (I2C || SPI || I3C) > > select IIO_BUFFER > > select IIO_KFIFO_BUF > > select IIO_ST_LSM6DSX_I2C if (I2C) > > select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) > > + select IIO_ST_LSM6DSX_I3C if (I3C) > > help > > Say yes here to build support for STMicroelectronics LSM6DSx imu > > sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, > > @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI > > tristate > > depends on IIO_ST_LSM6DSX > > select REGMAP_SPI > > + > > +config IIO_ST_LSM6DSX_I3C > > + tristate > > + depends on IIO_ST_LSM6DSX > > + select REGMAP_I3C > > diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile > > b/drivers/iio/imu/st_lsm6dsx/Makefile > > index e5f733c..c676965 100644 > > --- a/drivers/iio/imu/st_lsm6dsx/Makefile > > +++ b/drivers/iio/imu/st_lsm6dsx/Makefile > > @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ > > obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o > > obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o > > obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o > > +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > new file mode 100644 > > index 000..2e89524 > > --- /dev/null > > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > @@ -0,0 +1,58 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > + * > > + * Author: Vitor Soares > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "st_lsm6dsx.h" > > + > > +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { > > + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), > > + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), > > I think you need an uintptr_t cast here: > > I3C_DEVICE(0x0104, 0x006C, (void *)(uintptr_t)ST_LSM6DSO_ID), > I3C_DEVICE(0x0104, 0x006B, (void *)(uintptr_t)ST_LSM6DSR_ID), > > otherwise gcc might complain that the integer and pointer do not have > the same size (on 64-bit architectures). I don't understand this part. Can you provide or point some background? > > > + { /* sentinel */ }, > > +}; > > +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); > > + > > +static const struct regmap_config st_lsm6dsx_i3c_regmap_config = { > > + .reg_bits = 8, > > + .val_bits = 8, > > +}; > > This can be moved ... > > > + > > +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) > > +{ > > ... here without the static and const qualifiers: I understand that can be move to here, but I don't understand the advantages. Can you explain? > > struct regmap_config regmap_config = { > .reg_bits = 8, > .val_bits = 8, > }; > >
RE: [PATCH v4 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
From: Boris Brezillon Date: Fri, Jul 12, 2019 at 17:43:23 > On Fri, 12 Jul 2019 16:28:02 + > Vitor Soares wrote: > > > From: Boris Brezillon > > Date: Fri, Jul 12, 2019 at 17:14:29 > > > > > On Fri, 12 Jul 2019 13:53:30 +0200 > > > Vitor Soares wrote: > > > > > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only > > > > in > > > > spi and i2c mode. > > > > > > > > The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to > > > > them. > > > > > > > > Signed-off-by: Vitor Soares > > > > Acked-by: Lorenzo Bianconi > > > > --- > > > > Changes in v4: > > > > Remove hw_id variable > > > > > > > > Changes in v3: > > > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name > > > > Use st_lsm6dsx_probe new form > > > > > > > > Changes in v2: > > > > Add support for LSM6DSR > > > > Set pm_ops to st_lsm6dsx_pm_ops > > > > > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 58 > > > > + > > > > 3 files changed, 66 insertions(+), 1 deletion(-) > > > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > b/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > index 9e59297..6b5a73c 100644 > > > > --- a/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig > > > > @@ -1,11 +1,12 @@ > > > > > > > > config IIO_ST_LSM6DSX > > > > tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" > > > > - depends on (I2C || SPI) > > > > + depends on (I2C || SPI || I3C) > > > > select IIO_BUFFER > > > > select IIO_KFIFO_BUF > > > > select IIO_ST_LSM6DSX_I2C if (I2C) > > > > select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) > > > > + select IIO_ST_LSM6DSX_I3C if (I3C) > > > > help > > > > Say yes here to build support for STMicroelectronics LSM6DSx > > > > imu > > > > sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, > > > > lsm6dsm, > > > > @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI > > > > tristate > > > > depends on IIO_ST_LSM6DSX > > > > select REGMAP_SPI > > > > + > > > > +config IIO_ST_LSM6DSX_I3C > > > > + tristate > > > > + depends on IIO_ST_LSM6DSX > > > > + select REGMAP_I3C > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile > > > > b/drivers/iio/imu/st_lsm6dsx/Makefile > > > > index e5f733c..c676965 100644 > > > > --- a/drivers/iio/imu/st_lsm6dsx/Makefile > > > > +++ b/drivers/iio/imu/st_lsm6dsx/Makefile > > > > @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ > > > > obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o > > > > obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o > > > > obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o > > > > +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > new file mode 100644 > > > > index 000..2e89524 > > > > --- /dev/null > > > > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > @@ -0,0 +1,58 @@ > > > > +// SPDX-License-Identifier: GPL-2.0 > > > > +/* > > > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > > > + * > > > > + * Author: Vitor Soares > > > > + */ > > > > + > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > +#include > > > > + > > > > +#include "st_lsm6dsx.h" > > > > + > > > > +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { >
RE: [PATCH v2 0/3] Add ST lsm6dso i3c support
Hi, Since the regmap-i3c.c was already applied in: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/regmap-i3c I wonder what is clean way to submit this patch set? And since the i3c-regmap was merge in From: Vitor Soares Date: Thu, Jun 06, 2019 at 16:12:01 > This patch series add i3c support for STM LSM6DSO and LSM6DSR sensors. > > It is also introduced i3c support on regmap api. Due the lack of > i3c devices HDR capables on the market the support for now is only for > i3c sdr mode by using i3c_device_do_priv_xfers() method. > > Changes in v2: > Change i3c_get_device_id() to drivers/i3c/device.c > Add support for LSM6DSR > > Vitor Soares (3): > regmap: add i3c bus support > i3c: Add i3c_get_device_id helper > iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR > > drivers/base/regmap/Kconfig | 6 ++- > drivers/base/regmap/Makefile| 1 + > drivers/base/regmap/regmap-i3c.c| 60 +++ > drivers/i3c/device.c| 8 +++ > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 ++- > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 76 > + > include/linux/i3c/device.h | 1 + > include/linux/regmap.h | 20 > 9 files changed, 179 insertions(+), 2 deletions(-) > create mode 100644 drivers/base/regmap/regmap-i3c.c > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > -- > 2.7.4 Best regards, Vitor Soares
[PATCH v3 3/3] i3c: dw: add limited bus mode support
This patch add limited bus mode support for DesignWare i3c master Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- Changes in v3: None Changes in v2: None drivers/i3c/master/dw-i3c-master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97..9612d93 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -599,6 +599,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: ret = dw_i2c_clk_cfg(master); if (ret) return ret; -- 2.7.4
[PATCH v3 2/3] i3c: add mixed limited bus mode
The i3c bus spec defines a bus configuration where i2c devices don't have a 50ns filter but support SCL running at SDR max rate (12.5MHz). This patch introduces the limited bus mode so that users can use a higher speed in presence of i2c devices index 1. Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- Changes in v3: None Changes in v2: Enhance commit message drivers/i3c/master.c | 5 + include/linux/i3c/master.h | 5 + 2 files changed, 10 insertions(+) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index f8e580e..025925c 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -470,6 +470,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) static const char * const i3c_bus_mode_strings[] = { [I3C_BUS_MODE_PURE] = "pure", [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", + [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", }; @@ -585,6 +586,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; break; case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: if (!i3cbus->scl_rate.i3c) i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; if (!i3cbus->scl_rate.i2c) @@ -2490,6 +2492,9 @@ int i3c_master_register(struct i3c_master_controller *master, mode = I3C_BUS_MODE_MIXED_FAST; break; case I3C_LVR_I2C_INDEX(1): + if (mode < I3C_BUS_MODE_MIXED_LIMITED) + mode = I3C_BUS_MODE_MIXED_LIMITED; + break; case I3C_LVR_I2C_INDEX(2): if (mode < I3C_BUS_MODE_MIXED_SLOW) mode = I3C_BUS_MODE_MIXED_SLOW; diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index f13fd8b..89ea461 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -250,12 +250,17 @@ struct i3c_device { * the bus. The only impact in this mode is that the * high SCL pulse has to stay below 50ns to trick I2C * devices when transmitting I3C frames + * @I3C_BUS_MODE_MIXED_LIMITED: I2C devices without 50ns spike filter are + * present on the bus. However they allows + * compliance up to the maximum SDR SCL clock + * frequency. * @I3C_BUS_MODE_MIXED_SLOW: I2C devices without 50ns spike filter are present * on the bus */ enum i3c_bus_mode { I3C_BUS_MODE_PURE, I3C_BUS_MODE_MIXED_FAST, + I3C_BUS_MODE_MIXED_LIMITED, I3C_BUS_MODE_MIXED_SLOW, }; -- 2.7.4
[PATCH v3 1/3] i3c: fix i2c and i3c scl rate by bus mode
Currently the I3C framework limits SCL frequency to FM speed when dealing with a mixed slow bus, even if all I2C devices are FM+ capable. The core was also not accounting for I3C speed limitations when operating in mixed slow mode and was erroneously using FM+ speed as the max I2C speed when operating in mixed fast mode. Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: Cc: --- Changes in v3: Change dev_warn() to dev_dbg() Changes in v2: Enhance commit message Add dev_warn() in case user-defined i2c rate doesn't match LVR constraint Add dev_warn() in case user-defined i3c rate lower than i2c rate drivers/i3c/master.c | 61 +--- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..f8e580e 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) up_read(&bus->lock); } +static struct i3c_master_controller * +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) +{ + return container_of(i3cbus, struct i3c_master_controller, bus); +} + static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) { return container_of(dev, struct i3c_master_controller, dev); @@ -565,20 +571,48 @@ static const struct device_type i3c_masterdev_type = { .groups = i3c_masterdev_groups, }; -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, +unsigned long max_i2c_scl_rate) { - i3cbus->mode = mode; - if (!i3cbus->scl_rate.i3c) - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); - if (!i3cbus->scl_rate.i2c) { - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - else - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; + i3cbus->mode = mode; + + switch (i3cbus->mode) { + case I3C_BUS_MODE_PURE: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + break; + case I3C_BUS_MODE_MIXED_FAST: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + break; + case I3C_BUS_MODE_MIXED_SLOW: + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + if (!i3cbus->scl_rate.i3c || + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; + break; + default: + return -EINVAL; } + if (i3cbus->scl_rate.i3c < i3cbus->scl_rate.i2c) + dev_dbg(&master->dev, + "i3c-scl-hz=%ld lower than i2c-scl-hz=%ld\n", + i3cbus->scl_rate.i3c, i3cbus->scl_rate.i2c); + + if (i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_SCL_RATE && + i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_PLUS_SCL_RATE && + i3cbus->mode != I3C_BUS_MODE_PURE) + dev_dbg(&master->dev, + "i2c-scl-hz=%ld not defined according MIPI I3C spec\n", + i3cbus->scl_rate.i2c); + /* * I3C/I2C frequency may have been overridden, check that user-provided * values are not exceeding max possible frequency. @@ -1966,9 +2000,6 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master, /* LVR is encoded in reg[2]. */ boardinfo->lvr = reg[2]; - if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) - master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - list_add_tail(&boardinfo->node, &master->boardinfo.i2c); of_node_get(node); @@ -2417,6 +2448,7 @@ int i3c_master_register(struct i3c_master_controller *master, const struct i3c_master_controller_ops *ops, bool secondary) { + unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; struct i3c_bus *i3cbus = i3c_master_get_bus(master); enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; struct i2c_dev_boardinfo *i2cbi; @@ -2466,9 +2498,12 @@ int i3c_master_register(struct i3c_master_controller *master, ret = -EINVAL; goto err_put_dev
[PATCH v2 1/3] i3c: fix i2c and i3c scl rate by bus mode
Currently the I3C framework limits SCL frequency to FM speed when dealing with a mixed slow bus, even if all I2C devices are FM+ capable. The core was also not accounting for I3C speed limitations when operating in mixed slow mode and was erroneously using FM+ speed as the max I2C speed when operating in mixed fast mode. Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: Cc: --- Changes in v2: Enhance commit message Add dev_warn() in case user-defined i2c rate doesn't match LVR constraint Add dev_warn() in case user-defined i3c rate lower than i2c rate. drivers/i3c/master.c | 61 +--- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..8cd5824 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) up_read(&bus->lock); } +static struct i3c_master_controller * +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) +{ + return container_of(i3cbus, struct i3c_master_controller, bus); +} + static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) { return container_of(dev, struct i3c_master_controller, dev); @@ -565,20 +571,48 @@ static const struct device_type i3c_masterdev_type = { .groups = i3c_masterdev_groups, }; -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, +unsigned long max_i2c_scl_rate) { - i3cbus->mode = mode; - if (!i3cbus->scl_rate.i3c) - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); - if (!i3cbus->scl_rate.i2c) { - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - else - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; + i3cbus->mode = mode; + + switch (i3cbus->mode) { + case I3C_BUS_MODE_PURE: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + break; + case I3C_BUS_MODE_MIXED_FAST: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + break; + case I3C_BUS_MODE_MIXED_SLOW: + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + if (!i3cbus->scl_rate.i3c || + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; + break; + default: + return -EINVAL; } + if (i3cbus->scl_rate.i3c < i3cbus->scl_rate.i2c) + dev_warn(&master->dev, +"i3c-scl-hz=%ld lower than i2c-scl-hz=%ld\n", +i3cbus->scl_rate.i3c, i3cbus->scl_rate.i2c); + + if (i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_SCL_RATE && + i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_PLUS_SCL_RATE && + i3cbus->mode != I3C_BUS_MODE_PURE) + dev_warn(&master->dev, +"i2c-scl-hz=%ld not defined according MIPI I3C spec\n" +, i3cbus->scl_rate.i2c); + /* * I3C/I2C frequency may have been overridden, check that user-provided * values are not exceeding max possible frequency. @@ -1966,9 +2000,6 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master, /* LVR is encoded in reg[2]. */ boardinfo->lvr = reg[2]; - if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) - master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - list_add_tail(&boardinfo->node, &master->boardinfo.i2c); of_node_get(node); @@ -2417,6 +2448,7 @@ int i3c_master_register(struct i3c_master_controller *master, const struct i3c_master_controller_ops *ops, bool secondary) { + unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; struct i3c_bus *i3cbus = i3c_master_get_bus(master); enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; struct i2c_dev_boardinfo *i2cbi; @@ -2466,9 +2498,12 @@ int i3c_master_register(struct i3c_master_controller *master, ret = -EINVAL; goto err_put_dev; } + + if (i2cb
[PATCH v2 3/3] i3c: dw: add limited bus mode support
This patch add limited bus mode support for DesignWare i3c master Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- Changes in v2: None drivers/i3c/master/dw-i3c-master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97..9612d93 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -599,6 +599,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: ret = dw_i2c_clk_cfg(master); if (ret) return ret; -- 2.7.4
[PATCH v2 2/3] i3c: add mixed limited bus mode
The i3c bus spec defines a bus configuration where i2c devices don't have a 50ns filter but support SCL running at SDR max rate (12.5MHz). This patch introduces the limited bus mode so that users can use a higher speed in presence of i2c devices index 1. Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- Changes in v2: Enhance commit message drivers/i3c/master.c | 5 + include/linux/i3c/master.h | 5 + 2 files changed, 10 insertions(+) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 8cd5824..f446c4d 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -470,6 +470,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) static const char * const i3c_bus_mode_strings[] = { [I3C_BUS_MODE_PURE] = "pure", [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", + [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", }; @@ -585,6 +586,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; break; case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: if (!i3cbus->scl_rate.i3c) i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; if (!i3cbus->scl_rate.i2c) @@ -2490,6 +2492,9 @@ int i3c_master_register(struct i3c_master_controller *master, mode = I3C_BUS_MODE_MIXED_FAST; break; case I3C_LVR_I2C_INDEX(1): + if (mode < I3C_BUS_MODE_MIXED_LIMITED) + mode = I3C_BUS_MODE_MIXED_LIMITED; + break; case I3C_LVR_I2C_INDEX(2): if (mode < I3C_BUS_MODE_MIXED_SLOW) mode = I3C_BUS_MODE_MIXED_SLOW; diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index f13fd8b..89ea461 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -250,12 +250,17 @@ struct i3c_device { * the bus. The only impact in this mode is that the * high SCL pulse has to stay below 50ns to trick I2C * devices when transmitting I3C frames + * @I3C_BUS_MODE_MIXED_LIMITED: I2C devices without 50ns spike filter are + * present on the bus. However they allows + * compliance up to the maximum SDR SCL clock + * frequency. * @I3C_BUS_MODE_MIXED_SLOW: I2C devices without 50ns spike filter are present * on the bus */ enum i3c_bus_mode { I3C_BUS_MODE_PURE, I3C_BUS_MODE_MIXED_FAST, + I3C_BUS_MODE_MIXED_LIMITED, I3C_BUS_MODE_MIXED_SLOW, }; -- 2.7.4
[PATCH v2 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in spi and i2c mode. The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to them. Signed-off-by: Vitor Soares --- Changes in v2: Add support for LSM6DSR Set pm_ops to st_lsm6dsx_pm_ops drivers/iio/imu/st_lsm6dsx/Kconfig | 8 ++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 76 + 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 002a423..8115936 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -2,11 +2,12 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, @@ -24,3 +25,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index 28cc673..57cbcd6 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -5,3 +5,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000..70b70d1 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +#define NAME_SIZE 32 + +struct st_lsm6dsx_i3c_data { + const char name[NAME_SIZE]; + enum st_lsm6dsx_hw_id id; +}; + +enum st_lsm6dsx_i3c_data_id { + ST_LSM6DSO_I3C_DATA_ID, + ST_LSM6DSR_I3C_DATA_ID, +}; + +static const struct st_lsm6dsx_i3c_data hw_data[] = { + { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, + { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, +}; + +static const struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + const struct i3c_device_id *id = i3c_get_device_id(i3cdev); + const struct st_lsm6dsx_i3c_data *hw_data = id->data; + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, hw_data->id, + hw_data->name, regmap); +} + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, &hw_data[ST_LSM6DSO_I3C_DATA_ID]), + I3C_DEVICE(0x0104, 0x006B, &hw_data[ST_LSM6DSR_I3C_DATA_ID]), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4
[PATCH v2 1/3] regmap: add i3c bus support
Add basic support for i3c bus. This is a simple implementation that only give support for SDR Read and Write commands. Signed-off-by: Vitor Soares --- Changes in v2: None drivers/base/regmap/Kconfig | 6 +++- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-i3c.c | 60 include/linux/regmap.h | 20 ++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-i3c.c diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 6ad5ef4..c8bbf53 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,7 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_I3C) select IRQ_DOMAIN if REGMAP_IRQ bool @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE config REGMAP_SCCB tristate depends on I2C + +config REGMAP_I3C + tristate + depends on I3C diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index f5b4e88..ff6c7d8 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_W1) += regmap-w1.o obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o diff --git a/drivers/base/regmap/regmap-i3c.c b/drivers/base/regmap/regmap-i3c.c new file mode 100644 index 000..1578fb5 --- /dev/null +++ b/drivers/base/regmap/regmap-i3c.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + +#include +#include +#include +#include + +static int regmap_i3c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = count, + .data.out = data, + }, + }; + + return i3c_device_do_priv_xfers(i3c, xfers, 1); +} + +static int regmap_i3c_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[2]; + + xfers[0].rnw = false; + xfers[0].len = reg_size; + xfers[0].data.out = reg; + + xfers[1].rnw = true; + xfers[1].len = val_size; + xfers[1].data.in = val; + + return i3c_device_do_priv_xfers(i3c, xfers, 2); +} + +static struct regmap_bus regmap_i3c = { + .write = regmap_i3c_write, + .read = regmap_i3c_read, +}; + +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("Regmap I3C Module"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index daeec7d..f65984d 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -25,6 +25,7 @@ struct module; struct clk; struct device; struct i2c_client; +struct i3c_device; struct irq_domain; struct slim_device; struct spi_device; @@ -624,6 +625,10 @@ struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, +const struct regmap_config *config, +struct lock_class_key *lock_key, +const char *lock_name); /* * Wrapper for regmap_init macros to include a unique lockdep key and name * for each call. No-op if CONFIG_LOCKDEP is not set. @@ -982,6 +987,21 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); #define devm_regmap_init_slimbus(slimbus, config) \ __regmap_lockdep_wrapper(__devm_regmap_init_slimbus, #config, \ slimbus, config) + +/** + * devm_regmap_init_i3c() -
[PATCH v2 0/3] Add ST lsm6dso i3c support
This patch series add i3c support for STM LSM6DSO and LSM6DSR sensors. It is also introduced i3c support on regmap api. Due the lack of i3c devices HDR capables on the market the support for now is only for i3c sdr mode by using i3c_device_do_priv_xfers() method. Changes in v2: Change i3c_get_device_id() to drivers/i3c/device.c Add support for LSM6DSR Vitor Soares (3): regmap: add i3c bus support i3c: Add i3c_get_device_id helper iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR drivers/base/regmap/Kconfig | 6 ++- drivers/base/regmap/Makefile| 1 + drivers/base/regmap/regmap-i3c.c| 60 +++ drivers/i3c/device.c| 8 +++ drivers/iio/imu/st_lsm6dsx/Kconfig | 8 ++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 76 + include/linux/i3c/device.h | 1 + include/linux/regmap.h | 20 9 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 drivers/base/regmap/regmap-i3c.c create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c -- 2.7.4
[PATCH v2 2/3] i3c: add i3c_get_device_id helper
This helper return the i3c_device_id structure in order the client have access to the driver data. Signed-off-by: Vitor Soares --- Changes in v2: move this function to drivers/i3c/device.c drivers/i3c/device.c | 8 include/linux/i3c/device.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 69cc040..a6d0796 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -200,6 +200,14 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) } EXPORT_SYMBOL_GPL(dev_to_i3cdev); +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev) +{ + const struct i3c_driver *i3cdrv = drv_to_i3cdrv(i3cdev->dev.driver); + + return i3cdrv->id_table; +} +EXPORT_SYMBOL_GPL(i3c_get_device_id); + /** * i3c_driver_register_with_owner() - register an I3C device driver * diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index 5ecb055..e0415e1 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -187,6 +187,7 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv) struct device *i3cdev_to_dev(struct i3c_device *i3cdev); struct i3c_device *dev_to_i3cdev(struct device *dev); +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev); static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev, void *data) -- 2.7.4
RE: [PATCH v2 0/3] Add ST lsm6dso i3c support
Hi Wolfram, I think I2C ecosystem is also part interested in I3C due the compatibility and maybe they can provide some feedback. If you think differently, sorry I will remove I2C list next time. Regards, Vitor Soares From: Wolfram Sang Date: Thu, Jun 06, 2019 at 17:25:23 > On Thu, Jun 06, 2019 at 05:12:01PM +0200, Vitor Soares wrote: > > This patch series add i3c support for STM LSM6DSO and LSM6DSR sensors. > > Why is the I2C list on CC? Is there something relevant I missed?
RE: [PATCH v2 2/3] i3c: add i3c_get_device_id helper
Hi Boris, From: Boris Brezillon Date: Thu, Jun 06, 2019 at 16:17:55 > On Thu, 6 Jun 2019 17:12:03 +0200 > Vitor Soares wrote: > > > This helper return the i3c_device_id structure in order the client > > have access to the driver data. > > > > Signed-off-by: Vitor Soares > > --- > > Changes in v2: > > move this function to drivers/i3c/device.c > > > > drivers/i3c/device.c | 8 > > include/linux/i3c/device.h | 1 + > > 2 files changed, 9 insertions(+) > > > > diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c > > index 69cc040..a6d0796 100644 > > --- a/drivers/i3c/device.c > > +++ b/drivers/i3c/device.c > > @@ -200,6 +200,14 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) > > } > > EXPORT_SYMBOL_GPL(dev_to_i3cdev); > > > > +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev) > > +{ > > + const struct i3c_driver *i3cdrv = drv_to_i3cdrv(i3cdev->dev.driver); > > + > > + return i3cdrv->id_table; > > +} > > +EXPORT_SYMBOL_GPL(i3c_get_device_id); > > That's not what I asked. I told you to expose i3c_device_match_id() > which already exists and is in master.c. What you really want is to get > the device_id entry that matches your device, not the first entry in > the table... > I didn't see it has the full table. I will change it. > > + > > /** > > * i3c_driver_register_with_owner() - register an I3C device driver > > * > > diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h > > index 5ecb055..e0415e1 100644 > > --- a/include/linux/i3c/device.h > > +++ b/include/linux/i3c/device.h > > @@ -187,6 +187,7 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct > > device_driver *drv) > > > > struct device *i3cdev_to_dev(struct i3c_device *i3cdev); > > struct i3c_device *dev_to_i3cdev(struct device *dev); > > +const struct i3c_device_id *i3c_get_device_id(struct i3c_device *i3cdev); > > > > static inline void i3cdev_set_drvdata(struct i3c_device *i3cdev, > > void *data)
RE: [PATCH v2 1/3] i3c: fix i2c and i3c scl rate by bus mode
From: Boris Brezillon Date: Thu, Jun 06, 2019 at 15:18:44 > On Thu, 6 Jun 2019 16:00:01 +0200 > Vitor Soares wrote: > > > Currently the I3C framework limits SCL frequency to FM speed when > > dealing with a mixed slow bus, even if all I2C devices are FM+ capable. > > > > The core was also not accounting for I3C speed limitations when > > operating in mixed slow mode and was erroneously using FM+ speed as the > > max I2C speed when operating in mixed fast mode. > > > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > Signed-off-by: Vitor Soares > > Cc: Boris Brezillon > > Cc: > > Cc: > > --- > > Changes in v2: > > Enhance commit message > > Add dev_warn() in case user-defined i2c rate doesn't match LVR constraint > > Add dev_warn() in case user-defined i3c rate lower than i2c rate. > > > > drivers/i3c/master.c | 61 > > +--- > > 1 file changed, 48 insertions(+), 13 deletions(-) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 5f4bd52..8cd5824 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) > > up_read(&bus->lock); > > } > > > > +static struct i3c_master_controller * > > +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) > > +{ > > + return container_of(i3cbus, struct i3c_master_controller, bus); > > +} > > + > > static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) > > { > > return container_of(dev, struct i3c_master_controller, dev); > > @@ -565,20 +571,48 @@ static const struct device_type i3c_masterdev_type = { > > .groups = i3c_masterdev_groups, > > }; > > > > -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) > > +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, > > +unsigned long max_i2c_scl_rate) > > { > > - i3cbus->mode = mode; > > > > - if (!i3cbus->scl_rate.i3c) > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); > > > > - if (!i3cbus->scl_rate.i2c) { > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > - else > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > + i3cbus->mode = mode; > > + > > + switch (i3cbus->mode) { > > + case I3C_BUS_MODE_PURE: > > + if (!i3cbus->scl_rate.i3c) > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + break; > > + case I3C_BUS_MODE_MIXED_FAST: > > + if (!i3cbus->scl_rate.i3c) > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + if (!i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > + break; > > + case I3C_BUS_MODE_MIXED_SLOW: > > + if (!i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > + if (!i3cbus->scl_rate.i3c || > > + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > + break; > > + default: > > + return -EINVAL; > > } > > > > + if (i3cbus->scl_rate.i3c < i3cbus->scl_rate.i2c) > > + dev_warn(&master->dev, > > +"i3c-scl-hz=%ld lower than i2c-scl-hz=%ld\n", > > +i3cbus->scl_rate.i3c, i3cbus->scl_rate.i2c); > > + > > + if (i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_SCL_RATE && > > + i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_PLUS_SCL_RATE && > > + i3cbus->mode != I3C_BUS_MODE_PURE) > > If you are so strict, there's clearly no point exposing an i2c-scl-hz > property. I'm still not convinced having an i2c rate that's slower than > what the I2C/I3C spec defines as the *typical* rate is a bad thing, I'm not been strictive, I just inform the user about that case. > just > like I'm not convinced having an I3C rate that's slower than the I2C > one is a problem (it's definitely a weird situation, but there's nothing > preventing that
RE: [PATCH v2 1/3] i3c: fix i2c and i3c scl rate by bus mode
From: Boris Brezillon Date: Thu, Jun 06, 2019 at 18:35:40 > On Thu, 6 Jun 2019 17:16:55 + > Vitor Soares wrote: > > > From: Boris Brezillon > > Date: Thu, Jun 06, 2019 at 15:18:44 > > > > > On Thu, 6 Jun 2019 16:00:01 +0200 > > > Vitor Soares wrote: > > > > > > > Currently the I3C framework limits SCL frequency to FM speed when > > > > dealing with a mixed slow bus, even if all I2C devices are FM+ capable. > > > > > > > > The core was also not accounting for I3C speed limitations when > > > > operating in mixed slow mode and was erroneously using FM+ speed as the > > > > max I2C speed when operating in mixed fast mode. > > > > > > > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > > > Signed-off-by: Vitor Soares > > > > Cc: Boris Brezillon > > > > Cc: > > > > Cc: > > > > --- > > > > Changes in v2: > > > > Enhance commit message > > > > Add dev_warn() in case user-defined i2c rate doesn't match LVR > > > > constraint > > > > Add dev_warn() in case user-defined i3c rate lower than i2c rate. > > > > > > > > drivers/i3c/master.c | 61 > > > > +--- > > > > 1 file changed, 48 insertions(+), 13 deletions(-) > > > > > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > > > index 5f4bd52..8cd5824 100644 > > > > --- a/drivers/i3c/master.c > > > > +++ b/drivers/i3c/master.c > > > > @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) > > > > up_read(&bus->lock); > > > > } > > > > > > > > +static struct i3c_master_controller * > > > > +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) > > > > +{ > > > > + return container_of(i3cbus, struct i3c_master_controller, bus); > > > > +} > > > > + > > > > static struct i3c_master_controller *dev_to_i3cmaster(struct device > > > > *dev) > > > > { > > > > return container_of(dev, struct i3c_master_controller, dev); > > > > @@ -565,20 +571,48 @@ static const struct device_type > > > > i3c_masterdev_type = { > > > > .groups = i3c_masterdev_groups, > > > > }; > > > > > > > > -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) > > > > +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, > > > > +unsigned long max_i2c_scl_rate) > > > > { > > > > - i3cbus->mode = mode; > > > > > > > > - if (!i3cbus->scl_rate.i3c) > > > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + struct i3c_master_controller *master = > > > > i3c_bus_to_i3c_master(i3cbus); > > > > > > > > - if (!i3cbus->scl_rate.i2c) { > > > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > > > - else > > > > - i3cbus->scl_rate.i2c = > > > > I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > > > + i3cbus->mode = mode; > > > > + > > > > + switch (i3cbus->mode) { > > > > + case I3C_BUS_MODE_PURE: > > > > + if (!i3cbus->scl_rate.i3c) > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + break; > > > > + case I3C_BUS_MODE_MIXED_FAST: > > > > + if (!i3cbus->scl_rate.i3c) > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + if (!i3cbus->scl_rate.i2c) > > > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > > > + break; > > > > + case I3C_BUS_MODE_MIXED_SLOW: > > > > + if (!i3cbus->scl_rate.i2c) > > > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > > > + if (!i3cbus->scl_rate.i3c || > > > > + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) > > > > + i3cbus->scl_rat
[PATCH v5 2/2] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in spi and i2c mode. The LSM6DSO and LSM6DSR are also i3c capable so let's give i3c support to them. Signed-off-by: Vitor Soares Acked-by: Lorenzo Bianconi --- Changes in v5: Move regmap_config declaration inside st_lsm6dsx_i3c_probe() Fix warning [-Wint-to-void-pointer-cast] when compiling in 64-bit arch Changes in v4: Remove hw_id variable Changes in v3: Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name Use st_lsm6dsx_probe new form Changes in v2: Add support for LSM6DSR Set pm_ops to st_lsm6dsx_pm_ops drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 57 + 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 9e59297..6b5a73c 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -1,11 +1,12 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index e5f733c..c676965 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000..57e6331 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, + st_lsm6dsx_i3c_ids); + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap); +} + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4
[PATCH v5 0/2] Add ST lsm6dso i3c support
This patch-series add i3c support for STM LSM6DSO and LSM6DSR sensors. It is also introduced i3c support on regmap API. Due to the lack of i3c devices with HDR feature on the market the support, for now, is only for i3c SDR mode by using i3c_device_do_priv_xfers() method. The i3c regmap API is already available in the Git repository at: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/regmap-i3c Change in v5: Remove regmap-i3c patch, already applied in regmap tree Fix warning when compiling in 64-bit architecture Change in v4: remover hw_id variable from st_lsm6dsx_i3c_probe() Change in v3: Update st_lsm6dsx_probe() call Remove i3c_get_device_id() and use i3c_device_match_id() Changes in v2: Change i3c_get_device_id() to drivers/i3c/device.c Add support for LSM6DSR Vitor Soares (2): i3c: add i3c_get_device_id helper iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR drivers/i3c/device.c| 53 +++ drivers/i3c/master.c| 45 --- drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 57 + include/linux/i3c/device.h | 4 ++ 6 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c -- 2.7.4
[PATCH v5 1/2] i3c: move i3c_device_match_id to device.c and export it
Some I3C device drivers need to know which entry matches the i3c_device object passed to the probe function Let's move i3c_device_match_id() to device.c and export it so it can be used by drivers. Signed-off-by: Vitor Soares --- Changes in v5: Add kerneldoc Improve commit message Changes in v4: None Changes in v3: Remove i3c_get_device_id Move i3c_device_match_id from drivers/i3c/master.c to drivers/i3c/device.c Export i3c_device_match_id Changes in v2: move this function to drivers/i3c/device.c drivers/i3c/device.c | 53 ++ drivers/i3c/master.c | 45 --- include/linux/i3c/device.h | 4 3 files changed, 57 insertions(+), 45 deletions(-) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 69cc040..5349059 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -201,6 +201,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) EXPORT_SYMBOL_GPL(dev_to_i3cdev); /** + * i3c_device_match_id() - Returns the I3C device match id in @i3cdev + * @i3cdev: I3C device + * @id_table: I3C device match table + * + * Return: a pointer to I3C device id object. + */ +const struct i3c_device_id * +i3c_device_match_id(struct i3c_device *i3cdev, + const struct i3c_device_id *id_table) +{ + struct i3c_device_info devinfo; + const struct i3c_device_id *id; + + i3c_device_get_info(i3cdev, &devinfo); + + /* +* The lower 32bits of the provisional ID is just filled with a random +* value, try to match using DCR info. +*/ + if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { + u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); + u16 part = I3C_PID_PART_ID(devinfo.pid); + u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); + + /* First try to match by manufacturer/part ID. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != + I3C_MATCH_MANUF_AND_PART) + continue; + + if (manuf != id->manuf_id || part != id->part_id) + continue; + + if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && + ext_info != id->extra_info) + continue; + + return id; + } + } + + /* Fallback to DCR match. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_DCR) && + id->dcr == devinfo.dcr) + return id; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(i3c_device_match_id); + +/** * i3c_driver_register_with_owner() - register an I3C device driver * * @drv: driver to register diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..7667f84 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -270,51 +270,6 @@ static const struct device_type i3c_device_type = { .uevent = i3c_device_uevent, }; -static const struct i3c_device_id * -i3c_device_match_id(struct i3c_device *i3cdev, - const struct i3c_device_id *id_table) -{ - struct i3c_device_info devinfo; - const struct i3c_device_id *id; - - i3c_device_get_info(i3cdev, &devinfo); - - /* -* The lower 32bits of the provisional ID is just filled with a random -* value, try to match using DCR info. -*/ - if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { - u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); - u16 part = I3C_PID_PART_ID(devinfo.pid); - u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); - - /* First try to match by manufacturer/part ID. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != - I3C_MATCH_MANUF_AND_PART) - continue; - - if (manuf != id->manuf_id || part != id->part_id) - continue; - - if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && - ext_info != id->extra_info) - continue; - - return id; - } - } - - /* Fallback to DCR match. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_DCR) && - id->dcr == devinfo.dcr) - return id; - } - - return NULL; -} - static int i3c_device_match(struct device *dev, struct device_driver *dr
[PATCH v6 0/2] Add ST lsm6dso i3c support
This patch-series add i3c support for STM LSM6DSO and LSM6DSR sensors. It is also introduced i3c support on regmap API. Due to the lack of i3c devices with HDR feature on the market the support, for now, is only for i3c SDR mode by using i3c_device_do_priv_xfers() method. The i3c regmap API is already available in the Git repository at: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/regmap-i3c Change in v6: Improve kerneldoc Change in v5: Remove regmap-i3c patch, already applied in regmap tree Fix warning when compiling in 64-bit architecture Change in v4: remover hw_id variable from st_lsm6dsx_i3c_probe() Change in v3: Update st_lsm6dsx_probe() call Remove i3c_get_device_id() and use i3c_device_match_id() Changes in v2: Change i3c_get_device_id() to drivers/i3c/device.c Add support for LSM6DSR Vitor Soares (2): i3c: add i3c_get_device_id helper iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR drivers/i3c/device.c| 53 +++ drivers/i3c/master.c| 45 --- drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 57 + include/linux/i3c/device.h | 4 ++ 6 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c -- 2.7.4
[PATCH v6 2/2] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in spi and i2c mode. The LSM6DSO and LSM6DSR are also i3c capable so let's give i3c support to them. Signed-off-by: Vitor Soares Acked-by: Lorenzo Bianconi Reviewed-by: Boris Brezillon --- Changes in v6: none Changes in v5: Move regmap_config declaration inside st_lsm6dsx_i3c_probe() Fix warning [-Wint-to-void-pointer-cast] when compiling in 64-bit arch Changes in v4: Remove hw_id variable Changes in v3: Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name Use st_lsm6dsx_probe new form Changes in v2: Add support for LSM6DSR Set pm_ops to st_lsm6dsx_pm_ops drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 57 + 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 9e59297..6b5a73c 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -1,11 +1,12 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index e5f733c..c676965 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000..57e6331 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, + st_lsm6dsx_i3c_ids); + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap); +} + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4
[PATCH v6 1/2] i3c: move i3c_device_match_id to device.c and export it
Some I3C device drivers need to know which entry matches the i3c_device object passed to the probe function Let's move i3c_device_match_id() to device.c and export it so it can be used by drivers. Signed-off-by: Vitor Soares --- Changes in v6: Improve kerneldoc Changes in v5: Add kerneldoc Improve commit message Changes in v4: None Changes in v3: Remove i3c_get_device_id Move i3c_device_match_id from drivers/i3c/master.c to drivers/i3c/device.c Export i3c_device_match_id Changes in v2: move this function to drivers/i3c/device.c drivers/i3c/device.c | 53 ++ drivers/i3c/master.c | 45 --- include/linux/i3c/device.h | 4 3 files changed, 57 insertions(+), 45 deletions(-) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 69cc040..c15f5ca 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -201,6 +201,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) EXPORT_SYMBOL_GPL(dev_to_i3cdev); /** + * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev + * @i3cdev: I3C device + * @id_table: I3C device match table + * + * Return: a pointer to an i3c_device_id object or NULL if there's no match. + */ +const struct i3c_device_id * +i3c_device_match_id(struct i3c_device *i3cdev, + const struct i3c_device_id *id_table) +{ + struct i3c_device_info devinfo; + const struct i3c_device_id *id; + + i3c_device_get_info(i3cdev, &devinfo); + + /* +* The lower 32bits of the provisional ID is just filled with a random +* value, try to match using DCR info. +*/ + if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { + u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); + u16 part = I3C_PID_PART_ID(devinfo.pid); + u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); + + /* First try to match by manufacturer/part ID. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != + I3C_MATCH_MANUF_AND_PART) + continue; + + if (manuf != id->manuf_id || part != id->part_id) + continue; + + if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && + ext_info != id->extra_info) + continue; + + return id; + } + } + + /* Fallback to DCR match. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_DCR) && + id->dcr == devinfo.dcr) + return id; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(i3c_device_match_id); + +/** * i3c_driver_register_with_owner() - register an I3C device driver * * @drv: driver to register diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..7667f84 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -270,51 +270,6 @@ static const struct device_type i3c_device_type = { .uevent = i3c_device_uevent, }; -static const struct i3c_device_id * -i3c_device_match_id(struct i3c_device *i3cdev, - const struct i3c_device_id *id_table) -{ - struct i3c_device_info devinfo; - const struct i3c_device_id *id; - - i3c_device_get_info(i3cdev, &devinfo); - - /* -* The lower 32bits of the provisional ID is just filled with a random -* value, try to match using DCR info. -*/ - if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { - u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); - u16 part = I3C_PID_PART_ID(devinfo.pid); - u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); - - /* First try to match by manufacturer/part ID. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != - I3C_MATCH_MANUF_AND_PART) - continue; - - if (manuf != id->manuf_id || part != id->part_id) - continue; - - if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && - ext_info != id->extra_info) - continue; - - return id; - } - } - - /* Fallback to DCR match. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_DCR) && - id->dcr == devinfo.dcr) - return id; - } - - return NULL; -}
RE: [PATCH v5 2/2] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
From: Boris Brezillon Date: Fri, Jul 19, 2019 at 13:51:10 > On Fri, 19 Jul 2019 13:19:05 +0200 > Vitor Soares wrote: > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in > > spi and i2c mode. > > > > The LSM6DSO and LSM6DSR are also i3c capable so let's give i3c support to > > them. > > > > Signed-off-by: Vitor Soares > > Acked-by: Lorenzo Bianconi > > Reviewed-by: Boris Brezillon Thanks 😊 > > > --- > > Changes in v5: > > Move regmap_config declaration inside st_lsm6dsx_i3c_probe() > > Fix warning [-Wint-to-void-pointer-cast] when compiling in 64-bit arch > > > > Changes in v4: > > Remove hw_id variable > > > > Changes in v3: > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name > > Use st_lsm6dsx_probe new form > > > > Changes in v2: > > Add support for LSM6DSR > > Set pm_ops to st_lsm6dsx_pm_ops > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 57 > > + > > 3 files changed, 65 insertions(+), 1 deletion(-) > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig > > b/drivers/iio/imu/st_lsm6dsx/Kconfig > > index 9e59297..6b5a73c 100644 > > --- a/drivers/iio/imu/st_lsm6dsx/Kconfig > > +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig > > @@ -1,11 +1,12 @@ > > > > config IIO_ST_LSM6DSX > > tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" > > - depends on (I2C || SPI) > > + depends on (I2C || SPI || I3C) > > select IIO_BUFFER > > select IIO_KFIFO_BUF > > select IIO_ST_LSM6DSX_I2C if (I2C) > > select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) > > + select IIO_ST_LSM6DSX_I3C if (I3C) > > help > > Say yes here to build support for STMicroelectronics LSM6DSx imu > > sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, > > @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI > > tristate > > depends on IIO_ST_LSM6DSX > > select REGMAP_SPI > > + > > +config IIO_ST_LSM6DSX_I3C > > + tristate > > + depends on IIO_ST_LSM6DSX > > + select REGMAP_I3C > > diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile > > b/drivers/iio/imu/st_lsm6dsx/Makefile > > index e5f733c..c676965 100644 > > --- a/drivers/iio/imu/st_lsm6dsx/Makefile > > +++ b/drivers/iio/imu/st_lsm6dsx/Makefile > > @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ > > obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o > > obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o > > obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o > > +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > new file mode 100644 > > index 000..57e6331 > > --- /dev/null > > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > @@ -0,0 +1,57 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > + * > > + * Author: Vitor Soares > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "st_lsm6dsx.h" > > + > > +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { > > + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), > > + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), > > + { /* sentinel */ }, > > +}; > > +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); > > + > > +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) > > +{ > > + struct regmap_config st_lsm6dsx_i3c_regmap_config = { > > + .reg_bits = 8, > > + .val_bits = 8, > > + }; > > + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, > > + st_lsm6dsx_i3c_ids); > > + struct regmap *regmap; > > + > > + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); > > + if (IS_ERR(regmap)) { > > + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", > > + (int)PTR_ERR(regmap)); > > + return PTR_ERR(regmap); > > + } > > + > > + return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap); > > +} > > + > > +static struct i3c_driver st_lsm6dsx_driver = { > > + .driver = { > > + .name = "st_lsm6dsx_i3c", > > + .pm = &st_lsm6dsx_pm_ops, > > + }, > > + .probe = st_lsm6dsx_i3c_probe, > > + .id_table = st_lsm6dsx_i3c_ids, > > +}; > > +module_i3c_driver(st_lsm6dsx_driver); > > + > > +MODULE_AUTHOR("Vitor Soares "); > > +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); > > +MODULE_LICENSE("GPL v2"); Best regards, Vitor Soares
RE: [PATCH v6 1/2] i3c: move i3c_device_match_id to device.c and export it
From: Boris Brezillon Date: Fri, Jul 19, 2019 at 14:45:03 > On Fri, 19 Jul 2019 15:30:54 +0200 > Vitor Soares wrote: > > > Some I3C device drivers need to know which entry matches the > > i3c_device object passed to the probe function > > > > Let's move i3c_device_match_id() to device.c and export it so it can be > > used by drivers. > > > > Signed-off-by: Vitor Soares > > Looks good to me. I'll apply the patch when -rc1 is out and provide an > immutable branch for iio maintainers. Thanks, Vitor Soares
[PATCH v3 0/3] Add ST lsm6dso i3c support
This patch series add i3c support for STM LSM6DSO and LSM6DSR sensors. It is also introduced i3c support on regmap api. Due the lack of i3c devices HDR capables on the market the support for now is only for i3c sdr mode by using i3c_device_do_priv_xfers() method. The i3c regmap api is already available in the Git repository at: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/regmap-i3c Change in v3: Update st_lsm6dsx_probe() call Remove i3c_get_device_id() and use i3c_device_match_id() Changes in v2: Change i3c_get_device_id() to drivers/i3c/device.c Add support for LSM6DSR Vitor Soares (3): regmap: add i3c bus support i3c: add i3c_get_device_id helper iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR drivers/base/regmap/Kconfig | 6 ++- drivers/base/regmap/Makefile| 1 + drivers/base/regmap/regmap-i3c.c| 60 drivers/i3c/device.c| 46 ++ drivers/i3c/master.c| 45 - drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 61 + include/linux/i3c/device.h | 4 ++ include/linux/regmap.h | 20 ++ 10 files changed, 205 insertions(+), 47 deletions(-) create mode 100644 drivers/base/regmap/regmap-i3c.c create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c -- 2.7.4
[PATCH v3 2/3] i3c: move i3c_device_match_id to device.c and export it
The i3c device driver needs the i3c_device_id table. Lets move it to device.c and export it to be used. Signed-off-by: Vitor Soares --- Changes in v3: Remove i3c_get_device_id Move i3c_device_match_id from drivers/i3c/master.c to drivers/i3c/device.c Export i3c_device_match_id Changes in v2: move this function to drivers/i3c/device.c drivers/i3c/device.c | 46 ++ drivers/i3c/master.c | 45 - include/linux/i3c/device.h | 4 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 69cc040..383df3b 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -200,6 +200,52 @@ struct i3c_device *dev_to_i3cdev(struct device *dev) } EXPORT_SYMBOL_GPL(dev_to_i3cdev); +const struct i3c_device_id * +i3c_device_match_id(struct i3c_device *i3cdev, + const struct i3c_device_id *id_table) +{ + struct i3c_device_info devinfo; + const struct i3c_device_id *id; + + i3c_device_get_info(i3cdev, &devinfo); + + /* +* The lower 32bits of the provisional ID is just filled with a random +* value, try to match using DCR info. +*/ + if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { + u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); + u16 part = I3C_PID_PART_ID(devinfo.pid); + u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); + + /* First try to match by manufacturer/part ID. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != + I3C_MATCH_MANUF_AND_PART) + continue; + + if (manuf != id->manuf_id || part != id->part_id) + continue; + + if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && + ext_info != id->extra_info) + continue; + + return id; + } + } + + /* Fallback to DCR match. */ + for (id = id_table; id->match_flags != 0; id++) { + if ((id->match_flags & I3C_MATCH_DCR) && + id->dcr == devinfo.dcr) + return id; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(i3c_device_match_id); + /** * i3c_driver_register_with_owner() - register an I3C device driver * diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..7667f84 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -270,51 +270,6 @@ static const struct device_type i3c_device_type = { .uevent = i3c_device_uevent, }; -static const struct i3c_device_id * -i3c_device_match_id(struct i3c_device *i3cdev, - const struct i3c_device_id *id_table) -{ - struct i3c_device_info devinfo; - const struct i3c_device_id *id; - - i3c_device_get_info(i3cdev, &devinfo); - - /* -* The lower 32bits of the provisional ID is just filled with a random -* value, try to match using DCR info. -*/ - if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) { - u16 manuf = I3C_PID_MANUF_ID(devinfo.pid); - u16 part = I3C_PID_PART_ID(devinfo.pid); - u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); - - /* First try to match by manufacturer/part ID. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) != - I3C_MATCH_MANUF_AND_PART) - continue; - - if (manuf != id->manuf_id || part != id->part_id) - continue; - - if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && - ext_info != id->extra_info) - continue; - - return id; - } - } - - /* Fallback to DCR match. */ - for (id = id_table; id->match_flags != 0; id++) { - if ((id->match_flags & I3C_MATCH_DCR) && - id->dcr == devinfo.dcr) - return id; - } - - return NULL; -} - static int i3c_device_match(struct device *dev, struct device_driver *drv) { struct i3c_device *i3cdev; diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index 5ecb055..de102e4 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -188,6 +188,10 @@ static inline struct i3c_driver *drv_to_i3cdrv(struct device_driver *drv) struct device *i3cdev_to_dev(struct i3c_device *i3cdev); struct i3c_dev
[PATCH v3 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in spi and i2c mode. The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to them. Signed-off-by: Vitor Soares Acked-by: Lorenzo Bianconi --- Changes in v3: Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name Use st_lsm6dsx_probe new form Changes in v2: Add support for LSM6DSR Set pm_ops to st_lsm6dsx_pm_ops drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- drivers/iio/imu/st_lsm6dsx/Makefile | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 61 + 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 9e59297..6b5a73c 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -1,11 +1,12 @@ config IIO_ST_LSM6DSX tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors" - depends on (I2C || SPI) + depends on (I2C || SPI || I3C) select IIO_BUFFER select IIO_KFIFO_BUF select IIO_ST_LSM6DSX_I2C if (I2C) select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) + select IIO_ST_LSM6DSX_I3C if (I3C) help Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, @@ -23,3 +24,8 @@ config IIO_ST_LSM6DSX_SPI tristate depends on IIO_ST_LSM6DSX select REGMAP_SPI + +config IIO_ST_LSM6DSX_I3C + tristate + depends on IIO_ST_LSM6DSX + select REGMAP_I3C diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index e5f733c..c676965 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -4,3 +4,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o +obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c new file mode 100644 index 000..f683754 --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + * + * Author: Vitor Soares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[]; + +static const struct regmap_config st_lsm6dsx_i3c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) +{ + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, + st_lsm6dsx_i3c_ids); + struct regmap *regmap; + int hw_id = (int)id->data; + + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return st_lsm6dsx_probe(&i3cdev->dev, 0, hw_id, regmap); +} + +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); + +static struct i3c_driver st_lsm6dsx_driver = { + .driver = { + .name = "st_lsm6dsx_i3c", + .pm = &st_lsm6dsx_pm_ops, + }, + .probe = st_lsm6dsx_i3c_probe, + .id_table = st_lsm6dsx_i3c_ids, +}; +module_i3c_driver(st_lsm6dsx_driver); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); +MODULE_LICENSE("GPL v2"); -- 2.7.4
[PATCH v3 1/3] regmap: add i3c bus support
Add basic support for i3c bus. This is a simple implementation that only give support for SDR Read and Write commands. Signed-off-by: Vitor Soares --- drivers/base/regmap/Kconfig | 6 +++- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-i3c.c | 60 include/linux/regmap.h | 20 ++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-i3c.c diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 6ad5ef4..c8bbf53 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,7 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_I3C) select IRQ_DOMAIN if REGMAP_IRQ bool @@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE config REGMAP_SCCB tristate depends on I2C + +config REGMAP_I3C + tristate + depends on I3C diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index f5b4e88..ff6c7d8 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_W1) += regmap-w1.o obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o +obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o diff --git a/drivers/base/regmap/regmap-i3c.c b/drivers/base/regmap/regmap-i3c.c new file mode 100644 index 000..1578fb5 --- /dev/null +++ b/drivers/base/regmap/regmap-i3c.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. + +#include +#include +#include +#include + +static int regmap_i3c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = count, + .data.out = data, + }, + }; + + return i3c_device_do_priv_xfers(i3c, xfers, 1); +} + +static int regmap_i3c_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i3c_device *i3c = dev_to_i3cdev(dev); + struct i3c_priv_xfer xfers[2]; + + xfers[0].rnw = false; + xfers[0].len = reg_size; + xfers[0].data.out = reg; + + xfers[1].rnw = true; + xfers[1].len = val_size; + xfers[1].data.in = val; + + return i3c_device_do_priv_xfers(i3c, xfers, 2); +} + +static struct regmap_bus regmap_i3c = { + .write = regmap_i3c_write, + .read = regmap_i3c_read, +}; + +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + return __devm_regmap_init(&i3c->dev, ®map_i3c, &i3c->dev, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c); + +MODULE_AUTHOR("Vitor Soares "); +MODULE_DESCRIPTION("Regmap I3C Module"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index daeec7d..f65984d 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -25,6 +25,7 @@ struct module; struct clk; struct device; struct i2c_client; +struct i3c_device; struct irq_domain; struct slim_device; struct spi_device; @@ -624,6 +625,10 @@ struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c, +const struct regmap_config *config, +struct lock_class_key *lock_key, +const char *lock_name); /* * Wrapper for regmap_init macros to include a unique lockdep key and name * for each call. No-op if CONFIG_LOCKDEP is not set. @@ -982,6 +987,21 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); #define devm_regmap_init_slimbus(slimbus, config) \ __regmap_lockdep_wrapper(__devm_regmap_init_slimbus, #config, \ slimbus, config) + +/** + * devm_regmap_init_i3c() - Initialise managed re
RE: [PATCH v3 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
Hi Lorenzo, From: Lorenzo Bianconi Date: Wed, Jul 10, 2019 at 20:44:05 > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in > > spi and i2c mode. > > > > The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to > > them. > > Hi Vitor, > > just few comments inline. > > Regards, > Lorenzo > > > > > Signed-off-by: Vitor Soares > > Acked-by: Lorenzo Bianconi > > --- > > Changes in v3: > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name > > Use st_lsm6dsx_probe new form > > > > Changes in v2: > > Add support for LSM6DSR > > Set pm_ops to st_lsm6dsx_pm_ops > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 61 > > + > > 3 files changed, 69 insertions(+), 1 deletion(-) > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > [...] > > > diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > new file mode 100644 > > index 000..f683754 > > --- /dev/null > > +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > @@ -0,0 +1,61 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. > > + * > > + * Author: Vitor Soares > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "st_lsm6dsx.h" > > + > > +static const struct i3c_device_id st_lsm6dsx_i3c_ids[]; > > + > > why do we need this? I guess you can just move st_lsm6dsx_i3c_ids definition > here > > > +static const struct regmap_config st_lsm6dsx_i3c_regmap_config = { > > + .reg_bits = 8, > > + .val_bits = 8, > > +}; > > + > > +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) > > +{ > > + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, > > + st_lsm6dsx_i3c_ids); > > i3c_device_match_id can theoretically fail so is it better to check > return value here? (maybe I am too paranoid :)) > > > + struct regmap *regmap; > > + int hw_id = (int)id->data; > > I guess we do not need this since we use it just in st_lsm6dsx_probe(), > we can just do: > > return st_lsm6dsx_probe(&i3cdev->dev, 0, (int)id->data, regmap); > > + > > + regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config); > > + if (IS_ERR(regmap)) { > > + dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", > > + (int)PTR_ERR(regmap)); > > + return PTR_ERR(regmap); > > + } > > + > > + return st_lsm6dsx_probe(&i3cdev->dev, 0, hw_id, regmap); > > +} > > + > > +static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = { > > + I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID), > > + I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID), > > + { /* sentinel */ }, > > +}; > > +MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids); > > + > > +static struct i3c_driver st_lsm6dsx_driver = { > > + .driver = { > > + .name = "st_lsm6dsx_i3c", > > + .pm = &st_lsm6dsx_pm_ops, > > + }, > > + .probe = st_lsm6dsx_i3c_probe, > > + .id_table = st_lsm6dsx_i3c_ids, > > +}; > > +module_i3c_driver(st_lsm6dsx_driver); > > + > > +MODULE_AUTHOR("Vitor Soares "); > > +MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.7.4 > > Thanks for your comments. I will address them and send a new version. Best regards, Vitor Soares
RE: [PATCH v3 3/3] iio: imu: st_lsm6dsx: add i3c basic support for LSM6DSO and LSM6DSR
From: Vitor Soares Date: Thu, Jul 11, 2019 at 11:12:34 > Hi Lorenzo, > > From: Lorenzo Bianconi > Date: Wed, Jul 10, 2019 at 20:44:05 > > > > For today the st_lsm6dsx driver support LSM6DSO and LSM6DSR sensor only in > > > spi and i2c mode. > > > > > > The LSM6DSO and LSM6DSR are also i3c capable so lets give i3c support to > > > them. > > > > Hi Vitor, > > > > just few comments inline. > > > > Regards, > > Lorenzo > > > > > > > > Signed-off-by: Vitor Soares > > > Acked-by: Lorenzo Bianconi > > > --- > > > Changes in v3: > > > Remove unnecessary st_lsm6dsx_i3c_data table used to hold device name > > > Use st_lsm6dsx_probe new form > > > > > > Changes in v2: > > > Add support for LSM6DSR > > > Set pm_ops to st_lsm6dsx_pm_ops > > > > > > drivers/iio/imu/st_lsm6dsx/Kconfig | 8 +++- > > > drivers/iio/imu/st_lsm6dsx/Makefile | 1 + > > > drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c | 61 > > > + > > > 3 files changed, 69 insertions(+), 1 deletion(-) > > > create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c > > > > > > > [...] > > > +static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev) > > > +{ > > > + const struct i3c_device_id *id = i3c_device_match_id(i3cdev, > > > + st_lsm6dsx_i3c_ids); > > > > i3c_device_match_id can theoretically fail so is it better to check > > return value here? (maybe I am too paranoid :)) I was preparing the patch and if the i3c_device_match_id() fail it return NULL so the st_lsm6dsx_probe() will fail automatically. Checking the spi_get_device_id(), the drivers don't test the return value too. Do you think it is really necessary to test it before the st_lsm6dsx_probe() function? Best regards, Vitor Soares
[PATCH 3/7] i3c: master: dw: remove dead code from dw_i3c_master_*_xfers()
Detected by CoverityScan (Event result_independent_of_operands): "(i3c_xfers + i).len > 65536" is always false regardless of the values of its operands. This occurs as the logical operand of "if" "(i2c_xfers + i).len > 65536" is always false regardless of the values of its operands. This occurs as the logical operand of "if" Signed-off-by: Vitor Soares --- drivers/i3c/master/dw-i3c-master.c | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index bb03079..eef6fae 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -840,11 +840,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, return -ENOTSUPP; for (i = 0; i < i3c_nxfers; i++) { - if (i3c_xfers[i].len > COMMAND_PORT_ARG_DATA_LEN_MAX) - return -ENOTSUPP; - } - - for (i = 0; i < i3c_nxfers; i++) { if (i3c_xfers[i].rnw) nrxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4); else @@ -973,11 +968,6 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, return -ENOTSUPP; for (i = 0; i < i2c_nxfers; i++) { - if (i2c_xfers[i].len > COMMAND_PORT_ARG_DATA_LEN_MAX) - return -ENOTSUPP; - } - - for (i = 0; i < i2c_nxfers; i++) { if (i2c_xfers[i].flags & I2C_M_RD) nrxwords += DIV_ROUND_UP(i2c_xfers[i].len, 4); else -- 2.7.4
RE: [PATCH v3 1/3] i3c: fix i2c and i3c scl rate by bus mode
From: Boris Brezillon Date: Wed, Jun 12, 2019 at 07:15:33 > On Tue, 11 Jun 2019 16:06:43 +0200 > Vitor Soares wrote: > > > Currently the I3C framework limits SCL frequency to FM speed when > > dealing with a mixed slow bus, even if all I2C devices are FM+ capable. > > > > The core was also not accounting for I3C speed limitations when > > operating in mixed slow mode and was erroneously using FM+ speed as the > > max I2C speed when operating in mixed fast mode. > > > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > Signed-off-by: Vitor Soares > > Cc: Boris Brezillon > > Cc: > > Cc: > > --- > > Changes in v3: > > Change dev_warn() to dev_dbg() > > > > Changes in v2: > > Enhance commit message > > Add dev_warn() in case user-defined i2c rate doesn't match LVR constraint > > Add dev_warn() in case user-defined i3c rate lower than i2c rate > > > > drivers/i3c/master.c | 61 > > +--- > > 1 file changed, 48 insertions(+), 13 deletions(-) > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > index 5f4bd52..f8e580e 100644 > > --- a/drivers/i3c/master.c > > +++ b/drivers/i3c/master.c > > @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) > > up_read(&bus->lock); > > } > > > > +static struct i3c_master_controller * > > +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) > > +{ > > + return container_of(i3cbus, struct i3c_master_controller, bus); > > +} > > + > > static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) > > { > > return container_of(dev, struct i3c_master_controller, dev); > > @@ -565,20 +571,48 @@ static const struct device_type i3c_masterdev_type = { > > .groups = i3c_masterdev_groups, > > }; > > > > -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) > > +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, > > +unsigned long max_i2c_scl_rate) > > { > > - i3cbus->mode = mode; > > > > - if (!i3cbus->scl_rate.i3c) > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); > > > > - if (!i3cbus->scl_rate.i2c) { > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > - else > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > + i3cbus->mode = mode; > > + > > + switch (i3cbus->mode) { > > + case I3C_BUS_MODE_PURE: > > + if (!i3cbus->scl_rate.i3c) > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + break; > > + case I3C_BUS_MODE_MIXED_FAST: > > + if (!i3cbus->scl_rate.i3c) > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > + if (!i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > + break; > > + case I3C_BUS_MODE_MIXED_SLOW: > > + if (!i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > + if (!i3cbus->scl_rate.i3c || > > + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) > > + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; > > + break; > > + default: > > + return -EINVAL; > > } > > > > + if (i3cbus->scl_rate.i3c < i3cbus->scl_rate.i2c) > > + dev_dbg(&master->dev, > > + "i3c-scl-hz=%ld lower than i2c-scl-hz=%ld\n", > > + i3cbus->scl_rate.i3c, i3cbus->scl_rate.i2c); > > + > > + if (i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_SCL_RATE && > > + i3cbus->scl_rate.i2c != I3C_BUS_I2C_FM_PLUS_SCL_RATE && > > + i3cbus->mode != I3C_BUS_MODE_PURE) > > + dev_dbg(&master->dev, > > + "i2c-scl-hz=%ld not defined according MIPI I3C spec\n", > > + i3cbus->scl_rate.i2c); > > + > > Again, that's not what I suggested, so I'll write it down: > > dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n", > i3cbus->scl_rate.i2c, i3cbus->s
RE: [PATCH v3 1/3] i3c: fix i2c and i3c scl rate by bus mode
From: Boris Brezillon Date: Wed, Jun 12, 2019 at 12:37:27 > On Wed, 12 Jun 2019 11:16:34 + > Vitor Soares wrote: > > > From: Boris Brezillon > > Date: Wed, Jun 12, 2019 at 07:15:33 > > > > > On Tue, 11 Jun 2019 16:06:43 +0200 > > > Vitor Soares wrote: > > > > > > > Currently the I3C framework limits SCL frequency to FM speed when > > > > dealing with a mixed slow bus, even if all I2C devices are FM+ capable. > > > > > > > > The core was also not accounting for I3C speed limitations when > > > > operating in mixed slow mode and was erroneously using FM+ speed as the > > > > max I2C speed when operating in mixed fast mode. > > > > > > > > Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") > > > > Signed-off-by: Vitor Soares > > > > Cc: Boris Brezillon > > > > Cc: > > > > Cc: > > > > --- > > > > Changes in v3: > > > > Change dev_warn() to dev_dbg() > > > > > > > > Changes in v2: > > > > Enhance commit message > > > > Add dev_warn() in case user-defined i2c rate doesn't match LVR > > > > constraint > > > > Add dev_warn() in case user-defined i3c rate lower than i2c rate > > > > > > > > drivers/i3c/master.c | 61 > > > > +--- > > > > 1 file changed, 48 insertions(+), 13 deletions(-) > > > > > > > > diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c > > > > index 5f4bd52..f8e580e 100644 > > > > --- a/drivers/i3c/master.c > > > > +++ b/drivers/i3c/master.c > > > > @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) > > > > up_read(&bus->lock); > > > > } > > > > > > > > +static struct i3c_master_controller * > > > > +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) > > > > +{ > > > > + return container_of(i3cbus, struct i3c_master_controller, bus); > > > > +} > > > > + > > > > static struct i3c_master_controller *dev_to_i3cmaster(struct device > > > > *dev) > > > > { > > > > return container_of(dev, struct i3c_master_controller, dev); > > > > @@ -565,20 +571,48 @@ static const struct device_type > > > > i3c_masterdev_type = { > > > > .groups = i3c_masterdev_groups, > > > > }; > > > > > > > > -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) > > > > +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, > > > > +unsigned long max_i2c_scl_rate) > > > > { > > > > - i3cbus->mode = mode; > > > > > > > > - if (!i3cbus->scl_rate.i3c) > > > > - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + struct i3c_master_controller *master = > > > > i3c_bus_to_i3c_master(i3cbus); > > > > > > > > - if (!i3cbus->scl_rate.i2c) { > > > > - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) > > > > - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; > > > > - else > > > > - i3cbus->scl_rate.i2c = > > > > I3C_BUS_I2C_FM_PLUS_SCL_RATE; > > > > + i3cbus->mode = mode; > > > > + > > > > + switch (i3cbus->mode) { > > > > + case I3C_BUS_MODE_PURE: > > > > + if (!i3cbus->scl_rate.i3c) > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + break; > > > > + case I3C_BUS_MODE_MIXED_FAST: > > > > + if (!i3cbus->scl_rate.i3c) > > > > + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; > > > > + if (!i3cbus->scl_rate.i2c) > > > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > > > + break; > > > > + case I3C_BUS_MODE_MIXED_SLOW: > > > > + if (!i3cbus->scl_rate.i2c) > > > > + i3cbus->scl_rate.i2c = max_i2c_scl_rate; > > > > + if (!i3cbus->scl_rate.i3c || > > > > + i3
[PATCH v4 3/3] i3c: dw: add limited bus mode support
This patch add limited bus mode support for DesignWare i3c master Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- Changes in v4: None Changes in v3: None Changes in v2: None drivers/i3c/master/dw-i3c-master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 1d83c97..9612d93 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -599,6 +599,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: ret = dw_i2c_clk_cfg(master); if (ret) return ret; -- 2.7.4
[PATCH v4 2/3] i3c: add mixed limited bus mode
The i3c bus spec defines a bus configuration where i2c devices don't have a 50ns filter but support SCL running at SDR max rate (12.5MHz). This patch introduces the limited bus mode so that users can use a higher speed in presence of i2c devices index 1. Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- Changes in v4: None Changes in v3: None Changes in v2: Enhance commit message drivers/i3c/master.c | 5 + include/linux/i3c/master.h | 5 + 2 files changed, 10 insertions(+) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 14980db..76549f1 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -470,6 +470,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) static const char * const i3c_bus_mode_strings[] = { [I3C_BUS_MODE_PURE] = "pure", [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", + [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", }; @@ -585,6 +586,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; break; case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: if (!i3cbus->scl_rate.i3c) i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; if (!i3cbus->scl_rate.i2c) @@ -2481,6 +2483,9 @@ int i3c_master_register(struct i3c_master_controller *master, mode = I3C_BUS_MODE_MIXED_FAST; break; case I3C_LVR_I2C_INDEX(1): + if (mode < I3C_BUS_MODE_MIXED_LIMITED) + mode = I3C_BUS_MODE_MIXED_LIMITED; + break; case I3C_LVR_I2C_INDEX(2): if (mode < I3C_BUS_MODE_MIXED_SLOW) mode = I3C_BUS_MODE_MIXED_SLOW; diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index f13fd8b..89ea461 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -250,12 +250,17 @@ struct i3c_device { * the bus. The only impact in this mode is that the * high SCL pulse has to stay below 50ns to trick I2C * devices when transmitting I3C frames + * @I3C_BUS_MODE_MIXED_LIMITED: I2C devices without 50ns spike filter are + * present on the bus. However they allows + * compliance up to the maximum SDR SCL clock + * frequency. * @I3C_BUS_MODE_MIXED_SLOW: I2C devices without 50ns spike filter are present * on the bus */ enum i3c_bus_mode { I3C_BUS_MODE_PURE, I3C_BUS_MODE_MIXED_FAST, + I3C_BUS_MODE_MIXED_LIMITED, I3C_BUS_MODE_MIXED_SLOW, }; -- 2.7.4
[PATCH v4 1/3] i3c: fix i2c and i3c scl rate by bus mode
Currently the I3C framework limits SCL frequency to FM speed when dealing with a mixed slow bus, even if all I2C devices are FM+ capable. The core was also not accounting for I3C speed limitations when operating in mixed slow mode and was erroneously using FM+ speed as the max I2C speed when operating in mixed fast mode. Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: Cc: --- Changes in v4: Print i2c-scl and i3c-scl unconditionally when in debug mode Changes in v3: Change dev_warn() to dev_dbg() Changes in v2: Enhance commit message Add dev_warn() in case user-defined i2c rate doesn't match LVR constraint Add dev_warn() in case user-defined i3c rate lower than i2c rate drivers/i3c/master.c | 52 +++- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5f4bd52..14980db 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus) up_read(&bus->lock); } +static struct i3c_master_controller * +i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) +{ + return container_of(i3cbus, struct i3c_master_controller, bus); +} + static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) { return container_of(dev, struct i3c_master_controller, dev); @@ -565,20 +571,39 @@ static const struct device_type i3c_masterdev_type = { .groups = i3c_masterdev_groups, }; -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, +unsigned long max_i2c_scl_rate) { - i3cbus->mode = mode; - if (!i3cbus->scl_rate.i3c) - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); - if (!i3cbus->scl_rate.i2c) { - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - else - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; + i3cbus->mode = mode; + + switch (i3cbus->mode) { + case I3C_BUS_MODE_PURE: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + break; + case I3C_BUS_MODE_MIXED_FAST: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + break; + case I3C_BUS_MODE_MIXED_SLOW: + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = max_i2c_scl_rate; + if (!i3cbus->scl_rate.i3c || + i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; + break; + default: + return -EINVAL; } + dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n", + i3cbus->scl_rate.i2c, i3cbus->scl_rate.i3c); + /* * I3C/I2C frequency may have been overridden, check that user-provided * values are not exceeding max possible frequency. @@ -1966,9 +1991,6 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master, /* LVR is encoded in reg[2]. */ boardinfo->lvr = reg[2]; - if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) - master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - list_add_tail(&boardinfo->node, &master->boardinfo.i2c); of_node_get(node); @@ -2417,6 +2439,7 @@ int i3c_master_register(struct i3c_master_controller *master, const struct i3c_master_controller_ops *ops, bool secondary) { + unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; struct i3c_bus *i3cbus = i3c_master_get_bus(master); enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; struct i2c_dev_boardinfo *i2cbi; @@ -2466,9 +2489,12 @@ int i3c_master_register(struct i3c_master_controller *master, ret = -EINVAL; goto err_put_dev; } + + if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE) + i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE; } - ret = i3c_bus_set_mode(i3cbus, mode); + ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate); if (ret) goto err_put_dev; -- 2.7.4
RE: [PATCH] reset: axs10x: Implement assert and deassert callbacks
Hi Eugeniy, From: Eugeniy Paltsev Date: Fri, Apr 12, 2019 at 14:22:33 > Hi Vitor, > > On Mon, 2019-04-08 at 13:25 +0000, Vitor Soares wrote: > > Hi Eugeniy, > > > > From: Eugeniy Paltsev > > Date: Mon, Apr 08, 2019 at 12:40:00 > > > > > Hi Vitor, > > > > > > On Mon, 2019-04-08 at 12:31 +0200, Vitor Soares wrote: > > > > Some custom IP-block connected to ARC AXS10x board need assert and > > > > deassert functions to control reset signal of selected peripherals. > > > > > > > > This patch improve AXS10x reset driver by adding assert and deassert > > > > callbacks. > > > > > > > > > In the AXS10x reset driver only 'reset' callback is intentionally > > > > implemented. > > > > > > AXS10x is FPGA based boards and with our default firmware AXS10x reset > > > > register is implemented as self-deasserted. > > > > I have another reset block connect through AXI. > > > > > Do you have somehow modified AXS10x firmware where reset register is not > > > > self-deasserted? > > > > > > In that case "simple-reset" driver will be suitable for you, I guess. > > > > I will try it. > > > > > Otherwise this implementation is incorrect - there should be no 'assert' > > > for > > > > reset controller with self-deasserted logic. > > > > So the assert and reset callback are mutually exclusive? > > Not actually. > > Adding 'assert' callback is incorrect for exclusive reset controls in > case of self-deasserted reset controller. > It will cause reset_control_assert() to return success for exclusive > reset controls, even though the .assert op failed to leave the reset > line asserted after the function returns. > Sorry I'm not understanding. Can you please explain? What I see in reset_control_assert() when not shared is return -ENOTSUPP. > > [snap] > > > > Best regards, > > Vitor Soares > > > -- > Eugeniy Paltsev Thanks for your feedback. Best regards, Vitor Soares
[PATCH 1/3] i3c: fix i2c and i3c scl rate by bus mode
Currently in case of mixed slow bus topologie and all i2c devices support FM+ speed, the i3c subsystem limite the SCL to FM speed. Also in case on mixed slow bus mode the max speed for both i2c or i3c transfers is FM or FM+. This patch fix the definition of i2c and i3c scl rate based on bus topologie and LVR[4] if no user input. In case of mixed slow mode the i3c scl rate is overridden. Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: Cc: --- drivers/i3c/master.c | 39 +-- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 909c2ad..1c4a86a 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -564,20 +564,30 @@ static const struct device_type i3c_masterdev_type = { .groups = i3c_masterdev_groups, }; -int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) +int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, +unsigned long i2c_scl_rate) { i3cbus->mode = mode; - if (!i3cbus->scl_rate.i3c) - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; - - if (!i3cbus->scl_rate.i2c) { - if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - else - i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; + switch (i3cbus->mode) { + case I3C_BUS_MODE_PURE: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + break; + case I3C_BUS_MODE_MIXED_FAST: + if (!i3cbus->scl_rate.i3c) + i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = i2c_scl_rate; + break; + case I3C_BUS_MODE_MIXED_SLOW: + if (!i3cbus->scl_rate.i2c) + i3cbus->scl_rate.i2c = i2c_scl_rate; + i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; + break; + default: + return -EINVAL; } - /* * I3C/I2C frequency may have been overridden, check that user-provided * values are not exceeding max possible frequency. @@ -1980,9 +1990,6 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master, /* LVR is encoded in reg[2]. */ boardinfo->lvr = reg[2]; - if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) - master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; - list_add_tail(&boardinfo->node, &master->boardinfo.i2c); of_node_get(node); @@ -2432,6 +2439,7 @@ int i3c_master_register(struct i3c_master_controller *master, const struct i3c_master_controller_ops *ops, bool secondary) { + unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; struct i3c_bus *i3cbus = i3c_master_get_bus(master); enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; struct i2c_dev_boardinfo *i2cbi; @@ -2481,9 +2489,12 @@ int i3c_master_register(struct i3c_master_controller *master, ret = -EINVAL; goto err_put_dev; } + + if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE) + i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE; } - ret = i3c_bus_set_mode(i3cbus, mode); + ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate); if (ret) goto err_put_dev; -- 2.7.4
[PATCH 2/3] i3c: add mixed limited bus mode
The i3c bus spec define a bus configuration where the i2c devices doesn't have the 50ns filter yet they allow the SDR max speed. This patch introduce the limited bus mode so the users can use a higher speed on presence of i2c devices index 1. Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- drivers/i3c/master.c | 5 + include/linux/i3c/master.h | 5 + 2 files changed, 10 insertions(+) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 1c4a86a..46d3774 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -463,6 +463,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) static const char * const i3c_bus_mode_strings[] = { [I3C_BUS_MODE_PURE] = "pure", [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", + [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", }; @@ -575,6 +576,7 @@ int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; break; case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: if (!i3cbus->scl_rate.i3c) i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; if (!i3cbus->scl_rate.i2c) @@ -2481,6 +2483,9 @@ int i3c_master_register(struct i3c_master_controller *master, mode = I3C_BUS_MODE_MIXED_FAST; break; case I3C_LVR_I2C_INDEX(1): + if (mode < I3C_BUS_MODE_MIXED_LIMITED) + mode = I3C_BUS_MODE_MIXED_LIMITED; + break; case I3C_LVR_I2C_INDEX(2): if (mode < I3C_BUS_MODE_MIXED_SLOW) mode = I3C_BUS_MODE_MIXED_SLOW; diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 44fb3cf..740235e 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -250,12 +250,17 @@ struct i3c_device { * the bus. The only impact in this mode is that the * high SCL pulse has to stay below 50ns to trick I2C * devices when transmitting I3C frames + * @I3C_BUS_MODE_MIXED_LIMITED: I2C devices without 50ns spike filter are + * present on the bus. However they allows + * compliance up to the maximum SDR SCL clock + * frequency. * @I3C_BUS_MODE_MIXED_SLOW: I2C devices without 50ns spike filter are present * on the bus */ enum i3c_bus_mode { I3C_BUS_MODE_PURE, I3C_BUS_MODE_MIXED_FAST, + I3C_BUS_MODE_MIXED_LIMITED, I3C_BUS_MODE_MIXED_SLOW, }; -- 2.7.4
[PATCH 3/3] i3c: dw: Add limited bus mode support
This patch add limited bus mode support for DesignWare i3c master Signed-off-by: Vitor Soares Cc: Boris Brezillon Cc: --- drivers/i3c/master/dw-i3c-master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 0b01607..4005508 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -650,6 +650,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: + case I3C_BUS_MODE_MIXED_LIMITED: ret = dw_i2c_clk_cfg(master); if (ret) return ret; -- 2.7.4