Message ID | 20191122212052.27053-1-vladimir.olovyannikov@broadcom.com |
---|---|
State | Changes Requested |
Delegated to: | Heiko Schocher |
Headers | show |
Series | [U-Boot,1/1] drivers: i2c: Add brcm iproc I2C driver support | expand |
Hello Vladimir, Am 22.11.2019 um 22:20 schrieb Vladimir Olovyannikov: > From: Arjun Jyothi <arjun.jyothi@broadcom.com> > > Add I2C driver support for Broadcom iproc-based socs. > > Signed-off-by: Arjun Jyothi <arjun.jyothi@broadcom.com> > Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com> > Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com> > Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com> > --- > drivers/i2c/Kconfig | 623 ++++++++++++++++---------------- > drivers/i2c/Makefile | 2 +- > drivers/i2c/iproc_i2c.c | 765 ++++++++++++++++++++++++++++++++++++++++ > drivers/i2c/iproc_i2c.h | 356 +++++++++++++++++++ > 4 files changed, 1437 insertions(+), 309 deletions(-) > create mode 100644 drivers/i2c/iproc_i2c.c > create mode 100644 drivers/i2c/iproc_i2c.h > > diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig > index 03d2fed341..7a80971b12 100644 > --- a/drivers/i2c/Kconfig > +++ b/drivers/i2c/Kconfig > @@ -5,454 +5,461 @@ > menu "I2C support" > > config DM_I2C > - bool "Enable Driver Model for I2C drivers" > - depends on DM > - help > - Enable driver model for I2C. The I2C uclass interface: probe, read, > - write and speed, is implemented with the bus drivers operations, > - which provide methods for bus setting and data transfer. Each chip > - device (bus child) info is kept as parent platdata. The interface > - is defined in include/i2c.h. > + bool "Enable Driver Model for I2C drivers" > + depends on DM > + help > + Enable driver model for I2C. The I2C uclass interface: probe, read, > + write and speed, is implemented with the bus drivers operations, > + which provide methods for bus setting and data transfer. Each chip > + device (bus child) info is kept as parent platdata. The interface > + is defined in include/i2c.h. This (and a lot of following) change removes tabs with spaces, NACK. Please do not remove the tabs! > config I2C_CROS_EC_TUNNEL > - tristate "Chrome OS EC tunnel I2C bus" > - depends on CROS_EC > - help > - This provides an I2C bus that will tunnel i2c commands through to > - the other side of the Chrome OS EC to the I2C bus connected there. > - This will work whatever the interface used to talk to the EC (SPI, > - I2C or LPC). Some Chromebooks use this when the hardware design > - does not allow direct access to the main PMIC from the AP. > + tristate "Chrome OS EC tunnel I2C bus" > + depends on CROS_EC > + help > + This provides an I2C bus that will tunnel i2c commands through to > + the other side of the Chrome OS EC to the I2C bus connected there. > + This will work whatever the interface used to talk to the EC (SPI, > + I2C or LPC). Some Chromebooks use this when the hardware design > + does not allow direct access to the main PMIC from the AP. > > config I2C_CROS_EC_LDO > - bool "Provide access to LDOs on the Chrome OS EC" > - depends on CROS_EC > - ---help--- > - On many Chromebooks the main PMIC is inaccessible to the AP. This is > - often dealt with by using an I2C pass-through interface provided by > - the EC. On some unfortunate models (e.g. Spring) the pass-through > - is not available, and an LDO message is available instead. This > - option enables a driver which provides very basic access to those > - regulators, via the EC. We implement this as an I2C bus which > - emulates just the TPS65090 messages we know about. This is done to > - avoid duplicating the logic in the TPS65090 regulator driver for > - enabling/disabling an LDO. > + bool "Provide access to LDOs on the Chrome OS EC" > + depends on CROS_EC > + ---help--- > + On many Chromebooks the main PMIC is inaccessible to the AP. This is > + often dealt with by using an I2C pass-through interface provided by > + the EC. On some unfortunate models (e.g. Spring) the pass-through > + is not available, and an LDO message is available instead. This > + option enables a driver which provides very basic access to those > + regulators, via the EC. We implement this as an I2C bus which > + emulates just the TPS65090 messages we know about. This is done to > + avoid duplicating the logic in the TPS65090 regulator driver for > + enabling/disabling an LDO. > > config I2C_SET_DEFAULT_BUS_NUM > - bool "Set default I2C bus number" > - depends on DM_I2C > - help > - Set default number of I2C bus to be accessed. This option provides > - behaviour similar to old (i.e. pre DM) I2C bus driver. > + bool "Set default I2C bus number" > + depends on DM_I2C > + help > + Set default number of I2C bus to be accessed. This option provides > + behaviour similar to old (i.e. pre DM) I2C bus driver. > > config I2C_DEFAULT_BUS_NUMBER > - hex "I2C default bus number" > - depends on I2C_SET_DEFAULT_BUS_NUM > - default 0x0 > - help > - Number of default I2C bus to use > + hex "I2C default bus number" > + depends on I2C_SET_DEFAULT_BUS_NUM > + default 0x0 > + help > + Number of default I2C bus to use > > config DM_I2C_GPIO > - bool "Enable Driver Model for software emulated I2C bus driver" > - depends on DM_I2C && DM_GPIO > - help > - Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO > - configuration is given by the device tree. Kernel-style device tree > - bindings are supported. > - Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt > + bool "Enable Driver Model for software emulated I2C bus driver" > + depends on DM_I2C && DM_GPIO > + help > + Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO > + configuration is given by the device tree. Kernel-style device tree > + bindings are supported. > + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt > > config SYS_I2C_AT91 > - bool "Atmel I2C driver" > - depends on DM_I2C && ARCH_AT91 > - help > - Add support for the Atmel I2C driver. A serious problem is that there > - is no documented way to issue repeated START conditions for more than > - two messages, as needed to support combined I2C messages. Use the > - i2c-gpio driver unless your system can cope with this limitation. > - Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > + bool "Atmel I2C driver" > + depends on DM_I2C && ARCH_AT91 > + help > + Add support for the Atmel I2C driver. A serious problem is that there > + is no documented way to issue repeated START conditions for more than > + two messages, as needed to support combined I2C messages. Use the > + i2c-gpio driver unless your system can cope with this limitation. > + Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > + > +config IPROC_I2C > + bool "Broadcom iProc I2C driver" > + depends on DM_I2C > + help > + Add support for Broadcom iProc I2C driver. > + The driver is used in iProc SoCs. > > config SYS_I2C_FSL > bool "Freescale I2C bus driver" > depends on DM_I2C > help > - Add support for Freescale I2C busses as used on MPC8240, MPC8245, and > - MPC85xx processors. > + Add support for Freescale I2C busses as used on MPC8240, MPC8245, and > + MPC85xx processors. > > config SYS_I2C_CADENCE > - tristate "Cadence I2C Controller" > - depends on DM_I2C && (ARCH_ZYNQ || ARM64) > - help > - Say yes here to select Cadence I2C Host Controller. This controller is > - e.g. used by Xilinx Zynq. > + tristate "Cadence I2C Controller" > + depends on DM_I2C && (ARCH_ZYNQ || ARM64) > + help > + Say yes here to select Cadence I2C Host Controller. This controller is > + e.g. used by Xilinx Zynq. > > config SYS_I2C_DAVINCI > - bool "Davinci I2C Controller" > - depends on (ARCH_KEYSTONE || ARCH_DAVINCI) > - help > - Say yes here to add support for Davinci and Keystone I2C controller > + bool "Davinci I2C Controller" > + depends on (ARCH_KEYSTONE || ARCH_DAVINCI) > + help > + Say yes here to add support for Davinci and Keystone I2C controller > > config SYS_I2C_DW > - bool "Designware I2C Controller" > - default n > - help > - Say yes here to select the Designware I2C Host Controller. This > - controller is used in various SoCs, e.g. the ST SPEAr, Altera > - SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. > + bool "Designware I2C Controller" > + default n > + help > + Say yes here to select the Designware I2C Host Controller. This > + controller is used in various SoCs, e.g. the ST SPEAr, Altera > + SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. > > config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED > - bool "DW I2C Enable Status Register not supported" > - depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ > - TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) > - default y > - help > - Some versions of the Designware I2C controller do not support the > - enable status register. This config option can be enabled in such > - cases. > + bool "DW I2C Enable Status Register not supported" > + depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ > + TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) > + default y > + help > + Some versions of the Designware I2C controller do not support the > + enable status register. This config option can be enabled in such > + cases. > > config SYS_I2C_ASPEED > - bool "Aspeed I2C Controller" > - depends on DM_I2C && ARCH_ASPEED > - help > - Say yes here to select Aspeed I2C Host Controller. The driver > - supports AST2500 and AST2400 controllers, but is very limited. > - Only single master mode is supported and only byte-by-byte > - synchronous reads and writes are supported, no Pool Buffers or DMA. > + bool "Aspeed I2C Controller" > + depends on DM_I2C && ARCH_ASPEED > + help > + Say yes here to select Aspeed I2C Host Controller. The driver > + supports AST2500 and AST2400 controllers, but is very limited. > + Only single master mode is supported and only byte-by-byte > + synchronous reads and writes are supported, no Pool Buffers or DMA. > > config SYS_I2C_INTEL > - bool "Intel I2C/SMBUS driver" > - depends on DM_I2C > - help > - Add support for the Intel SMBUS driver. So far this driver is just > - a stub which perhaps some basic init. There is no implementation of > - the I2C API meaning that any I2C operations will immediately fail > - for now. > + bool "Intel I2C/SMBUS driver" > + depends on DM_I2C > + help > + Add support for the Intel SMBUS driver. So far this driver is just > + a stub which perhaps some basic init. There is no implementation of > + the I2C API meaning that any I2C operations will immediately fail > + for now. > > config SYS_I2C_IMX_LPI2C > - bool "NXP i.MX LPI2C driver" > - help > - Add support for the NXP i.MX LPI2C driver. > + bool "NXP i.MX LPI2C driver" > + help > + Add support for the NXP i.MX LPI2C driver. > > config SYS_I2C_MESON > - bool "Amlogic Meson I2C driver" > - depends on DM_I2C && ARCH_MESON > - help > - Add support for the I2C controller available in Amlogic Meson > - SoCs. The controller supports programmable bus speed including > - standard (100kbits/s) and fast (400kbit/s) speed and allows the > - software to define a flexible format of the bit streams. It has an > - internal buffer holding up to 8 bytes for transfers and supports > - both 7-bit and 10-bit addresses. > + bool "Amlogic Meson I2C driver" > + depends on DM_I2C && ARCH_MESON > + help > + Add support for the I2C controller available in Amlogic Meson > + SoCs. The controller supports programmable bus speed including > + standard (100kbits/s) and fast (400kbit/s) speed and allows the > + software to define a flexible format of the bit streams. It has an > + internal buffer holding up to 8 bytes for transfers and supports > + both 7-bit and 10-bit addresses. > > config SYS_I2C_MXC > - bool "NXP MXC I2C driver" > - help > - Add support for the NXP I2C driver. This supports up to four bus > - channels and operating on standard mode up to 100 kbits/s and fast > - mode up to 400 kbits/s. > + bool "NXP MXC I2C driver" > + help > + Add support for the NXP I2C driver. This supports up to four bus > + channels and operating on standard mode up to 100 kbits/s and fast > + mode up to 400 kbits/s. > > # These settings are not used with DM_I2C, however SPL doesn't use > # DM_I2C even if DM_I2C is enabled, and so might use these settings even > # when main u-boot does not! > if SYS_I2C_MXC && (!DM_I2C || SPL) > config SYS_I2C_MXC_I2C1 > - bool "NXP MXC I2C1" > - help > - Add support for NXP MXC I2C Controller 1. > - Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A > + bool "NXP MXC I2C1" > + help > + Add support for NXP MXC I2C Controller 1. > + Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A > > config SYS_I2C_MXC_I2C2 > - bool "NXP MXC I2C2" > - help > - Add support for NXP MXC I2C Controller 2. > - Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A > + bool "NXP MXC I2C2" > + help > + Add support for NXP MXC I2C Controller 2. > + Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A > > config SYS_I2C_MXC_I2C3 > - bool "NXP MXC I2C3" > - help > - Add support for NXP MXC I2C Controller 3. > - Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A > + bool "NXP MXC I2C3" > + help > + Add support for NXP MXC I2C Controller 3. > + Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A > > config SYS_I2C_MXC_I2C4 > - bool "NXP MXC I2C4" > - help > - Add support for NXP MXC I2C Controller 4. > - Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A > + bool "NXP MXC I2C4" > + help > + Add support for NXP MXC I2C Controller 4. > + Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A > > config SYS_I2C_MXC_I2C5 > - bool "NXP MXC I2C5" > - help > - Add support for NXP MXC I2C Controller 5. > - Required for SoCs which have I2C MXC controller 5 eg LX2160A > + bool "NXP MXC I2C5" > + help > + Add support for NXP MXC I2C Controller 5. > + Required for SoCs which have I2C MXC controller 5 eg LX2160A > > config SYS_I2C_MXC_I2C6 > - bool "NXP MXC I2C6" > - help > - Add support for NXP MXC I2C Controller 6. > - Required for SoCs which have I2C MXC controller 6 eg LX2160A > + bool "NXP MXC I2C6" > + help > + Add support for NXP MXC I2C Controller 6. > + Required for SoCs which have I2C MXC controller 6 eg LX2160A > > config SYS_I2C_MXC_I2C7 > - bool "NXP MXC I2C7" > - help > - Add support for NXP MXC I2C Controller 7. > - Required for SoCs which have I2C MXC controller 7 eg LX2160A > + bool "NXP MXC I2C7" > + help > + Add support for NXP MXC I2C Controller 7. > + Required for SoCs which have I2C MXC controller 7 eg LX2160A > > config SYS_I2C_MXC_I2C8 > - bool "NXP MXC I2C8" > - help > - Add support for NXP MXC I2C Controller 8. > - Required for SoCs which have I2C MXC controller 8 eg LX2160A > + bool "NXP MXC I2C8" > + help > + Add support for NXP MXC I2C Controller 8. > + Required for SoCs which have I2C MXC controller 8 eg LX2160A > endif > > if SYS_I2C_MXC_I2C1 > config SYS_MXC_I2C1_SPEED > - int "I2C Channel 1 speed" > - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > - default 100000 > - help > - MXC I2C Channel 1 speed > + int "I2C Channel 1 speed" > + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > + default 100000 > + help > + MXC I2C Channel 1 speed > > config SYS_MXC_I2C1_SLAVE > - int "I2C1 Slave" > - default 0 > - help > - MXC I2C1 Slave > + int "I2C1 Slave" > + default 0 > + help > + MXC I2C1 Slave > endif > > if SYS_I2C_MXC_I2C2 > config SYS_MXC_I2C2_SPEED > - int "I2C Channel 2 speed" > - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > - default 100000 > - help > - MXC I2C Channel 2 speed > + int "I2C Channel 2 speed" > + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > + default 100000 > + help > + MXC I2C Channel 2 speed > > config SYS_MXC_I2C2_SLAVE > - int "I2C2 Slave" > - default 0 > - help > - MXC I2C2 Slave > + int "I2C2 Slave" > + default 0 > + help > + MXC I2C2 Slave > endif > > if SYS_I2C_MXC_I2C3 > config SYS_MXC_I2C3_SPEED > - int "I2C Channel 3 speed" > - default 100000 > - help > - MXC I2C Channel 3 speed > + int "I2C Channel 3 speed" > + default 100000 > + help > + MXC I2C Channel 3 speed > > config SYS_MXC_I2C3_SLAVE > - int "I2C3 Slave" > - default 0 > - help > - MXC I2C3 Slave > + int "I2C3 Slave" > + default 0 > + help > + MXC I2C3 Slave > endif > > if SYS_I2C_MXC_I2C4 > config SYS_MXC_I2C4_SPEED > - int "I2C Channel 4 speed" > - default 100000 > - help > - MXC I2C Channel 4 speed > + int "I2C Channel 4 speed" > + default 100000 > + help > + MXC I2C Channel 4 speed > > config SYS_MXC_I2C4_SLAVE > - int "I2C4 Slave" > - default 0 > - help > - MXC I2C4 Slave > + int "I2C4 Slave" > + default 0 > + help > + MXC I2C4 Slave > endif > > if SYS_I2C_MXC_I2C5 > config SYS_MXC_I2C5_SPEED > - int "I2C Channel 5 speed" > - default 100000 > - help > - MXC I2C Channel 5 speed > + int "I2C Channel 5 speed" > + default 100000 > + help > + MXC I2C Channel 5 speed > > config SYS_MXC_I2C5_SLAVE > - int "I2C5 Slave" > - default 0 > - help > - MXC I2C5 Slave > + int "I2C5 Slave" > + default 0 > + help > + MXC I2C5 Slave > endif > > if SYS_I2C_MXC_I2C6 > config SYS_MXC_I2C6_SPEED > - int "I2C Channel 6 speed" > - default 100000 > - help > - MXC I2C Channel 6 speed > + int "I2C Channel 6 speed" > + default 100000 > + help > + MXC I2C Channel 6 speed > > config SYS_MXC_I2C6_SLAVE > - int "I2C6 Slave" > - default 0 > - help > - MXC I2C6 Slave > + int "I2C6 Slave" > + default 0 > + help > + MXC I2C6 Slave > endif > > if SYS_I2C_MXC_I2C7 > config SYS_MXC_I2C7_SPEED > - int "I2C Channel 7 speed" > - default 100000 > - help > - MXC I2C Channel 7 speed > + int "I2C Channel 7 speed" > + default 100000 > + help > + MXC I2C Channel 7 speed > > config SYS_MXC_I2C7_SLAVE > - int "I2C7 Slave" > - default 0 > - help > - MXC I2C7 Slave > + int "I2C7 Slave" > + default 0 > + help > + MXC I2C7 Slave > endif > > if SYS_I2C_MXC_I2C8 > config SYS_MXC_I2C8_SPEED > - int "I2C Channel 8 speed" > - default 100000 > - help > - MXC I2C Channel 8 speed > + int "I2C Channel 8 speed" > + default 100000 > + help > + MXC I2C Channel 8 speed > > config SYS_MXC_I2C8_SLAVE > - int "I2C8 Slave" > - default 0 > - help > - MXC I2C8 Slave > + int "I2C8 Slave" > + default 0 > + help > + MXC I2C8 Slave > endif > > config SYS_I2C_OMAP24XX > - bool "TI OMAP2+ I2C driver" > - depends on ARCH_OMAP2PLUS || ARCH_K3 > - help > - Add support for the OMAP2+ I2C driver. > + bool "TI OMAP2+ I2C driver" > + depends on ARCH_OMAP2PLUS || ARCH_K3 > + help > + Add support for the OMAP2+ I2C driver. > > if SYS_I2C_OMAP24XX > config SYS_OMAP24_I2C_SLAVE > - int "I2C Slave addr channel 0" > - default 1 > - help > - OMAP24xx I2C Slave address channel 0 > + int "I2C Slave addr channel 0" > + default 1 > + help > + OMAP24xx I2C Slave address channel 0 > > config SYS_OMAP24_I2C_SPEED > - int "I2C Slave channel 0 speed" > - default 100000 > - help > - OMAP24xx Slave speed channel 0 > + int "I2C Slave channel 0 speed" > + default 100000 > + help > + OMAP24xx Slave speed channel 0 > endif > > config SYS_I2C_RCAR_I2C > - bool "Renesas RCar I2C driver" > - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > - help > - Support for Renesas RCar I2C controller. > + bool "Renesas RCar I2C driver" > + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > + help > + Support for Renesas RCar I2C controller. > > config SYS_I2C_RCAR_IIC > - bool "Renesas RCar Gen3 IIC driver" > - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > - help > - Support for Renesas RCar Gen3 IIC controller. > + bool "Renesas RCar Gen3 IIC driver" > + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > + help > + Support for Renesas RCar Gen3 IIC controller. > > config SYS_I2C_ROCKCHIP > - bool "Rockchip I2C driver" > - depends on DM_I2C > - help > - Add support for the Rockchip I2C driver. This is used with various > - Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips > - have several I2C ports and all are provided, controlled by the > - device tree. > + bool "Rockchip I2C driver" > + depends on DM_I2C > + help > + Add support for the Rockchip I2C driver. This is used with various > + Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips > + have several I2C ports and all are provided, controlled by the > + device tree. > > config SYS_I2C_SANDBOX > - bool "Sandbox I2C driver" > - depends on SANDBOX && DM_I2C > - help > - Enable I2C support for sandbox. This is an emulation of a real I2C > - bus. Devices can be attached to the bus using the device tree > - which specifies the driver to use. See sandbox.dts as an example. > + bool "Sandbox I2C driver" > + depends on SANDBOX && DM_I2C > + help > + Enable I2C support for sandbox. This is an emulation of a real I2C > + bus. Devices can be attached to the bus using the device tree > + which specifies the driver to use. See sandbox.dts as an example. > > config SYS_I2C_S3C24X0 > - bool "Samsung I2C driver" > - depends on ARCH_EXYNOS4 && DM_I2C > - help > - Support for Samsung I2C controller as Samsung SoCs. > + bool "Samsung I2C driver" > + depends on ARCH_EXYNOS4 && DM_I2C > + help > + Support for Samsung I2C controller as Samsung SoCs. > > config SYS_I2C_STM32F7 > - bool "STMicroelectronics STM32F7 I2C support" > - depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C > - help > - Enable this option to add support for STM32 I2C controller > - introduced with STM32F7/H7 SoCs. This I2C controller supports : > - _ Slave and master modes > - _ Multimaster capability > - _ Standard-mode (up to 100 kHz) > - _ Fast-mode (up to 400 kHz) > - _ Fast-mode Plus (up to 1 MHz) > - _ 7-bit and 10-bit addressing mode > - _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) > - _ All 7-bit addresses acknowledge mode > - _ General call > - _ Programmable setup and hold times > - _ Easy to use event management > - _ Optional clock stretching > - _ Software reset > + bool "STMicroelectronics STM32F7 I2C support" > + depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C > + help > + Enable this option to add support for STM32 I2C controller > + introduced with STM32F7/H7 SoCs. This I2C controller supports : > + _ Slave and master modes > + _ Multimaster capability > + _ Standard-mode (up to 100 kHz) > + _ Fast-mode (up to 400 kHz) > + _ Fast-mode Plus (up to 1 MHz) > + _ 7-bit and 10-bit addressing mode > + _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) > + _ All 7-bit addresses acknowledge mode > + _ General call > + _ Programmable setup and hold times > + _ Easy to use event management > + _ Optional clock stretching > + _ Software reset > > config SYS_I2C_TEGRA > - bool "NVIDIA Tegra internal I2C controller" > - depends on TEGRA > - help > - Support for NVIDIA I2C controller available in Tegra SoCs. > + bool "NVIDIA Tegra internal I2C controller" > + depends on TEGRA > + help > + Support for NVIDIA I2C controller available in Tegra SoCs. > > config SYS_I2C_UNIPHIER > - bool "UniPhier I2C driver" > - depends on ARCH_UNIPHIER && DM_I2C > - default y > - help > - Support for UniPhier I2C controller driver. This I2C controller > - is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. > + bool "UniPhier I2C driver" > + depends on ARCH_UNIPHIER && DM_I2C > + default y > + help > + Support for UniPhier I2C controller driver. This I2C controller > + is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. > > config SYS_I2C_UNIPHIER_F > - bool "UniPhier FIFO-builtin I2C driver" > - depends on ARCH_UNIPHIER && DM_I2C > - default y > - help > - Support for UniPhier FIFO-builtin I2C controller driver. > - This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > + bool "UniPhier FIFO-builtin I2C driver" > + depends on ARCH_UNIPHIER && DM_I2C > + default y > + help > + Support for UniPhier FIFO-builtin I2C controller driver. > + This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > > config SYS_I2C_VERSATILE > - bool "Arm Ltd Versatile I2C bus driver" > - depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) > - help > - Add support for the Arm Ltd Versatile Express I2C driver. The I2C host > - controller is present in the development boards manufactured by Arm Ltd. > + bool "Arm Ltd Versatile I2C bus driver" > + depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) > + help > + Add support for the Arm Ltd Versatile Express I2C driver. The I2C host > + controller is present in the development boards manufactured by Arm Ltd. > > config SYS_I2C_MVTWSI > - bool "Marvell I2C driver" > - depends on DM_I2C > - help > - Support for Marvell I2C controllers as used on the orion5x and > - kirkwood SoC families. > + bool "Marvell I2C driver" > + depends on DM_I2C > + help > + Support for Marvell I2C controllers as used on the orion5x and > + kirkwood SoC families. > > config TEGRA186_BPMP_I2C > - bool "Enable Tegra186 BPMP-based I2C driver" > - depends on TEGRA186_BPMP > - help > - Support for Tegra I2C controllers managed by the BPMP (Boot and > - Power Management Processor). On Tegra186, some I2C controllers are > - directly controlled by the main CPU, whereas others are controlled > - by the BPMP, and can only be accessed by the main CPU via IPC > - requests to the BPMP. This driver covers the latter case. > + bool "Enable Tegra186 BPMP-based I2C driver" > + depends on TEGRA186_BPMP > + help > + Support for Tegra I2C controllers managed by the BPMP (Boot and > + Power Management Processor). On Tegra186, some I2C controllers are > + directly controlled by the main CPU, whereas others are controlled > + by the BPMP, and can only be accessed by the main CPU via IPC > + requests to the BPMP. This driver covers the latter case. > > config SYS_I2C_BUS_MAX > - int "Max I2C busses" > - depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA > - default 2 if TI816X > - default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE > - default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X > - default 5 if OMAP54XX > - help > - Define the maximum number of available I2C buses. > + int "Max I2C busses" > + depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA > + default 2 if TI816X > + default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE > + default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X > + default 5 if OMAP54XX > + help > + Define the maximum number of available I2C buses. > > config SYS_I2C_XILINX_XIIC > - bool "Xilinx AXI I2C driver" > - depends on DM_I2C > - help > - Support for Xilinx AXI I2C controller. > + bool "Xilinx AXI I2C driver" > + depends on DM_I2C > + help > + Support for Xilinx AXI I2C controller. > > config SYS_I2C_IHS > bool "gdsys IHS I2C driver" > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > index c2f75d8755..7cfe68e088 100644 > --- a/drivers/i2c/Makefile > +++ b/drivers/i2c/Makefile > @@ -38,5 +38,5 @@ obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o > obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o > obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o > obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o > - > +obj-$(CONFIG_IPROC_I2C) += iproc_i2c.o please keep lists sorted! (Same applies to your "drivers: pcie: Add Broadcom IPROC PCIe driver" patch) > obj-$(CONFIG_I2C_MUX) += muxes/ > diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c > new file mode 100644 > index 0000000000..692035666c > --- /dev/null > +++ b/drivers/i2c/iproc_i2c.c > @@ -0,0 +1,765 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C)) 2018 Broadcom > + */ > + > +#include <common.h> > +#include <config.h> > +#include <dm.h> > +#include <i2c.h> > +#include <asm/io.h> > +#include "errno.h" > +#include "iproc_i2c.h" > + > +DECLARE_GLOBAL_DATA_PTR; > + > +static int i2c_init_done; > + > +struct iproc_i2c_regs { > + u32 cfg_reg; > + u32 timg_cfg; > + u32 addr_reg; > + u32 mstr_fifo_ctrl; > + u32 slv_fifo_ctrl; > + u32 bitbng_ctrl; > + u32 blnks[6]; /* Not to be used */ > + u32 mstr_cmd; > + u32 slv_cmd; > + u32 evt_en; > + u32 evt_sts; > + u32 mstr_datawr; > + u32 mstr_datard; > + u32 slv_datawr; > + u32 slv_datard; > +}; > + > +struct iproc_i2c { > + struct iproc_i2c_regs __iomem *base; /* register base */ > + int bus_speed; > +}; > + > +/* Function to read a value from specified register. */ > +static unsigned int iproc_i2c_reg_read(u32 *reg_addr) > +{ > + unsigned int val; > + > + val = readl((void *)(reg_addr)); > + return cpu_to_le32(val); > +} > + > +/* Function to write a value ('val') in to a specified register. */ > +static int iproc_i2c_reg_write(u32 *reg_addr, unsigned int val) > +{ > + val = cpu_to_le32(val); > + writel(val, (void *)(reg_addr)); > + return 0; > +} > + > +#ifdef IPROC_I2C_DBG Can you add this define at least through Kconfig ? Do we need this define? debug() should be dropped if DEBUG is not defined... and you can do here #if defined(DEBUG) static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) [...] #else static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata){ return 0; } #endif and drop all later "ifdef IPROC_I2C_DBG" stuff... > +static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + unsigned int regval; > + > + debug("\n----------------------------------------------\n"); > + debug("%s: Dumping SMBus registers...\n", __func__); > + > + regval = iproc_i2c_reg_read(&base->cfg_reg); > + debug("CCB_SMB_CFG_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->timg_cfg); > + debug("CCB_SMB_TIMGCFG_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->addr_reg); > + debug("CCB_SMB_ADDR_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->mstr_fifo_ctrl); > + debug("CCB_SMB_MSTRFIFOCTL_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->slv_fifo_ctrl); > + debug("CCB_SMB_SLVFIFOCTL_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->bitbng_ctrl); > + debug("CCB_SMB_BITBANGCTL_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + debug("CCB_SMB_MSTRCMD_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->slv_cmd); > + debug("CCB_SMB_SLVCMD_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->evt_en); > + debug("CCB_SMB_EVTEN_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->evt_sts); > + debug("CCB_SMB_EVTSTS_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->mstr_datawr); > + debug("CCB_SMB_MSTRDATAWR_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->mstr_datard); > + debug("CCB_SMB_MSTRDATARD_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->slv_datawr); > + debug("CCB_SMB_SLVDATAWR_REG=0x%08X\n", regval); > + > + regval = iproc_i2c_reg_read(&base->slv_datard); > + debug("CCB_SMB_SLVDATARD_REG=0x%08X\n", regval); > + > + debug("----------------------------------------------\n\n"); > + return 0; > +} > +#endif > + > +/* > + * Function to ensure that the previous transaction was completed before > + * initiating a new transaction. It can also be used in polling mode to > + * check status of completion of a command > + */ > +static int iproc_i2c_startbusy_wait(struct iproc_i2c *bus_prvdata) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + unsigned int regval; > + > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + > + /* Check if an operation is in progress. During probe it won't be. > + * But when shutdown/remove was called we want to make sure that > + * the transaction in progress completed > + */ > + if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > + unsigned int i = 0; > + > + do { > + mdelay(10); /* Wait for 10 msec */ Please remove this comment. > + i++; > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + > + /* If start-busy bit cleared, exit the loop */ > + } while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) && > + (i < IPROC_SMB_MAX_RETRIES)); > + > + if (i >= IPROC_SMB_MAX_RETRIES) { > + pr_err("%s: START_BUSY bit didn't clear, exiting\n", > + __func__); > + > + return -ETIMEDOUT; > + } > + } > + return 0; > +} > + > +/* > + * This function set clock frequency for SMBus block. As per hardware > + * engineering, the clock frequency can be changed dynamically. > + */ > +static int iproc_i2c_set_clk_freq(struct iproc_i2c *bus_prvdata) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + unsigned int regval; > + > + regval = iproc_i2c_reg_read(&base->timg_cfg); > + > + switch (bus_prvdata->bus_speed) { > + case I2C_SPEED_100KHZ: > + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_100, > + CCB_SMB_TIMGCFG_MODE400_MASK, > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > + break; > + > + case I2C_SPEED_400KHZ: > + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_400, > + CCB_SMB_TIMGCFG_MODE400_MASK, > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > + break; > + > + default: > + return -EINVAL; > + } > + > + iproc_i2c_reg_write(&base->timg_cfg, regval); > + return 0; > +} > + > +static int iproc_i2c_init(struct iproc_i2c *bus_prvdata) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + unsigned int regval; > + > +#ifdef IPROC_I2C_DBG > + debug("\n%s: Entering", __func__); > +#endif /* IPROC_I2C_DBG */ > + > + /* Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0. > + * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts > + */ > + regval = CCB_SMB_MSTRRXFIFOFLSH_MASK | CCB_SMB_MSTRTXFIFOFLSH_MASK; > + iproc_i2c_reg_write(&base->mstr_fifo_ctrl, regval); > + > + /* Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero > + * since there will be only one master > + */ > + > + regval = iproc_i2c_reg_read(&base->cfg_reg); > + regval |= CCB_SMB_CFG_SMBEN_MASK; > + iproc_i2c_reg_write(&base->cfg_reg, regval); > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) What are this defines? Wbere come they from ? They are not in current mainline code: pollux:u-boot hs [work] $ grep -lr CONFIG_CYGNUS . ./mbox pollux:u-boot hs [work] $ grep -lr BCMOMEGA . ./mbox pollux:u-boot hs [work] $ please remove this code. Also this seems board specific code. We should prevent this in common driver code! > + regval = iproc_i2c_reg_read(&base->cfg_reg); > + regval |= CCB_SMB_CFG_RST_MASK; > + iproc_i2c_reg_write(&base->cfg_reg, regval); > + regval &= ~CCB_SMB_CFG_RST_MASK; > + iproc_i2c_reg_write(&base->cfg_reg, regval); > +#endif > + /* Wait a minimum of 50 Usec, as per SMB hw doc */ > + udelay(50); linux driver waits here for 100usec ... with the comment "per spec" ... and flushes the FIFO after ... but I have no insight into this hardware, so cannot say, what the better procedure... > + > + /* Set default clock frequency */ > + iproc_i2c_set_clk_freq(bus_prvdata); > + > + /* Disable intrs */ > + iproc_i2c_reg_write(&base->evt_en, 0); > + > + /* Clear intrs (W1TC) */ > + regval = iproc_i2c_reg_read(&base->evt_sts); > + iproc_i2c_reg_write(&base->evt_sts, regval); > + > + i2c_init_done = 1; Why you need this global variable ? Please store this variable in "iproc_i2c" > + > +#ifdef IPROC_I2C_DBG > + iproc_dump_i2c_regs(bus_prvdata); > + > + debug("%s: Init successful\n", __func__); > +#endif /* IPROC_I2C_DBG */ > + > + return 0; > +} > + > +/* > + * This function copies data to SMBus's Tx FIFO. Valid for write transactions > + * only > + * > + * base_addr: Mapped address of this SMBus instance > + * dev_addr: SMBus (I2C) device address. We are assuming 7-bit addresses > + * initially > + * info: Data to copy in to Tx FIFO. For read commands, the size should be > + * set to zero by the caller > + * > + */ > +static void iproc_i2c_write_trans_data(struct iproc_i2c *bus_prvdata, > + unsigned short dev_addr, > + struct iproc_xact_info *info) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + unsigned int regval; > + unsigned int i; > + unsigned int num_data_bytes = 0; > + > +#ifdef IPROC_I2C_DBG > + debug("%s: dev_addr=0x%X cmd_valid=%d cmd=0x%02x size=%u proto=%d\n" > + "buf[] %x\n", > + __func__, > + dev_addr, > + info->cmd_valid, > + info->command, > + info->size, > + info->smb_proto, > + info->data[0]); > +#endif /* IPROC_I2C_DBG */ > + > + /* Write SMBus device address first */ > + /* Note, we are assuming 7-bit addresses for now. For 10-bit addresses, > + * we may have one more write to send the upper 3 bits of 10-bit addr > + */ > + iproc_i2c_reg_write(&base->mstr_datawr, dev_addr); > + > + /* If the protocol needs command code, copy it */ > + if (info->cmd_valid) > + iproc_i2c_reg_write(&base->mstr_datawr, info->command); > + > + /* Depending on the SMBus protocol, we need to write additional > + * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus > + * spec for sequence for a transaction > + */ > + switch (info->smb_proto) { > + case SMBUS_PROT_RECV_BYTE: > + /* No additional data to be written */ > + num_data_bytes = 0; > + break; > + > + case SMBUS_PROT_SEND_BYTE: > + num_data_bytes = info->size; > + break; > + > + case SMBUS_PROT_RD_BYTE: > + case SMBUS_PROT_RD_WORD: > + case SMBUS_PROT_BLK_RD: > + /* Write slave address with R/W~ set (bit #0) */ > + iproc_i2c_reg_write(&base->mstr_datawr, > + dev_addr | 0x1); > + num_data_bytes = 0; > + break; > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > + case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL: > + iproc_i2c_reg_write(&base->mstr_datawr, > + dev_addr | 0x1 | > + CCB_SMB_MSTRWRSTS_MASK); > + num_data_bytes = 0; > + break; > +#endif > + case SMBUS_PROT_WR_BYTE: > + case SMBUS_PROT_WR_WORD: > + /* No additional bytes to be written. > + * Data portion is written in the > + * 'for' loop below > + */ > + num_data_bytes = info->size; > + break; > + > + case SMBUS_PROT_BLK_WR: > + /* 3rd byte is byte count */ > + iproc_i2c_reg_write(&base->mstr_datawr, info->size); > + num_data_bytes = info->size; > + break; > + > + default: > + break; > + } > + > + /* Copy actual data from caller, next. In general, for reads, no data is > + * copied > + */ > + for (i = 0; num_data_bytes; --num_data_bytes, i++) { > + /* For the last byte, set MASTER_WR_STATUS bit */ > + regval = (num_data_bytes == 1) ? > + info->data[i] | CCB_SMB_MSTRWRSTS_MASK : > + info->data[i]; > + > + iproc_i2c_reg_write(&base->mstr_datawr, regval); > + } > +} > + > +static int iproc_i2c_data_send(struct iproc_i2c *bus_prvdata, > + unsigned short addr, > + struct iproc_xact_info *info) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + int rc, retry = 3; unsigned int regval; > + > + /* Make sure the previous transaction completed */ > + rc = iproc_i2c_startbusy_wait(bus_prvdata); > + > + if (rc < 0) { > + pr_err("%s: Send: bus is busy, exiting\n", __func__); > + return rc; > + } > + > + /* Write transaction bytes to Tx FIFO */ > + iproc_i2c_write_trans_data(bus_prvdata, addr, info); > + > + /* Program master command register (0x30) with protocol type and set > + * start_busy_command bit to initiate the write transaction > + */ > + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > + CCB_SMB_MSTRSTARTBUSYCMD_MASK; > + > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > + > + /* Check for Master status */ > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > + mdelay(10); > + if (retry-- <= 0) > + break; > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + } > + > + /* If start_busy bit cleared, check if there are any errors */ > + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { > + /* start_busy bit cleared, check master_status field now */ > + regval &= CCB_SMB_MSTRSTS_MASK; > + regval >>= CCB_SMB_MSTRSTS_SHIFT; > + > + if (regval != MSTR_STS_XACT_SUCCESS) { > + /* Error We can flush Tx FIFO here */ > + pr_err("%s: ERROR: Error in transaction %u, exiting\n", > + __func__, regval); > + return -EREMOTEIO; > + } > + } > + > + return 0; > +} > + > +static int iproc_i2c_data_recv(struct iproc_i2c *bus_prvdata, > + unsigned short addr, > + struct iproc_xact_info *info, > + unsigned int *num_bytes_read) > +{ > + struct iproc_i2c_regs *base = bus_prvdata->base; > + int rc, retry = 3; > + unsigned int regval; > + > + /* Make sure the previous transaction completed */ > + rc = iproc_i2c_startbusy_wait(bus_prvdata); > + > + if (rc < 0) { > + pr_err("%s: Receive: Bus is busy, exiting\n", __func__); > + return rc; > + } > + > + /* Program all transaction bytes into master Tx FIFO */ > + iproc_i2c_write_trans_data(bus_prvdata, addr, info); > + > + /* Program master command register (0x30) with protocol type and set > + * start_busy_command bit to initiate the write transaction > + */ > + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > + CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size; > + > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > + > + /* Check for Master status */ > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > + udelay(1000); > + if (retry-- <= 0) > + break; > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + } > + > + /* If start_busy bit cleared, check if there are any errors */ > + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { > + /* start_busy bit cleared, check master_status field now */ > + regval &= CCB_SMB_MSTRSTS_MASK; > + regval >>= CCB_SMB_MSTRSTS_SHIFT; > + > + if (regval != MSTR_STS_XACT_SUCCESS) { > + /* We can flush Tx FIFO here */ > + pr_err("%s: Error in transaction %d, exiting\n", > + __func__, regval); > + return -EREMOTEIO; > + } > + } > + > + /* Read received byte(s), after TX out address etc */ > + regval = iproc_i2c_reg_read(&base->mstr_datard); > + > + /* For block read, protocol (hw) returns byte count, > + * as the first byte > + */ > + if (info->smb_proto == SMBUS_PROT_BLK_RD) { > + int i; > + > + *num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK; > + > + /* Limit to reading a max of 32 bytes only; just a safeguard. > + * If # bytes read is a number > 32, check transaction set up, > + * and contact hw engg. Assumption: PEC is disabled > + */ > + for (i = 0; > + (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX); > + i++) { > + /* Read Rx FIFO for data bytes */ > + regval = iproc_i2c_reg_read(&base->mstr_datard); > + info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK; > + } > + } else { > + /* 1 Byte data */ > + *info->data = regval & CCB_SMB_MSTRRDDATA_MASK; > + *num_bytes_read = 1; > + } > + > + return 0; > +} > + > +static int i2c_write_byte(struct iproc_i2c *bus_prvdata, > + u8 devaddr, > + u8 regoffset, > + u8 value) > +{ > + int rc; > + struct iproc_xact_info info; > + > + devaddr <<= 1; > + > + info.cmd_valid = 1; > + info.command = (unsigned char)regoffset; > + info.data = &value; > + info.size = 1; > + info.flags = 0; > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) unknown defines ... > + info.smb_proto = SMBUS_PROT_WR_WORD;/*SMBUS_PROT_WR_BYTE;*/ > +#else > + info.smb_proto = SMBUS_PROT_WR_BYTE; > +#endif > + /* Refer to i2c_smbus_write_byte params passed. */ > + rc = iproc_i2c_data_send(bus_prvdata, devaddr, &info); > + > + if (rc < 0) { > + pr_err("%s: %s error accessing device 0x%X\n", > + __func__, "Write", devaddr); > + return -EREMOTEIO; > + } > + > + return 0; > +} > + > +int i2c_write(struct iproc_i2c *bus_prvdata, > + uchar chip, > + uint regaddr, > + int alen, > + uchar *buffer, > + int len) > +{ > + int i, data_len; > + u8 *data; > + > + if (alen > 1) { > + pr_err("I2C write: addr len %d not supported\n", alen); > + return 1; > + } > + > + if (regaddr + len > 256) { > + pr_err("I2C write: address out of range\n"); > + return 1; > + } > + > + if (len < 1) { > + pr_err("I2C write: Need offset addr and value\n"); > + return 1; > + } > + > + /* buffer contains offset addr followed by value to be written */ > + regaddr = buffer[0]; > + data = &buffer[1]; > + data_len = len - 1; > + > + for (i = 0; i < data_len; i++) { > + if (i2c_write_byte(bus_prvdata, chip, regaddr + i, data[i])) { > + pr_err("I2C write (%d): I/O error\n", i); > + iproc_i2c_init(bus_prvdata); > + return 1; > + } > + } > + > + return 0; > +} > + > +static int i2c_read_byte(struct iproc_i2c *bus_prvdata, > + u8 devaddr, > + u8 regoffset, > + u8 *value) > +{ > + int rc; > + struct iproc_xact_info info; > + unsigned int num_bytes_read = 0; > + > + devaddr <<= 1; > + > + info.cmd_valid = 1; > + info.command = (unsigned char)regoffset; > + info.data = value; > + info.size = 1; > + info.flags = 0; > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > + info.smb_proto = SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL; > +#else > + info.smb_proto = SMBUS_PROT_RD_BYTE; > +#endif > + /* Refer to i2c_smbus_read_byte for params passed. */ > + rc = iproc_i2c_data_recv(bus_prvdata, devaddr, &info, &num_bytes_read); > + > + if (rc < 0) { > + pr_err("%s: %s error accessing device 0x%X\n", > + __func__, "Read", devaddr); > + return -EREMOTEIO; > + } > + > + return 0; > +} > + > +int i2c_read(struct iproc_i2c *bus_prvdata, > + uchar chip, > + uint addr, > + int alen, > + uchar *buffer, > + int len) > +{ > + int i; > + > + if (alen > 1) { > + pr_err("I2C read: addr len %d not supported\n", alen); > + return 1; > + } > + > + if (addr + len > 256) { > + pr_err("I2C read: address out of range\n"); > + return 1; > + } You always pass addr = 0 and alen = 0 ... so this checks are useless (beside len check) same for i2c_write ... > + > + for (i = 0; i < len; i++) { > + if (i2c_read_byte(bus_prvdata, chip, addr + i, &buffer[i])) { > + pr_err("I2C read: I/O error\n"); > + iproc_i2c_init(bus_prvdata); > + return 1; > + } > + } > + > + return 0; > +} > + > +static int iproc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) > +{ > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > + int ret = 0; > + > +#ifdef IPROC_I2C_DBG > + debug("%s: %d messages\n", __func__, nmsgs); > +#endif > + > + for (; nmsgs > 0; nmsgs--, msg++) { > + if (msg->flags & I2C_M_RD) > + ret = i2c_read(bus_prvdata, > + msg->addr, > + 0, > + 0, > + msg->buf, > + msg->len); > + else > + ret = i2c_write(bus_prvdata, > + msg->addr, > + 0, > + 0, > + msg->buf, > + msg->len); > + } > + > + return ret; > +} > + > +static int iproc_i2c_probe_chip(struct udevice *bus, uint chip_addr, > + uint chip_flags) > +{ > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > + struct iproc_i2c_regs *base = bus_prvdata->base; > + u32 regval; > + > +#ifdef IPROC_I2C_DBG > + debug("\n%s: Entering chip probe\n", __func__); > +#endif /* IPROC_I2C_DBG */ > + > + /* Init internal regs, disable intrs (and then clear intrs), set fifo > + * thresholds, etc. > + */ > + if (!i2c_init_done) > + iproc_i2c_init(bus_prvdata); Couldn;t you store this "i2c_init_done" in bus_prvdata ? > + > + regval = (chip_addr << 1); > + iproc_i2c_reg_write(&base->mstr_datawr, regval); > + regval = ((SMBUS_PROT_QUICK_CMD << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > + (1 << CCB_SMB_MSTRSTARTBUSYCMD_SHIFT)); > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > + > + do { > + udelay(100); Is this delay somewhere described in a spec? > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + regval &= CCB_SMB_MSTRSTARTBUSYCMD_MASK; > + } while (regval); > + > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > + > + if ((regval & CCB_SMB_MSTRSTS_MASK) != 0) > + return -1; > + > +#ifdef IPROC_I2C_DBG > + iproc_dump_i2c_regs(bus_prvdata); > + > + debug("%s: chip probe successful\n", __func__); > +#endif /* IPROC_I2C_DBG */ > + > + return 0; > +} > + > +static int iproc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) > +{ > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > + > + bus_prvdata->bus_speed = speed; > + if (iproc_i2c_set_clk_freq(bus_prvdata)) > + return -EINVAL; couldn; t you return simply the return value from iproc_i2c_set_clk_freq()? > + > + return 0; > +} > + > +/** > + * i2c_get_bus_speed - get i2c bus speed > + * > + * This function returns the speed of operation in Hz > + */ > +int iproc_i2c_get_bus_speed(struct udevice *bus) > +{ > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > + struct iproc_i2c_regs *base = bus_prvdata->base; > + unsigned int regval; > + unsigned int val; > + > + regval = iproc_i2c_reg_read(&base->timg_cfg); > + val = GETREGFLDVAL(regval, CCB_SMB_TIMGCFG_MODE400_MASK, > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > + switch (val) { > + case 0: > + return I2C_SPEED_100KHZ; > + case 1: > + return I2C_SPEED_400KHZ; > + default: > + return -EINVAL; > + } > + return -EINVAL; > +} > + > +static int iproc_i2c_probe(struct udevice *bus) > +{ > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > + > + return iproc_i2c_init(bus_prvdata); > +} > + > +static int iproc_i2c_ofdata_to_platdata(struct udevice *bus) > +{ > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > + int node = dev_of_offset(bus); > + const void *blob = gd->fdt_blob; > + > + bus_prvdata->base = map_physmem(devfdt_get_addr(bus), > + sizeof(void *), > + MAP_NOCACHE); > + > + /* default 100KHz freq */ > + bus_prvdata->bus_speed = fdtdec_get_int(blob, node, "bus-frequency", > + I2C_SPEED_100KHZ); > + > + return 0; > +} > + > +static const struct dm_i2c_ops iproc_i2c_ops = { > + .xfer = iproc_i2c_xfer, > + .probe_chip = iproc_i2c_probe_chip, > + .set_bus_speed = iproc_i2c_set_bus_speed, > + .get_bus_speed = iproc_i2c_get_bus_speed, > +}; > + > +static const struct udevice_id iproc_i2c_ids[] = { > + { .compatible = "brcm,iproc-i2c" }, > + { } > +}; > + > +U_BOOT_DRIVER(iproc_i2c) = { > + .name = "iproc_i2c", > + .id = UCLASS_I2C, > + .of_match = iproc_i2c_ids, > + .ofdata_to_platdata = iproc_i2c_ofdata_to_platdata, > + .probe = iproc_i2c_probe, > + .priv_auto_alloc_size = sizeof(struct iproc_i2c), > + .ops = &iproc_i2c_ops, > + .flags = DM_FLAG_PRE_RELOC, > +}; > diff --git a/drivers/i2c/iproc_i2c.h b/drivers/i2c/iproc_i2c.h > new file mode 100644 > index 0000000000..4f8d6ba2b2 > --- /dev/null > +++ b/drivers/i2c/iproc_i2c.h > @@ -0,0 +1,356 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* Copyright (C) 2018 Broadcom */ > + > +#ifndef __IPROC_I2C_H__ > +#define __IPROC_I2C_H__ > + > +#if (defined(CONFIG_NS_PLUS) || defined(CONFIG_HELIX4)) again defines not in mainline! Please remove! > +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 > +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 > +#define IPROC_SMBUS_BASE_ADDR1 0x18038000 > +#define IPROC_SMBUS_BASE_ADDR2 0x1803B000 > +#elif (defined(CONFIG_CYGNUS)) > +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 > +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 > +#define IPROC_SMBUS_BASE_ADDR1 0x18008000 > +#define IPROC_SMBUS_BASE_ADDR2 0x1800B000 > +#endif Hmm... couldn;t come this values through DTS ? SHADOW_CPY_BUFFER_ADDR1, SHADOW_CPY_BUFFER_ADDR2, IPROC_SMBUS_BASE_ADDR1 and IPROC_SMBUS_BASE_ADDR2 not used in this patch in other places! So please remove this defines complete. > + > +/* Registers */ > +#define CCB_SMB_CFG_REG 0x0 > + > +#define CCB_SMB_CFG_RST_MASK 0x80000000 > +#define CCB_SMB_CFG_RST_SHIFT 31 > + > +#define CCB_SMB_CFG_SMBEN_MASK 0x40000000 > +#define CCB_SMB_CFG_SMBEN_SHIFT 30 > + > +#define CCB_SMB_CFG_BITBANGEN_MASK 0x20000000 > +#define CCB_SMB_CFG_BITBANGEN_SHIFT 29 > + > +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000 > +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28 > + > +#define CCB_SMB_CFG_PROMISCMODE_MASK 0x08000000 > +#define CCB_SMB_CFG_PROMISCMODE_SHIFT 27 > + > +#define CCB_SMB_CFG_TSTMPCNTEN_MASK 0x04000000 > +#define CCB_SMB_CFG_TSTMPCNTEN_SHIFT 26 > + > +#define CCB_SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000 > +#define CCB_SMB_CFG_MSTRRTRYCNT_SHIFT 16 > + > +#define CCB_SMB_TIMGCFG_REG 0x4 > + > +#define CCB_SMB_TIMGCFG_MODE400_MASK 0x80000000 > +#define CCB_SMB_TIMGCFG_MODE400_SHIFT 31 > + > +#define CCB_SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000 > +#define CCB_SMB_TIMGCFG_RNDSLVSTR_SHIFT 24 > + > +#define CCB_SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000 > +#define CCB_SMB_TIMGCFG_PERSLVSTR_SHIFT 16 > + > +#define CCB_SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00 > +#define CCB_SMB_TIMGCFG_IDLTIME_SHIFT 8 > + > +#define CCB_SMB_ADDR_REG 0x8 > + > +#define CCB_SMB_EN_NIC_SMBADDR3_MASK 0x80000000 > +#define CCB_SMB_EN_NIC_SMBADDR3_SHIFT 31 > + > +#define CCB_SMB_NIC_SMBADDR3_MASK 0x7F000000 > +#define CCB_SMB_NIC_SMBADDR3_SHIFT 24 > + > +#define CCB_SMB_EN_NIC_SMBADDR2_MASK 0x00800000 > +#define CCB_SMB_EN_NIC_SMBADDR2_SHIFT 23 > + > +#define CCB_SMB_NIC_SMBADDR2_MASK 0x007F0000 > +#define CCB_SMB_NIC_SMBADDR2_SHIFT 16 > + > +#define CCB_SMB_EN_NIC_SMBADDR1_MASK 0x00008000 > +#define CCB_SMB_EN_NIC_SMBADDR1_SHIFT 15 > + > +#define CCB_SMB_NIC_SMBADDR1_MASK 0x00007F00 > +#define CCB_SMB_NIC_SMBADDR1_SHIFT 8 > + > +#define CCB_SMB_EN_NIC_SMBADDR0_MASK 0x00000080 > +#define CCB_SMB_EN_NIC_SMBADDR0_SHIFT 7 > + > +#define CCB_SMB_NIC_SMBADDR0_MASK 0x0000007F > +#define CCB_SMB_NIC_SMBADDR0_SHIFT 0 > + > +#define CCB_SMB_MSTRFIFOCTL_REG 0xC > + > +#define CCB_SMB_MSTRRXFIFOFLSH_MASK 0x80000000 > +#define CCB_SMB_MSTRRXFIFOFLSH_SHIFT 31 > + > +#define CCB_SMB_MSTRTXFIFOFLSH_MASK 0x40000000 > +#define CCB_SMB_MSTRTXFIFOFLSH_SHIFT 30 > + > +#define CCB_SMB_MSTRRXPKTCNT_MASK 0x007F0000 > +#define CCB_SMB_MSTRRXPKTCNT_SHIFT 16 > + > +#define CCB_SMB_MSTRRXFIFOTHR_MASK 0x00003F00 > +#define CCB_SMB_MSTRRXFIFOTHR_SHIFT 8 > + > +#define CCB_SMB_SLVFIFOCTL_REG 0x10 > + > +#define CCB_SMB_SLVRXFIFOFLSH_MASK 0x80000000 > +#define CCB_SMB_SLVRXFIFOFLSH_SHIFT 31 > + > +#define CCB_SMB_SLVTXFIFOFLSH_MASK 0x40000000 > +#define CCB_SMB_SLVTXFIFOFLSH_SHIFT 30 > + > +#define CCB_SMB_SLVRXPKTCNT_MASK 0x007F0000 > +#define CCB_SMB_SLVRXPKTCNT_SHIFT 16 > + > +#define CCB_SMB_SLVRXFIFOTHR_MASK 0x00003F00 > +#define CCB_SMB_SLVRXFIFOTHR_SHIFT 8 > + > +#define CCB_SMB_BITBANGCTL_REG 0x14 > + > +#define CCB_SMB_SMBCLKIN_MASK 0x80000000 > +#define CCB_SMB_SMBCLKIN_SHIFT 31 > + > +#define CCB_SMB_SMBCLKOUTEN_MASK 0x40000000 > +#define CCB_SMB_SMBCLKOUTEN_SHIFT 30 > + > +#define CCB_SMB_SMBDATAIN_MASK 0x20000000 > +#define CCB_SMB_SMBDATAIN_SHIFT 29 > + > +#define CCB_SMB_SMBDATAOUTEN_MASK 0x10000000 > +#define CCB_SMB_SMBDATAOUTEN_SHIFT 28 > + > +#define CCB_SMB_MSTRCMD_REG 0x30 > + > +#define CCB_SMB_MSTRSTARTBUSYCMD_MASK 0x80000000 > +#define CCB_SMB_MSTRSTARTBUSYCMD_SHIFT 31 > + > +#define CCB_SMB_MSTRABORT_MASK 0x40000000 > +#define CCB_SMB_MSTRABORT_SHIFT 30 > + > +#define CCB_SMB_MSTRSTS_MASK 0x0E000000 > +#define CCB_SMB_MSTRSTS_SHIFT 25 > + > +#define CCB_SMB_MSTRSMBUSPROTO_MASK 0x00001E00 > +#define CCB_SMB_MSTRSMBUSPROTO_SHIFT 9 > + > +#define CCB_SMB_MSTRPEC_MASK 0x00000100 > +#define CCB_SMB_MSTRPEC_SHIFT 8 > + > +#define CCB_SMB_MSTRRDBYTECNT_MASK 0x000000FF > +#define CCB_SMB_MSTRRDBYTECNT_SHIFT 0 > + > +#define CCB_SMB_SLVCMD_REG 0x34 > + > +#define CCB_SMB_SLVSTARTBUSYCMD_MASK 0x80000000 > +#define CCB_SMB_SLVSTARTBUSYCMD_SHIFT 31 > + > +#define CCB_SMB_SLVABORT_MASK 0x40000000 > +#define CCB_SMB_SLVABORT_SHIFT 30 > + > +#define CCB_SMB_SLVSTS_MASK 0x03800000 > +#define CCB_SMB_SLVSTS_SHIFT 23 > + > +#define CCB_SMB_SLVPEC_MASK 0x00000100 > +#define CCB_SMB_SLVPEC_SHIFT 8 > + > +#define CCB_SMB_EVTEN_REG 0x38 > + > +#define CCB_SMB_MSTRRXFIFOFULLEN_MASK 0x80000000 > +#define CCB_SMB_MSTRRXFIFOFULLEN_SHIFT 31 > + > +#define CCB_SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000 > +#define CCB_SMB_MSTRRXFIFOTHRHITEN_SHIFT 30 > + > +#define CCB_SMB_MSTRRXEVTEN_MASK 0x20000000 > +#define CCB_SMB_MSTRRXEVTEN_SHIFT 29 > + > +#define CCB_SMB_MSTRSTARTBUSYEN_MASK 0x10000000 > +#define CCB_SMB_MSTRSTARTBUSYEN_SHIFT 28 > + > +#define CCB_SMB_MSTRTXUNDEN_MASK 0x08000000 > +#define CCB_SMB_MSTRTXUNDEN_SHIFT 27 > + > +#define CCB_SMB_SLVRXFIFOFULLEN_MASK 0x04000000 > +#define CCB_SMB_SLVRXFIFOFULLEN_SHIFT 26 > + > +#define CCB_SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000 > +#define CCB_SMB_SLVRXFIFOTHRHITEN_SHIFT 25 > + > +#define CCB_SMB_SLVRXEVTEN_MASK 0x01000000 > +#define CCB_SMB_SLVRXEVTEN_SHIFT 24 > + > +#define CCB_SMB_SLVSTARTBUSYEN_MASK 0x00800000 > +#define CCB_SMB_SLVSTARTBUSYEN_SHIFT 23 > + > +#define CCB_SMB_SLVTXUNDEN_MASK 0x00400000 > +#define CCB_SMB_SLVTXUNDEN_SHIFT 22 > + > +#define CCB_SMB_SLVRDEVTEN_MASK 0x00200000 > +#define CCB_SMB_SLVRDEVTEN_SHIFT 21 > + > +#define CCB_SMB_EVTSTS_REG 0x3C > + > +#define CCB_SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000 > +#define CCB_SMB_MSTRRXFIFOFULLSTS_SHIFT 31 > + > +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000 > +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30 > + > +#define CCB_SMB_MSTRRXEVTSTS_MASK 0x20000000 > +#define CCB_SMB_MSTRRXEVTSTS_SHIFT 29 > + > +#define CCB_SMB_MSTRSTARTBUSYSTS_MASK 0x10000000 > +#define CCB_SMB_MSTRSTARTBUSYSTS_SHIFT 28 > + > +#define CCB_SMB_MSTRTXUNDSTS_MASK 0x08000000 > +#define CCB_SMB_MSTRTXUNDSTS_SHIFT 27 > + > +#define CCB_SMB_SLVRXFIFOFULLSTS_MASK 0x04000000 > +#define CCB_SMB_SLVRXFIFOFULLSTS_SHIFT 26 > + > +#define CCB_SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000 > +#define CCB_SMB_SLVRXFIFOTHRHITSTS_SHIFT 25 > + > +#define CCB_SMB_SLVRXEVTSTS_MASK 0x01000000 > +#define CCB_SMB_SLVRXEVTSTS_SHIFT 24 > + > +#define CCB_SMB_SLVSTARTBUSYSTS_MASK 0x00800000 > +#define CCB_SMB_SLVSTARTBUSYSTS_SHIFT 23 > + > +#define CCB_SMB_SLVTXUNDSTS_MASK 0x00400000 > +#define CCB_SMB_SLVTXUNDSTS_SHIFT 22 > + > +#define CCB_SMB_SLVRDEVTSTS_MASK 0x00200000 > +#define CCB_SMB_SLVRDEVTSTS_SHIFT 21 > + > +#define CCB_SMB_MSTRDATAWR_REG 0x40 > + > +#define CCB_SMB_MSTRWRSTS_MASK 0x80000000 > +#define CCB_SMB_MSTRWRSTS_SHIFT 31 > + > +#define CCB_SMB_MSTRWRDATA_MASK 0x000000FF > +#define CCB_SMB_MSTRWRDATA_SHIFT 0 > + > +#define CCB_SMB_MSTRDATARD_REG 0x44 > + > +#define CCB_SMB_MSTRRDSTS_MASK 0xC0000000 > +#define CCB_SMB_MSTRRDSTS_SHIFT 30 > + > +#define CCB_SMB_MSTRRDPECERR_MASK 0x20000000 > +#define CCB_SMB_MSTRRDPECERR_SHIFT 29 > + > +#define CCB_SMB_MSTRRDDATA_MASK 0x000000FF > +#define CCB_SMB_MSTRRDDATA_SHIFT 0 > + > +#define CCB_SMB_SLVDATAWR_REG 0x48 > + > +#define CCB_SMB_SLVWRSTS_MASK 0x80000000 > +#define CCB_SMB_SLVWRSTS_SHIFT 31 > + > +#define CCB_SMB_SLVWRDATA_MASK 0x000000FF > +#define CCB_SMB_SLVWRDATA_SHIFT 0 > + > +#define CCB_SMB_SLVDATARD_REG 0x4C > + > +#define CCB_SMB_SLVRDSTS_MASK 0xC0000000 > +#define CCB_SMB_SLVRDSTS_SHIFT 30 > + > +#define CCB_SMB_SLVRDERRSTS_MASK 0x30000000 > +#define CCB_SMB_SLVRDERRSTS_SHIFT 28 > + > +#define CCB_SMB_SLVRDDATA_MASK 0x000000FF > +#define CCB_SMB_SLVRDDATA_SHIFT 0 > + > +/* --Registers-- */ > + > +/* Transaction error codes defined in Master command register (0x30) */ > +#define MSTR_STS_XACT_SUCCESS 0 > +#define MSTR_STS_LOST_ARB 1 > +#define MSTR_STS_NACK_FIRST_BYTE 2 > + > +/* NACK on a byte other than > + * the first byte > + */ > +#define MSTR_STS_NACK_NON_FIRST_BYTE 3 > + > +#define MSTR_STS_TTIMEOUT_EXCEEDED 4 > +#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5 > +#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6 > + > +/* SMBUS protocol values defined in register 0x30 */ > +#define SMBUS_PROT_QUICK_CMD 0 > +#define SMBUS_PROT_SEND_BYTE 1 > +#define SMBUS_PROT_RECV_BYTE 2 > +#define SMBUS_PROT_WR_BYTE 3 > +#define SMBUS_PROT_RD_BYTE 4 > +#define SMBUS_PROT_WR_WORD 5 > +#define SMBUS_PROT_RD_WORD 6 > +#define SMBUS_PROT_BLK_WR 7 > +#define SMBUS_PROT_BLK_RD 8 > +#define SMBUS_PROT_PROC_CALL 9 > +#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10 > + > +/* SMBUS Block speed mode */ > +#define SMBUS_BLOCK_MODE_100 0 > +#define SMBUS_BLOCK_MODE_400 1 > + > +#define BUS_BUSY_COUNT 100000 /* Number can be changed later */ > +#define IPROC_I2C_INVALID_ADDR 0xFF > +#define IPROC_SMB_MAX_RETRIES 35 > +#define I2C_SMBUS_BLOCK_MAX 32 > +#define GETREGFLDVAL(regval, mask, startbit) \ > + (((regval) & (mask)) >> (startbit)) > +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ > + ((regval) & ~(mask)) | \ > + ((fldval) << (startbit)) checkpatch complains with a warning: CHECK: Macro argument reuse 'regval' - possible side-effects? #1981: FILE: drivers/i2c/iproc_i2c.h:306: +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ + ((regval) & ~(mask)) | \ + ((fldval) << (startbit)) > + > +/* Enum to specify clock speed. The user will provide it during initialization > + * If needed, it can be changed dynamically > + */ > +enum iproc_smb_clk_freq { > + I2C_SPEED_100KHZ = 100000, > + I2C_SPEED_400KHZ = 400000, > + I2C_SPEED_INVALID = 255 > +}; > + > +/* This enum will be used to notify the user of status of a data transfer > + * request > + */ > +enum iproc_smb_error_code { > + I2C_NO_ERR = 0, > + I2C_TIMEOUT_ERR = 1, > + > + /* Invalid parameter(s) passed to the driver */ > + I2C_INVALID_PARAM_ERR = 2, > + > + /* The driver API was called before the present > + * transfer was completed > + */ > + I2C_OPER_IN_PROGRESS = 3, > + > + /* Transfer aborted unexpectedly, for example a NACK > + * received, before last byte was read/written > + */ > + I2C_OPER_ABORT_ERR = 4, > + > + /* Feature or function not supported > + * (e.g., 10-bit addresses, or clock speeds > + * other than 100KHz, 400KHz) > + */ > + I2C_FUNC_NOT_SUPPORTED = 5, > +}; > + > +/* Structure used to pass information to read/write functions. */ > +struct iproc_xact_info { > + unsigned char command; > + unsigned char *data; > + unsigned int size; > + unsigned short flags; /* used for specifying PEC, 10-bit addresses */ > + unsigned char smb_proto; /* SMBus protocol */ > + unsigned int cmd_valid; /* true if command is valid else false */ > +}; > + > +#endif /* __IPROC_I2C_H__ */ >
On Mon, Nov 25, 2019 at 2:05 PM Heiko Schocher <hs@denx.de> wrote: > > Hello Vladimir, > > Am 22.11.2019 um 22:20 schrieb Vladimir Olovyannikov: > > From: Arjun Jyothi <arjun.jyothi@broadcom.com> > > > > Add I2C driver support for Broadcom iproc-based socs. > > > > Signed-off-by: Arjun Jyothi <arjun.jyothi@broadcom.com> > > Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com> > > Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com> > > Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com> > > --- > > drivers/i2c/Kconfig | 623 ++++++++++++++++---------------- > > drivers/i2c/Makefile | 2 +- > > drivers/i2c/iproc_i2c.c | 765 ++++++++++++++++++++++++++++++++++++++++ > > drivers/i2c/iproc_i2c.h | 356 +++++++++++++++++++ > > 4 files changed, 1437 insertions(+), 309 deletions(-) > > create mode 100644 drivers/i2c/iproc_i2c.c > > create mode 100644 drivers/i2c/iproc_i2c.h > > > > diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig > > index 03d2fed341..7a80971b12 100644 > > --- a/drivers/i2c/Kconfig > > +++ b/drivers/i2c/Kconfig > > @@ -5,454 +5,461 @@ > > menu "I2C support" > > > > config DM_I2C > > - bool "Enable Driver Model for I2C drivers" > > - depends on DM > > - help > > - Enable driver model for I2C. The I2C uclass interface: probe, read, > > - write and speed, is implemented with the bus drivers operations, > > - which provide methods for bus setting and data transfer. Each chip > > - device (bus child) info is kept as parent platdata. The interface > > - is defined in include/i2c.h. > > + bool "Enable Driver Model for I2C drivers" > > + depends on DM > > + help > > + Enable driver model for I2C. The I2C uclass interface: probe, read, > > + write and speed, is implemented with the bus drivers operations, > > + which provide methods for bus setting and data transfer. Each chip > > + device (bus child) info is kept as parent platdata. The interface > > + is defined in include/i2c.h. > > This (and a lot of following) change removes tabs with spaces, NACK. > > Please do not remove the tabs! > > > config I2C_CROS_EC_TUNNEL > > - tristate "Chrome OS EC tunnel I2C bus" > > - depends on CROS_EC > > - help > > - This provides an I2C bus that will tunnel i2c commands through to > > - the other side of the Chrome OS EC to the I2C bus connected there. > > - This will work whatever the interface used to talk to the EC (SPI, > > - I2C or LPC). Some Chromebooks use this when the hardware design > > - does not allow direct access to the main PMIC from the AP. > > + tristate "Chrome OS EC tunnel I2C bus" > > + depends on CROS_EC > > + help > > + This provides an I2C bus that will tunnel i2c commands through to > > + the other side of the Chrome OS EC to the I2C bus connected there. > > + This will work whatever the interface used to talk to the EC (SPI, > > + I2C or LPC). Some Chromebooks use this when the hardware design > > + does not allow direct access to the main PMIC from the AP. > > > > config I2C_CROS_EC_LDO > > - bool "Provide access to LDOs on the Chrome OS EC" > > - depends on CROS_EC > > - ---help--- > > - On many Chromebooks the main PMIC is inaccessible to the AP. This is > > - often dealt with by using an I2C pass-through interface provided by > > - the EC. On some unfortunate models (e.g. Spring) the pass-through > > - is not available, and an LDO message is available instead. This > > - option enables a driver which provides very basic access to those > > - regulators, via the EC. We implement this as an I2C bus which > > - emulates just the TPS65090 messages we know about. This is done to > > - avoid duplicating the logic in the TPS65090 regulator driver for > > - enabling/disabling an LDO. > > + bool "Provide access to LDOs on the Chrome OS EC" > > + depends on CROS_EC > > + ---help--- > > + On many Chromebooks the main PMIC is inaccessible to the AP. This is > > + often dealt with by using an I2C pass-through interface provided by > > + the EC. On some unfortunate models (e.g. Spring) the pass-through > > + is not available, and an LDO message is available instead. This > > + option enables a driver which provides very basic access to those > > + regulators, via the EC. We implement this as an I2C bus which > > + emulates just the TPS65090 messages we know about. This is done to > > + avoid duplicating the logic in the TPS65090 regulator driver for > > + enabling/disabling an LDO. > > > > config I2C_SET_DEFAULT_BUS_NUM > > - bool "Set default I2C bus number" > > - depends on DM_I2C > > - help > > - Set default number of I2C bus to be accessed. This option provides > > - behaviour similar to old (i.e. pre DM) I2C bus driver. > > + bool "Set default I2C bus number" > > + depends on DM_I2C > > + help > > + Set default number of I2C bus to be accessed. This option provides > > + behaviour similar to old (i.e. pre DM) I2C bus driver. > > > > config I2C_DEFAULT_BUS_NUMBER > > - hex "I2C default bus number" > > - depends on I2C_SET_DEFAULT_BUS_NUM > > - default 0x0 > > - help > > - Number of default I2C bus to use > > + hex "I2C default bus number" > > + depends on I2C_SET_DEFAULT_BUS_NUM > > + default 0x0 > > + help > > + Number of default I2C bus to use > > > > config DM_I2C_GPIO > > - bool "Enable Driver Model for software emulated I2C bus driver" > > - depends on DM_I2C && DM_GPIO > > - help > > - Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO > > - configuration is given by the device tree. Kernel-style device tree > > - bindings are supported. > > - Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt > > + bool "Enable Driver Model for software emulated I2C bus driver" > > + depends on DM_I2C && DM_GPIO > > + help > > + Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO > > + configuration is given by the device tree. Kernel-style device tree > > + bindings are supported. > > + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt > > > > config SYS_I2C_AT91 > > - bool "Atmel I2C driver" > > - depends on DM_I2C && ARCH_AT91 > > - help > > - Add support for the Atmel I2C driver. A serious problem is that there > > - is no documented way to issue repeated START conditions for more than > > - two messages, as needed to support combined I2C messages. Use the > > - i2c-gpio driver unless your system can cope with this limitation. > > - Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > > + bool "Atmel I2C driver" > > + depends on DM_I2C && ARCH_AT91 > > + help > > + Add support for the Atmel I2C driver. A serious problem is that there > > + is no documented way to issue repeated START conditions for more than > > + two messages, as needed to support combined I2C messages. Use the > > + i2c-gpio driver unless your system can cope with this limitation. > > + Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > > + > > +config IPROC_I2C > > + bool "Broadcom iProc I2C driver" > > + depends on DM_I2C > > + help > > + Add support for Broadcom iProc I2C driver. > > + The driver is used in iProc SoCs. > > > > config SYS_I2C_FSL > > bool "Freescale I2C bus driver" > > depends on DM_I2C > > help > > - Add support for Freescale I2C busses as used on MPC8240, MPC8245, and > > - MPC85xx processors. > > + Add support for Freescale I2C busses as used on MPC8240, MPC8245, and > > + MPC85xx processors. > > > > config SYS_I2C_CADENCE > > - tristate "Cadence I2C Controller" > > - depends on DM_I2C && (ARCH_ZYNQ || ARM64) > > - help > > - Say yes here to select Cadence I2C Host Controller. This controller is > > - e.g. used by Xilinx Zynq. > > + tristate "Cadence I2C Controller" > > + depends on DM_I2C && (ARCH_ZYNQ || ARM64) > > + help > > + Say yes here to select Cadence I2C Host Controller. This controller is > > + e.g. used by Xilinx Zynq. > > > > config SYS_I2C_DAVINCI > > - bool "Davinci I2C Controller" > > - depends on (ARCH_KEYSTONE || ARCH_DAVINCI) > > - help > > - Say yes here to add support for Davinci and Keystone I2C controller > > + bool "Davinci I2C Controller" > > + depends on (ARCH_KEYSTONE || ARCH_DAVINCI) > > + help > > + Say yes here to add support for Davinci and Keystone I2C controller > > > > config SYS_I2C_DW > > - bool "Designware I2C Controller" > > - default n > > - help > > - Say yes here to select the Designware I2C Host Controller. This > > - controller is used in various SoCs, e.g. the ST SPEAr, Altera > > - SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. > > + bool "Designware I2C Controller" > > + default n > > + help > > + Say yes here to select the Designware I2C Host Controller. This > > + controller is used in various SoCs, e.g. the ST SPEAr, Altera > > + SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. > > > > config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED > > - bool "DW I2C Enable Status Register not supported" > > - depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ > > - TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) > > - default y > > - help > > - Some versions of the Designware I2C controller do not support the > > - enable status register. This config option can be enabled in such > > - cases. > > + bool "DW I2C Enable Status Register not supported" > > + depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ > > + TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) > > + default y > > + help > > + Some versions of the Designware I2C controller do not support the > > + enable status register. This config option can be enabled in such > > + cases. > > > > config SYS_I2C_ASPEED > > - bool "Aspeed I2C Controller" > > - depends on DM_I2C && ARCH_ASPEED > > - help > > - Say yes here to select Aspeed I2C Host Controller. The driver > > - supports AST2500 and AST2400 controllers, but is very limited. > > - Only single master mode is supported and only byte-by-byte > > - synchronous reads and writes are supported, no Pool Buffers or DMA. > > + bool "Aspeed I2C Controller" > > + depends on DM_I2C && ARCH_ASPEED > > + help > > + Say yes here to select Aspeed I2C Host Controller. The driver > > + supports AST2500 and AST2400 controllers, but is very limited. > > + Only single master mode is supported and only byte-by-byte > > + synchronous reads and writes are supported, no Pool Buffers or DMA. > > > > config SYS_I2C_INTEL > > - bool "Intel I2C/SMBUS driver" > > - depends on DM_I2C > > - help > > - Add support for the Intel SMBUS driver. So far this driver is just > > - a stub which perhaps some basic init. There is no implementation of > > - the I2C API meaning that any I2C operations will immediately fail > > - for now. > > + bool "Intel I2C/SMBUS driver" > > + depends on DM_I2C > > + help > > + Add support for the Intel SMBUS driver. So far this driver is just > > + a stub which perhaps some basic init. There is no implementation of > > + the I2C API meaning that any I2C operations will immediately fail > > + for now. > > > > config SYS_I2C_IMX_LPI2C > > - bool "NXP i.MX LPI2C driver" > > - help > > - Add support for the NXP i.MX LPI2C driver. > > + bool "NXP i.MX LPI2C driver" > > + help > > + Add support for the NXP i.MX LPI2C driver. > > > > config SYS_I2C_MESON > > - bool "Amlogic Meson I2C driver" > > - depends on DM_I2C && ARCH_MESON > > - help > > - Add support for the I2C controller available in Amlogic Meson > > - SoCs. The controller supports programmable bus speed including > > - standard (100kbits/s) and fast (400kbit/s) speed and allows the > > - software to define a flexible format of the bit streams. It has an > > - internal buffer holding up to 8 bytes for transfers and supports > > - both 7-bit and 10-bit addresses. > > + bool "Amlogic Meson I2C driver" > > + depends on DM_I2C && ARCH_MESON > > + help > > + Add support for the I2C controller available in Amlogic Meson > > + SoCs. The controller supports programmable bus speed including > > + standard (100kbits/s) and fast (400kbit/s) speed and allows the > > + software to define a flexible format of the bit streams. It has an > > + internal buffer holding up to 8 bytes for transfers and supports > > + both 7-bit and 10-bit addresses. > > > > config SYS_I2C_MXC > > - bool "NXP MXC I2C driver" > > - help > > - Add support for the NXP I2C driver. This supports up to four bus > > - channels and operating on standard mode up to 100 kbits/s and fast > > - mode up to 400 kbits/s. > > + bool "NXP MXC I2C driver" > > + help > > + Add support for the NXP I2C driver. This supports up to four bus > > + channels and operating on standard mode up to 100 kbits/s and fast > > + mode up to 400 kbits/s. > > > > # These settings are not used with DM_I2C, however SPL doesn't use > > # DM_I2C even if DM_I2C is enabled, and so might use these settings even > > # when main u-boot does not! > > if SYS_I2C_MXC && (!DM_I2C || SPL) > > config SYS_I2C_MXC_I2C1 > > - bool "NXP MXC I2C1" > > - help > > - Add support for NXP MXC I2C Controller 1. > > - Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A > > + bool "NXP MXC I2C1" > > + help > > + Add support for NXP MXC I2C Controller 1. > > + Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C2 > > - bool "NXP MXC I2C2" > > - help > > - Add support for NXP MXC I2C Controller 2. > > - Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A > > + bool "NXP MXC I2C2" > > + help > > + Add support for NXP MXC I2C Controller 2. > > + Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C3 > > - bool "NXP MXC I2C3" > > - help > > - Add support for NXP MXC I2C Controller 3. > > - Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A > > + bool "NXP MXC I2C3" > > + help > > + Add support for NXP MXC I2C Controller 3. > > + Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C4 > > - bool "NXP MXC I2C4" > > - help > > - Add support for NXP MXC I2C Controller 4. > > - Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A > > + bool "NXP MXC I2C4" > > + help > > + Add support for NXP MXC I2C Controller 4. > > + Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C5 > > - bool "NXP MXC I2C5" > > - help > > - Add support for NXP MXC I2C Controller 5. > > - Required for SoCs which have I2C MXC controller 5 eg LX2160A > > + bool "NXP MXC I2C5" > > + help > > + Add support for NXP MXC I2C Controller 5. > > + Required for SoCs which have I2C MXC controller 5 eg LX2160A > > > > config SYS_I2C_MXC_I2C6 > > - bool "NXP MXC I2C6" > > - help > > - Add support for NXP MXC I2C Controller 6. > > - Required for SoCs which have I2C MXC controller 6 eg LX2160A > > + bool "NXP MXC I2C6" > > + help > > + Add support for NXP MXC I2C Controller 6. > > + Required for SoCs which have I2C MXC controller 6 eg LX2160A > > > > config SYS_I2C_MXC_I2C7 > > - bool "NXP MXC I2C7" > > - help > > - Add support for NXP MXC I2C Controller 7. > > - Required for SoCs which have I2C MXC controller 7 eg LX2160A > > + bool "NXP MXC I2C7" > > + help > > + Add support for NXP MXC I2C Controller 7. > > + Required for SoCs which have I2C MXC controller 7 eg LX2160A > > > > config SYS_I2C_MXC_I2C8 > > - bool "NXP MXC I2C8" > > - help > > - Add support for NXP MXC I2C Controller 8. > > - Required for SoCs which have I2C MXC controller 8 eg LX2160A > > + bool "NXP MXC I2C8" > > + help > > + Add support for NXP MXC I2C Controller 8. > > + Required for SoCs which have I2C MXC controller 8 eg LX2160A > > endif > > > > if SYS_I2C_MXC_I2C1 > > config SYS_MXC_I2C1_SPEED > > - int "I2C Channel 1 speed" > > - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > - default 100000 > > - help > > - MXC I2C Channel 1 speed > > + int "I2C Channel 1 speed" > > + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > + default 100000 > > + help > > + MXC I2C Channel 1 speed > > > > config SYS_MXC_I2C1_SLAVE > > - int "I2C1 Slave" > > - default 0 > > - help > > - MXC I2C1 Slave > > + int "I2C1 Slave" > > + default 0 > > + help > > + MXC I2C1 Slave > > endif > > > > if SYS_I2C_MXC_I2C2 > > config SYS_MXC_I2C2_SPEED > > - int "I2C Channel 2 speed" > > - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > - default 100000 > > - help > > - MXC I2C Channel 2 speed > > + int "I2C Channel 2 speed" > > + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > + default 100000 > > + help > > + MXC I2C Channel 2 speed > > > > config SYS_MXC_I2C2_SLAVE > > - int "I2C2 Slave" > > - default 0 > > - help > > - MXC I2C2 Slave > > + int "I2C2 Slave" > > + default 0 > > + help > > + MXC I2C2 Slave > > endif > > > > if SYS_I2C_MXC_I2C3 > > config SYS_MXC_I2C3_SPEED > > - int "I2C Channel 3 speed" > > - default 100000 > > - help > > - MXC I2C Channel 3 speed > > + int "I2C Channel 3 speed" > > + default 100000 > > + help > > + MXC I2C Channel 3 speed > > > > config SYS_MXC_I2C3_SLAVE > > - int "I2C3 Slave" > > - default 0 > > - help > > - MXC I2C3 Slave > > + int "I2C3 Slave" > > + default 0 > > + help > > + MXC I2C3 Slave > > endif > > > > if SYS_I2C_MXC_I2C4 > > config SYS_MXC_I2C4_SPEED > > - int "I2C Channel 4 speed" > > - default 100000 > > - help > > - MXC I2C Channel 4 speed > > + int "I2C Channel 4 speed" > > + default 100000 > > + help > > + MXC I2C Channel 4 speed > > > > config SYS_MXC_I2C4_SLAVE > > - int "I2C4 Slave" > > - default 0 > > - help > > - MXC I2C4 Slave > > + int "I2C4 Slave" > > + default 0 > > + help > > + MXC I2C4 Slave > > endif > > > > if SYS_I2C_MXC_I2C5 > > config SYS_MXC_I2C5_SPEED > > - int "I2C Channel 5 speed" > > - default 100000 > > - help > > - MXC I2C Channel 5 speed > > + int "I2C Channel 5 speed" > > + default 100000 > > + help > > + MXC I2C Channel 5 speed > > > > config SYS_MXC_I2C5_SLAVE > > - int "I2C5 Slave" > > - default 0 > > - help > > - MXC I2C5 Slave > > + int "I2C5 Slave" > > + default 0 > > + help > > + MXC I2C5 Slave > > endif > > > > if SYS_I2C_MXC_I2C6 > > config SYS_MXC_I2C6_SPEED > > - int "I2C Channel 6 speed" > > - default 100000 > > - help > > - MXC I2C Channel 6 speed > > + int "I2C Channel 6 speed" > > + default 100000 > > + help > > + MXC I2C Channel 6 speed > > > > config SYS_MXC_I2C6_SLAVE > > - int "I2C6 Slave" > > - default 0 > > - help > > - MXC I2C6 Slave > > + int "I2C6 Slave" > > + default 0 > > + help > > + MXC I2C6 Slave > > endif > > > > if SYS_I2C_MXC_I2C7 > > config SYS_MXC_I2C7_SPEED > > - int "I2C Channel 7 speed" > > - default 100000 > > - help > > - MXC I2C Channel 7 speed > > + int "I2C Channel 7 speed" > > + default 100000 > > + help > > + MXC I2C Channel 7 speed > > > > config SYS_MXC_I2C7_SLAVE > > - int "I2C7 Slave" > > - default 0 > > - help > > - MXC I2C7 Slave > > + int "I2C7 Slave" > > + default 0 > > + help > > + MXC I2C7 Slave > > endif > > > > if SYS_I2C_MXC_I2C8 > > config SYS_MXC_I2C8_SPEED > > - int "I2C Channel 8 speed" > > - default 100000 > > - help > > - MXC I2C Channel 8 speed > > + int "I2C Channel 8 speed" > > + default 100000 > > + help > > + MXC I2C Channel 8 speed > > > > config SYS_MXC_I2C8_SLAVE > > - int "I2C8 Slave" > > - default 0 > > - help > > - MXC I2C8 Slave > > + int "I2C8 Slave" > > + default 0 > > + help > > + MXC I2C8 Slave > > endif > > > > config SYS_I2C_OMAP24XX > > - bool "TI OMAP2+ I2C driver" > > - depends on ARCH_OMAP2PLUS || ARCH_K3 > > - help > > - Add support for the OMAP2+ I2C driver. > > + bool "TI OMAP2+ I2C driver" > > + depends on ARCH_OMAP2PLUS || ARCH_K3 > > + help > > + Add support for the OMAP2+ I2C driver. > > > > if SYS_I2C_OMAP24XX > > config SYS_OMAP24_I2C_SLAVE > > - int "I2C Slave addr channel 0" > > - default 1 > > - help > > - OMAP24xx I2C Slave address channel 0 > > + int "I2C Slave addr channel 0" > > + default 1 > > + help > > + OMAP24xx I2C Slave address channel 0 > > > > config SYS_OMAP24_I2C_SPEED > > - int "I2C Slave channel 0 speed" > > - default 100000 > > - help > > - OMAP24xx Slave speed channel 0 > > + int "I2C Slave channel 0 speed" > > + default 100000 > > + help > > + OMAP24xx Slave speed channel 0 > > endif > > > > config SYS_I2C_RCAR_I2C > > - bool "Renesas RCar I2C driver" > > - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > - help > > - Support for Renesas RCar I2C controller. > > + bool "Renesas RCar I2C driver" > > + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > + help > > + Support for Renesas RCar I2C controller. > > > > config SYS_I2C_RCAR_IIC > > - bool "Renesas RCar Gen3 IIC driver" > > - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > - help > > - Support for Renesas RCar Gen3 IIC controller. > > + bool "Renesas RCar Gen3 IIC driver" > > + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > + help > > + Support for Renesas RCar Gen3 IIC controller. > > > > config SYS_I2C_ROCKCHIP > > - bool "Rockchip I2C driver" > > - depends on DM_I2C > > - help > > - Add support for the Rockchip I2C driver. This is used with various > > - Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips > > - have several I2C ports and all are provided, controlled by the > > - device tree. > > + bool "Rockchip I2C driver" > > + depends on DM_I2C > > + help > > + Add support for the Rockchip I2C driver. This is used with various > > + Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips > > + have several I2C ports and all are provided, controlled by the > > + device tree. > > > > config SYS_I2C_SANDBOX > > - bool "Sandbox I2C driver" > > - depends on SANDBOX && DM_I2C > > - help > > - Enable I2C support for sandbox. This is an emulation of a real I2C > > - bus. Devices can be attached to the bus using the device tree > > - which specifies the driver to use. See sandbox.dts as an example. > > + bool "Sandbox I2C driver" > > + depends on SANDBOX && DM_I2C > > + help > > + Enable I2C support for sandbox. This is an emulation of a real I2C > > + bus. Devices can be attached to the bus using the device tree > > + which specifies the driver to use. See sandbox.dts as an example. > > > > config SYS_I2C_S3C24X0 > > - bool "Samsung I2C driver" > > - depends on ARCH_EXYNOS4 && DM_I2C > > - help > > - Support for Samsung I2C controller as Samsung SoCs. > > + bool "Samsung I2C driver" > > + depends on ARCH_EXYNOS4 && DM_I2C > > + help > > + Support for Samsung I2C controller as Samsung SoCs. > > > > config SYS_I2C_STM32F7 > > - bool "STMicroelectronics STM32F7 I2C support" > > - depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C > > - help > > - Enable this option to add support for STM32 I2C controller > > - introduced with STM32F7/H7 SoCs. This I2C controller supports : > > - _ Slave and master modes > > - _ Multimaster capability > > - _ Standard-mode (up to 100 kHz) > > - _ Fast-mode (up to 400 kHz) > > - _ Fast-mode Plus (up to 1 MHz) > > - _ 7-bit and 10-bit addressing mode > > - _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) > > - _ All 7-bit addresses acknowledge mode > > - _ General call > > - _ Programmable setup and hold times > > - _ Easy to use event management > > - _ Optional clock stretching > > - _ Software reset > > + bool "STMicroelectronics STM32F7 I2C support" > > + depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C > > + help > > + Enable this option to add support for STM32 I2C controller > > + introduced with STM32F7/H7 SoCs. This I2C controller supports : > > + _ Slave and master modes > > + _ Multimaster capability > > + _ Standard-mode (up to 100 kHz) > > + _ Fast-mode (up to 400 kHz) > > + _ Fast-mode Plus (up to 1 MHz) > > + _ 7-bit and 10-bit addressing mode > > + _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) > > + _ All 7-bit addresses acknowledge mode > > + _ General call > > + _ Programmable setup and hold times > > + _ Easy to use event management > > + _ Optional clock stretching > > + _ Software reset > > > > config SYS_I2C_TEGRA > > - bool "NVIDIA Tegra internal I2C controller" > > - depends on TEGRA > > - help > > - Support for NVIDIA I2C controller available in Tegra SoCs. > > + bool "NVIDIA Tegra internal I2C controller" > > + depends on TEGRA > > + help > > + Support for NVIDIA I2C controller available in Tegra SoCs. > > > > config SYS_I2C_UNIPHIER > > - bool "UniPhier I2C driver" > > - depends on ARCH_UNIPHIER && DM_I2C > > - default y > > - help > > - Support for UniPhier I2C controller driver. This I2C controller > > - is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. > > + bool "UniPhier I2C driver" > > + depends on ARCH_UNIPHIER && DM_I2C > > + default y > > + help > > + Support for UniPhier I2C controller driver. This I2C controller > > + is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. > > > > config SYS_I2C_UNIPHIER_F > > - bool "UniPhier FIFO-builtin I2C driver" > > - depends on ARCH_UNIPHIER && DM_I2C > > - default y > > - help > > - Support for UniPhier FIFO-builtin I2C controller driver. > > - This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > > + bool "UniPhier FIFO-builtin I2C driver" > > + depends on ARCH_UNIPHIER && DM_I2C > > + default y > > + help > > + Support for UniPhier FIFO-builtin I2C controller driver. > > + This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > > > > config SYS_I2C_VERSATILE > > - bool "Arm Ltd Versatile I2C bus driver" > > - depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) > > - help > > - Add support for the Arm Ltd Versatile Express I2C driver. The I2C host > > - controller is present in the development boards manufactured by Arm Ltd. > > + bool "Arm Ltd Versatile I2C bus driver" > > + depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) > > + help > > + Add support for the Arm Ltd Versatile Express I2C driver. The I2C host > > + controller is present in the development boards manufactured by Arm Ltd. > > > > config SYS_I2C_MVTWSI > > - bool "Marvell I2C driver" > > - depends on DM_I2C > > - help > > - Support for Marvell I2C controllers as used on the orion5x and > > - kirkwood SoC families. > > + bool "Marvell I2C driver" > > + depends on DM_I2C > > + help > > + Support for Marvell I2C controllers as used on the orion5x and > > + kirkwood SoC families. > > > > config TEGRA186_BPMP_I2C > > - bool "Enable Tegra186 BPMP-based I2C driver" > > - depends on TEGRA186_BPMP > > - help > > - Support for Tegra I2C controllers managed by the BPMP (Boot and > > - Power Management Processor). On Tegra186, some I2C controllers are > > - directly controlled by the main CPU, whereas others are controlled > > - by the BPMP, and can only be accessed by the main CPU via IPC > > - requests to the BPMP. This driver covers the latter case. > > + bool "Enable Tegra186 BPMP-based I2C driver" > > + depends on TEGRA186_BPMP > > + help > > + Support for Tegra I2C controllers managed by the BPMP (Boot and > > + Power Management Processor). On Tegra186, some I2C controllers are > > + directly controlled by the main CPU, whereas others are controlled > > + by the BPMP, and can only be accessed by the main CPU via IPC > > + requests to the BPMP. This driver covers the latter case. > > > > config SYS_I2C_BUS_MAX > > - int "Max I2C busses" > > - depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA > > - default 2 if TI816X > > - default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE > > - default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X > > - default 5 if OMAP54XX > > - help > > - Define the maximum number of available I2C buses. > > + int "Max I2C busses" > > + depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA > > + default 2 if TI816X > > + default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE > > + default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X > > + default 5 if OMAP54XX > > + help > > + Define the maximum number of available I2C buses. > > > > config SYS_I2C_XILINX_XIIC > > - bool "Xilinx AXI I2C driver" > > - depends on DM_I2C > > - help > > - Support for Xilinx AXI I2C controller. > > + bool "Xilinx AXI I2C driver" > > + depends on DM_I2C > > + help > > + Support for Xilinx AXI I2C controller. > > > > config SYS_I2C_IHS > > bool "gdsys IHS I2C driver" > > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > > index c2f75d8755..7cfe68e088 100644 > > --- a/drivers/i2c/Makefile > > +++ b/drivers/i2c/Makefile > > @@ -38,5 +38,5 @@ obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o > > obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o > > obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o > > obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o > > - > > +obj-$(CONFIG_IPROC_I2C) += iproc_i2c.o > > please keep lists sorted! > (Same applies to your "drivers: pcie: Add Broadcom IPROC PCIe driver" patch) > > > obj-$(CONFIG_I2C_MUX) += muxes/ > > diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c > > new file mode 100644 > > index 0000000000..692035666c > > --- /dev/null > > +++ b/drivers/i2c/iproc_i2c.c > > @@ -0,0 +1,765 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright (C)) 2018 Broadcom > > + */ > > + > > +#include <common.h> > > +#include <config.h> > > +#include <dm.h> > > +#include <i2c.h> > > +#include <asm/io.h> > > +#include "errno.h" > > +#include "iproc_i2c.h" > > + > > +DECLARE_GLOBAL_DATA_PTR; > > + > > +static int i2c_init_done; > > + > > +struct iproc_i2c_regs { > > + u32 cfg_reg; > > + u32 timg_cfg; > > + u32 addr_reg; > > + u32 mstr_fifo_ctrl; > > + u32 slv_fifo_ctrl; > > + u32 bitbng_ctrl; > > + u32 blnks[6]; /* Not to be used */ > > + u32 mstr_cmd; > > + u32 slv_cmd; > > + u32 evt_en; > > + u32 evt_sts; > > + u32 mstr_datawr; > > + u32 mstr_datard; > > + u32 slv_datawr; > > + u32 slv_datard; > > +}; > > + > > +struct iproc_i2c { > > + struct iproc_i2c_regs __iomem *base; /* register base */ > > + int bus_speed; > > +}; > > + > > +/* Function to read a value from specified register. */ > > +static unsigned int iproc_i2c_reg_read(u32 *reg_addr) > > +{ > > + unsigned int val; > > + > > + val = readl((void *)(reg_addr)); > > + return cpu_to_le32(val); > > +} > > + > > +/* Function to write a value ('val') in to a specified register. */ > > +static int iproc_i2c_reg_write(u32 *reg_addr, unsigned int val) > > +{ > > + val = cpu_to_le32(val); > > + writel(val, (void *)(reg_addr)); > > + return 0; > > +} > > + > > +#ifdef IPROC_I2C_DBG > > Can you add this define at least through Kconfig ? > > Do we need this define? debug() should be dropped if DEBUG is > not defined... and you can do here > > #if defined(DEBUG) > static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) > [...] > #else > static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata){ > return 0; > } > #endif > > and drop all later "ifdef IPROC_I2C_DBG" stuff... > > > +static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > + debug("\n----------------------------------------------\n"); > > + debug("%s: Dumping SMBus registers...\n", __func__); > > + > > + regval = iproc_i2c_reg_read(&base->cfg_reg); > > + debug("CCB_SMB_CFG_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->timg_cfg); > > + debug("CCB_SMB_TIMGCFG_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->addr_reg); > > + debug("CCB_SMB_ADDR_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_fifo_ctrl); > > + debug("CCB_SMB_MSTRFIFOCTL_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_fifo_ctrl); > > + debug("CCB_SMB_SLVFIFOCTL_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->bitbng_ctrl); > > + debug("CCB_SMB_BITBANGCTL_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + debug("CCB_SMB_MSTRCMD_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_cmd); > > + debug("CCB_SMB_SLVCMD_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->evt_en); > > + debug("CCB_SMB_EVTEN_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->evt_sts); > > + debug("CCB_SMB_EVTSTS_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_datawr); > > + debug("CCB_SMB_MSTRDATAWR_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_datard); > > + debug("CCB_SMB_MSTRDATARD_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_datawr); > > + debug("CCB_SMB_SLVDATAWR_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_datard); > > + debug("CCB_SMB_SLVDATARD_REG=0x%08X\n", regval); > > + > > + debug("----------------------------------------------\n\n"); > > + return 0; > > +} > > +#endif > > + > > +/* > > + * Function to ensure that the previous transaction was completed before > > + * initiating a new transaction. It can also be used in polling mode to > > + * check status of completion of a command > > + */ > > +static int iproc_i2c_startbusy_wait(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + > > + /* Check if an operation is in progress. During probe it won't be. > > + * But when shutdown/remove was called we want to make sure that > > + * the transaction in progress completed > > + */ > > + if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > > + unsigned int i = 0; > > + > > + do { > > + mdelay(10); /* Wait for 10 msec */ > > Please remove this comment. > > > + i++; > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + > > + /* If start-busy bit cleared, exit the loop */ > > + } while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) && > > + (i < IPROC_SMB_MAX_RETRIES)); > > + > > + if (i >= IPROC_SMB_MAX_RETRIES) { > > + pr_err("%s: START_BUSY bit didn't clear, exiting\n", > > + __func__); > > + > > + return -ETIMEDOUT; > > + } > > + } > > + return 0; > > +} > > + > > +/* > > + * This function set clock frequency for SMBus block. As per hardware > > + * engineering, the clock frequency can be changed dynamically. > > + */ > > +static int iproc_i2c_set_clk_freq(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > + regval = iproc_i2c_reg_read(&base->timg_cfg); > > + > > + switch (bus_prvdata->bus_speed) { > > + case I2C_SPEED_100KHZ: > > + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_100, > > + CCB_SMB_TIMGCFG_MODE400_MASK, > > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > > + break; > > + > > + case I2C_SPEED_400KHZ: > > + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_400, > > + CCB_SMB_TIMGCFG_MODE400_MASK, > > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > > + break; > > + > > + default: > > + return -EINVAL; > > + } > > + > > + iproc_i2c_reg_write(&base->timg_cfg, regval); > > + return 0; > > +} > > + > > +static int iproc_i2c_init(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("\n%s: Entering", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + /* Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0. > > + * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts > > + */ > > + regval = CCB_SMB_MSTRRXFIFOFLSH_MASK | CCB_SMB_MSTRTXFIFOFLSH_MASK; > > + iproc_i2c_reg_write(&base->mstr_fifo_ctrl, regval); > > + > > + /* Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero > > + * since there will be only one master > > + */ > > + > > + regval = iproc_i2c_reg_read(&base->cfg_reg); > > + regval |= CCB_SMB_CFG_SMBEN_MASK; > > + iproc_i2c_reg_write(&base->cfg_reg, regval); > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > What are this defines? Wbere come they from ? They are not in current mainline > code: > > pollux:u-boot hs [work] $ grep -lr CONFIG_CYGNUS . > ./mbox > pollux:u-boot hs [work] $ grep -lr BCMOMEGA . > ./mbox > pollux:u-boot hs [work] $ > > please remove this code. Also this seems board specific code. We should > prevent this in common driver code! > > > + regval = iproc_i2c_reg_read(&base->cfg_reg); > > + regval |= CCB_SMB_CFG_RST_MASK; > > + iproc_i2c_reg_write(&base->cfg_reg, regval); > > + regval &= ~CCB_SMB_CFG_RST_MASK; > > + iproc_i2c_reg_write(&base->cfg_reg, regval); > > +#endif > > + /* Wait a minimum of 50 Usec, as per SMB hw doc */ > > + udelay(50); > > linux driver waits here for 100usec ... with the comment "per spec" ... > and flushes the FIFO after ... but I have no insight into this hardware, > so cannot say, what the better procedure... > > > + > > + /* Set default clock frequency */ > > + iproc_i2c_set_clk_freq(bus_prvdata); > > + > > + /* Disable intrs */ > > + iproc_i2c_reg_write(&base->evt_en, 0); > > + > > + /* Clear intrs (W1TC) */ > > + regval = iproc_i2c_reg_read(&base->evt_sts); > > + iproc_i2c_reg_write(&base->evt_sts, regval); > > + > > + i2c_init_done = 1; > > Why you need this global variable ? Please store this variable > in "iproc_i2c" > > > + > > +#ifdef IPROC_I2C_DBG > > + iproc_dump_i2c_regs(bus_prvdata); > > + > > + debug("%s: Init successful\n", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + return 0; > > +} > > + > > +/* > > + * This function copies data to SMBus's Tx FIFO. Valid for write transactions > > + * only > > + * > > + * base_addr: Mapped address of this SMBus instance > > + * dev_addr: SMBus (I2C) device address. We are assuming 7-bit addresses > > + * initially > > + * info: Data to copy in to Tx FIFO. For read commands, the size should be > > + * set to zero by the caller > > + * > > + */ > > +static void iproc_i2c_write_trans_data(struct iproc_i2c *bus_prvdata, > > + unsigned short dev_addr, > > + struct iproc_xact_info *info) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + unsigned int i; > > + unsigned int num_data_bytes = 0; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("%s: dev_addr=0x%X cmd_valid=%d cmd=0x%02x size=%u proto=%d\n" > > + "buf[] %x\n", > > + __func__, > > + dev_addr, > > + info->cmd_valid, > > + info->command, > > + info->size, > > + info->smb_proto, > > + info->data[0]); > > +#endif /* IPROC_I2C_DBG */ > > + > > + /* Write SMBus device address first */ > > + /* Note, we are assuming 7-bit addresses for now. For 10-bit addresses, > > + * we may have one more write to send the upper 3 bits of 10-bit addr > > + */ > > + iproc_i2c_reg_write(&base->mstr_datawr, dev_addr); > > + > > + /* If the protocol needs command code, copy it */ > > + if (info->cmd_valid) > > + iproc_i2c_reg_write(&base->mstr_datawr, info->command); > > + > > + /* Depending on the SMBus protocol, we need to write additional > > + * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus > > + * spec for sequence for a transaction > > + */ > > + switch (info->smb_proto) { > > + case SMBUS_PROT_RECV_BYTE: > > + /* No additional data to be written */ > > + num_data_bytes = 0; > > + break; > > + > > + case SMBUS_PROT_SEND_BYTE: > > + num_data_bytes = info->size; > > + break; > > + > > + case SMBUS_PROT_RD_BYTE: > > + case SMBUS_PROT_RD_WORD: > > + case SMBUS_PROT_BLK_RD: > > + /* Write slave address with R/W~ set (bit #0) */ > > + iproc_i2c_reg_write(&base->mstr_datawr, > > + dev_addr | 0x1); > > + num_data_bytes = 0; > > + break; > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > + case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL: > > + iproc_i2c_reg_write(&base->mstr_datawr, > > + dev_addr | 0x1 | > > + CCB_SMB_MSTRWRSTS_MASK); > > + num_data_bytes = 0; > > + break; > > +#endif > > + case SMBUS_PROT_WR_BYTE: > > + case SMBUS_PROT_WR_WORD: > > + /* No additional bytes to be written. > > + * Data portion is written in the > > + * 'for' loop below > > + */ > > + num_data_bytes = info->size; > > + break; > > + > > + case SMBUS_PROT_BLK_WR: > > + /* 3rd byte is byte count */ > > + iproc_i2c_reg_write(&base->mstr_datawr, info->size); > > + num_data_bytes = info->size; > > + break; > > + > > + default: > > + break; > > + } > > + > > + /* Copy actual data from caller, next. In general, for reads, no data is > > + * copied > > + */ > > + for (i = 0; num_data_bytes; --num_data_bytes, i++) { > > + /* For the last byte, set MASTER_WR_STATUS bit */ > > + regval = (num_data_bytes == 1) ? > > + info->data[i] | CCB_SMB_MSTRWRSTS_MASK : > > + info->data[i]; > > + > > + iproc_i2c_reg_write(&base->mstr_datawr, regval); > > + } > > +} > > + > > +static int iproc_i2c_data_send(struct iproc_i2c *bus_prvdata, > > + unsigned short addr, > > + struct iproc_xact_info *info) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + int rc, retry = 3; unsigned int regval; > > + > > + /* Make sure the previous transaction completed */ > > + rc = iproc_i2c_startbusy_wait(bus_prvdata); > > + > > + if (rc < 0) { > > + pr_err("%s: Send: bus is busy, exiting\n", __func__); > > + return rc; > > + } > > + > > + /* Write transaction bytes to Tx FIFO */ > > + iproc_i2c_write_trans_data(bus_prvdata, addr, info); > > + > > + /* Program master command register (0x30) with protocol type and set > > + * start_busy_command bit to initiate the write transaction > > + */ > > + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > > + CCB_SMB_MSTRSTARTBUSYCMD_MASK; > > + > > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > > + > > + /* Check for Master status */ > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > > + mdelay(10); > > + if (retry-- <= 0) > > + break; > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + } > > + > > + /* If start_busy bit cleared, check if there are any errors */ > > + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { > > + /* start_busy bit cleared, check master_status field now */ > > + regval &= CCB_SMB_MSTRSTS_MASK; > > + regval >>= CCB_SMB_MSTRSTS_SHIFT; > > + > > + if (regval != MSTR_STS_XACT_SUCCESS) { > > + /* Error We can flush Tx FIFO here */ > > + pr_err("%s: ERROR: Error in transaction %u, exiting\n", > > + __func__, regval); > > + return -EREMOTEIO; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int iproc_i2c_data_recv(struct iproc_i2c *bus_prvdata, > > + unsigned short addr, > > + struct iproc_xact_info *info, > > + unsigned int *num_bytes_read) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + int rc, retry = 3; > > + unsigned int regval; > > + > > + /* Make sure the previous transaction completed */ > > + rc = iproc_i2c_startbusy_wait(bus_prvdata); > > + > > + if (rc < 0) { > > + pr_err("%s: Receive: Bus is busy, exiting\n", __func__); > > + return rc; > > + } > > + > > + /* Program all transaction bytes into master Tx FIFO */ > > + iproc_i2c_write_trans_data(bus_prvdata, addr, info); > > + > > + /* Program master command register (0x30) with protocol type and set > > + * start_busy_command bit to initiate the write transaction > > + */ > > + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > > + CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size; > > + > > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > > + > > + /* Check for Master status */ > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > > + udelay(1000); > > + if (retry-- <= 0) > > + break; > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + } > > + > > + /* If start_busy bit cleared, check if there are any errors */ > > + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { > > + /* start_busy bit cleared, check master_status field now */ > > + regval &= CCB_SMB_MSTRSTS_MASK; > > + regval >>= CCB_SMB_MSTRSTS_SHIFT; > > + > > + if (regval != MSTR_STS_XACT_SUCCESS) { > > + /* We can flush Tx FIFO here */ > > + pr_err("%s: Error in transaction %d, exiting\n", > > + __func__, regval); > > + return -EREMOTEIO; > > + } > > + } > > + > > + /* Read received byte(s), after TX out address etc */ > > + regval = iproc_i2c_reg_read(&base->mstr_datard); > > + > > + /* For block read, protocol (hw) returns byte count, > > + * as the first byte > > + */ > > + if (info->smb_proto == SMBUS_PROT_BLK_RD) { > > + int i; > > + > > + *num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK; > > + > > + /* Limit to reading a max of 32 bytes only; just a safeguard. > > + * If # bytes read is a number > 32, check transaction set up, > > + * and contact hw engg. Assumption: PEC is disabled > > + */ > > + for (i = 0; > > + (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX); > > + i++) { > > + /* Read Rx FIFO for data bytes */ > > + regval = iproc_i2c_reg_read(&base->mstr_datard); > > + info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK; > > + } > > + } else { > > + /* 1 Byte data */ > > + *info->data = regval & CCB_SMB_MSTRRDDATA_MASK; > > + *num_bytes_read = 1; > > + } > > + > > + return 0; > > +} > > + > > +static int i2c_write_byte(struct iproc_i2c *bus_prvdata, > > + u8 devaddr, > > + u8 regoffset, > > + u8 value) > > +{ > > + int rc; > > + struct iproc_xact_info info; > > + > > + devaddr <<= 1; > > + > > + info.cmd_valid = 1; > > + info.command = (unsigned char)regoffset; > > + info.data = &value; > > + info.size = 1; > > + info.flags = 0; > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > unknown defines ... > > > + info.smb_proto = SMBUS_PROT_WR_WORD;/*SMBUS_PROT_WR_BYTE;*/ > > +#else > > + info.smb_proto = SMBUS_PROT_WR_BYTE; > > +#endif > > + /* Refer to i2c_smbus_write_byte params passed. */ > > + rc = iproc_i2c_data_send(bus_prvdata, devaddr, &info); > > + > > + if (rc < 0) { > > + pr_err("%s: %s error accessing device 0x%X\n", > > + __func__, "Write", devaddr); > > + return -EREMOTEIO; > > + } > > + > > + return 0; > > +} > > + > > +int i2c_write(struct iproc_i2c *bus_prvdata, > > + uchar chip, > > + uint regaddr, > > + int alen, > > + uchar *buffer, > > + int len) > > +{ > > + int i, data_len; > > + u8 *data; > > + > > + if (alen > 1) { > > + pr_err("I2C write: addr len %d not supported\n", alen); > > + return 1; > > + } > > + > > + if (regaddr + len > 256) { > > + pr_err("I2C write: address out of range\n"); > > + return 1; > > + } > > + > > + if (len < 1) { > > + pr_err("I2C write: Need offset addr and value\n"); > > + return 1; > > + } > > + > > + /* buffer contains offset addr followed by value to be written */ > > + regaddr = buffer[0]; > > + data = &buffer[1]; > > + data_len = len - 1; > > + > > + for (i = 0; i < data_len; i++) { > > + if (i2c_write_byte(bus_prvdata, chip, regaddr + i, data[i])) { > > + pr_err("I2C write (%d): I/O error\n", i); > > + iproc_i2c_init(bus_prvdata); > > + return 1; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int i2c_read_byte(struct iproc_i2c *bus_prvdata, > > + u8 devaddr, > > + u8 regoffset, > > + u8 *value) > > +{ > > + int rc; > > + struct iproc_xact_info info; > > + unsigned int num_bytes_read = 0; > > + > > + devaddr <<= 1; > > + > > + info.cmd_valid = 1; > > + info.command = (unsigned char)regoffset; > > + info.data = value; > > + info.size = 1; > > + info.flags = 0; > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > + info.smb_proto = SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL; > > +#else > > + info.smb_proto = SMBUS_PROT_RD_BYTE; > > +#endif > > + /* Refer to i2c_smbus_read_byte for params passed. */ > > + rc = iproc_i2c_data_recv(bus_prvdata, devaddr, &info, &num_bytes_read); > > + > > + if (rc < 0) { > > + pr_err("%s: %s error accessing device 0x%X\n", > > + __func__, "Read", devaddr); > > + return -EREMOTEIO; > > + } > > + > > + return 0; > > +} > > + > > +int i2c_read(struct iproc_i2c *bus_prvdata, > > + uchar chip, > > + uint addr, > > + int alen, > > + uchar *buffer, > > + int len) > > +{ > > + int i; > > + > > + if (alen > 1) { > > + pr_err("I2C read: addr len %d not supported\n", alen); > > + return 1; > > + } > > + > > + if (addr + len > 256) { > > + pr_err("I2C read: address out of range\n"); > > + return 1; > > + } > > You always pass addr = 0 and alen = 0 ... so this checks are useless (beside len check) > same for i2c_write ... > > > + > > + for (i = 0; i < len; i++) { > > + if (i2c_read_byte(bus_prvdata, chip, addr + i, &buffer[i])) { > > + pr_err("I2C read: I/O error\n"); > > + iproc_i2c_init(bus_prvdata); > > + return 1; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int iproc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + int ret = 0; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("%s: %d messages\n", __func__, nmsgs); > > +#endif > > + > > + for (; nmsgs > 0; nmsgs--, msg++) { > > + if (msg->flags & I2C_M_RD) > > + ret = i2c_read(bus_prvdata, > > + msg->addr, > > + 0, > > + 0, > > + msg->buf, > > + msg->len); > > + else > > + ret = i2c_write(bus_prvdata, > > + msg->addr, > > + 0, > > + 0, > > + msg->buf, > > + msg->len); > > + } > > + > > + return ret; > > +} > > + > > +static int iproc_i2c_probe_chip(struct udevice *bus, uint chip_addr, > > + uint chip_flags) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + u32 regval; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("\n%s: Entering chip probe\n", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + /* Init internal regs, disable intrs (and then clear intrs), set fifo > > + * thresholds, etc. > > + */ > > + if (!i2c_init_done) > > + iproc_i2c_init(bus_prvdata); > > Couldn;t you store this "i2c_init_done" in bus_prvdata ? > > > + > > + regval = (chip_addr << 1); > > + iproc_i2c_reg_write(&base->mstr_datawr, regval); > > + regval = ((SMBUS_PROT_QUICK_CMD << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > > + (1 << CCB_SMB_MSTRSTARTBUSYCMD_SHIFT)); > > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > > + > > + do { > > + udelay(100); > > Is this delay somewhere described in a spec? > > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + regval &= CCB_SMB_MSTRSTARTBUSYCMD_MASK; > > + } while (regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + > > + if ((regval & CCB_SMB_MSTRSTS_MASK) != 0) > > + return -1; > > + > > +#ifdef IPROC_I2C_DBG > > + iproc_dump_i2c_regs(bus_prvdata); > > + > > + debug("%s: chip probe successful\n", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + return 0; > > +} > > + > > +static int iproc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + > > + bus_prvdata->bus_speed = speed; > > + if (iproc_i2c_set_clk_freq(bus_prvdata)) > > + return -EINVAL; > > couldn; t you return simply the return value from iproc_i2c_set_clk_freq()? > > > + > > + return 0; > > +} > > + > > +/** > > + * i2c_get_bus_speed - get i2c bus speed > > + * > > + * This function returns the speed of operation in Hz > > + */ > > +int iproc_i2c_get_bus_speed(struct udevice *bus) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + unsigned int val; > > + > > + regval = iproc_i2c_reg_read(&base->timg_cfg); > > + val = GETREGFLDVAL(regval, CCB_SMB_TIMGCFG_MODE400_MASK, > > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > > + switch (val) { > > + case 0: > > + return I2C_SPEED_100KHZ; > > + case 1: > > + return I2C_SPEED_400KHZ; > > + default: > > + return -EINVAL; > > + } > > + return -EINVAL; > > +} > > + > > +static int iproc_i2c_probe(struct udevice *bus) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + > > + return iproc_i2c_init(bus_prvdata); > > +} > > + > > +static int iproc_i2c_ofdata_to_platdata(struct udevice *bus) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + int node = dev_of_offset(bus); > > + const void *blob = gd->fdt_blob; > > + > > + bus_prvdata->base = map_physmem(devfdt_get_addr(bus), > > + sizeof(void *), > > + MAP_NOCACHE); > > + > > + /* default 100KHz freq */ > > + bus_prvdata->bus_speed = fdtdec_get_int(blob, node, "bus-frequency", > > + I2C_SPEED_100KHZ); > > + > > + return 0; > > +} > > + > > +static const struct dm_i2c_ops iproc_i2c_ops = { > > + .xfer = iproc_i2c_xfer, > > + .probe_chip = iproc_i2c_probe_chip, > > + .set_bus_speed = iproc_i2c_set_bus_speed, > > + .get_bus_speed = iproc_i2c_get_bus_speed, > > +}; > > + > > +static const struct udevice_id iproc_i2c_ids[] = { > > + { .compatible = "brcm,iproc-i2c" }, > > + { } > > +}; > > + > > +U_BOOT_DRIVER(iproc_i2c) = { > > + .name = "iproc_i2c", > > + .id = UCLASS_I2C, > > + .of_match = iproc_i2c_ids, > > + .ofdata_to_platdata = iproc_i2c_ofdata_to_platdata, > > + .probe = iproc_i2c_probe, > > + .priv_auto_alloc_size = sizeof(struct iproc_i2c), > > + .ops = &iproc_i2c_ops, > > + .flags = DM_FLAG_PRE_RELOC, > > +}; > > diff --git a/drivers/i2c/iproc_i2c.h b/drivers/i2c/iproc_i2c.h > > new file mode 100644 > > index 0000000000..4f8d6ba2b2 > > --- /dev/null > > +++ b/drivers/i2c/iproc_i2c.h > > @@ -0,0 +1,356 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > +/* Copyright (C) 2018 Broadcom */ > > + > > +#ifndef __IPROC_I2C_H__ > > +#define __IPROC_I2C_H__ > > + > > +#if (defined(CONFIG_NS_PLUS) || defined(CONFIG_HELIX4)) > > again defines not in mainline! Please remove! > > > +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 > > +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 > > +#define IPROC_SMBUS_BASE_ADDR1 0x18038000 > > +#define IPROC_SMBUS_BASE_ADDR2 0x1803B000 > > +#elif (defined(CONFIG_CYGNUS)) > > +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 > > +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 > > +#define IPROC_SMBUS_BASE_ADDR1 0x18008000 > > +#define IPROC_SMBUS_BASE_ADDR2 0x1800B000 > > +#endif > > Hmm... couldn;t come this values through DTS ? > > SHADOW_CPY_BUFFER_ADDR1, SHADOW_CPY_BUFFER_ADDR2, IPROC_SMBUS_BASE_ADDR1 > and IPROC_SMBUS_BASE_ADDR2 not used in this patch in other places! > > So please remove this defines complete. > > > + > > +/* Registers */ > > +#define CCB_SMB_CFG_REG 0x0 > > + > > +#define CCB_SMB_CFG_RST_MASK 0x80000000 > > +#define CCB_SMB_CFG_RST_SHIFT 31 > > + > > +#define CCB_SMB_CFG_SMBEN_MASK 0x40000000 > > +#define CCB_SMB_CFG_SMBEN_SHIFT 30 > > + > > +#define CCB_SMB_CFG_BITBANGEN_MASK 0x20000000 > > +#define CCB_SMB_CFG_BITBANGEN_SHIFT 29 > > + > > +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000 > > +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28 > > + > > +#define CCB_SMB_CFG_PROMISCMODE_MASK 0x08000000 > > +#define CCB_SMB_CFG_PROMISCMODE_SHIFT 27 > > + > > +#define CCB_SMB_CFG_TSTMPCNTEN_MASK 0x04000000 > > +#define CCB_SMB_CFG_TSTMPCNTEN_SHIFT 26 > > + > > +#define CCB_SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000 > > +#define CCB_SMB_CFG_MSTRRTRYCNT_SHIFT 16 > > + > > +#define CCB_SMB_TIMGCFG_REG 0x4 > > + > > +#define CCB_SMB_TIMGCFG_MODE400_MASK 0x80000000 > > +#define CCB_SMB_TIMGCFG_MODE400_SHIFT 31 > > + > > +#define CCB_SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000 > > +#define CCB_SMB_TIMGCFG_RNDSLVSTR_SHIFT 24 > > + > > +#define CCB_SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000 > > +#define CCB_SMB_TIMGCFG_PERSLVSTR_SHIFT 16 > > + > > +#define CCB_SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00 > > +#define CCB_SMB_TIMGCFG_IDLTIME_SHIFT 8 > > + > > +#define CCB_SMB_ADDR_REG 0x8 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR3_MASK 0x80000000 > > +#define CCB_SMB_EN_NIC_SMBADDR3_SHIFT 31 > > + > > +#define CCB_SMB_NIC_SMBADDR3_MASK 0x7F000000 > > +#define CCB_SMB_NIC_SMBADDR3_SHIFT 24 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR2_MASK 0x00800000 > > +#define CCB_SMB_EN_NIC_SMBADDR2_SHIFT 23 > > + > > +#define CCB_SMB_NIC_SMBADDR2_MASK 0x007F0000 > > +#define CCB_SMB_NIC_SMBADDR2_SHIFT 16 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR1_MASK 0x00008000 > > +#define CCB_SMB_EN_NIC_SMBADDR1_SHIFT 15 > > + > > +#define CCB_SMB_NIC_SMBADDR1_MASK 0x00007F00 > > +#define CCB_SMB_NIC_SMBADDR1_SHIFT 8 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR0_MASK 0x00000080 > > +#define CCB_SMB_EN_NIC_SMBADDR0_SHIFT 7 > > + > > +#define CCB_SMB_NIC_SMBADDR0_MASK 0x0000007F > > +#define CCB_SMB_NIC_SMBADDR0_SHIFT 0 > > + > > +#define CCB_SMB_MSTRFIFOCTL_REG 0xC > > + > > +#define CCB_SMB_MSTRRXFIFOFLSH_MASK 0x80000000 > > +#define CCB_SMB_MSTRRXFIFOFLSH_SHIFT 31 > > + > > +#define CCB_SMB_MSTRTXFIFOFLSH_MASK 0x40000000 > > +#define CCB_SMB_MSTRTXFIFOFLSH_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRXPKTCNT_MASK 0x007F0000 > > +#define CCB_SMB_MSTRRXPKTCNT_SHIFT 16 > > + > > +#define CCB_SMB_MSTRRXFIFOTHR_MASK 0x00003F00 > > +#define CCB_SMB_MSTRRXFIFOTHR_SHIFT 8 > > + > > +#define CCB_SMB_SLVFIFOCTL_REG 0x10 > > + > > +#define CCB_SMB_SLVRXFIFOFLSH_MASK 0x80000000 > > +#define CCB_SMB_SLVRXFIFOFLSH_SHIFT 31 > > + > > +#define CCB_SMB_SLVTXFIFOFLSH_MASK 0x40000000 > > +#define CCB_SMB_SLVTXFIFOFLSH_SHIFT 30 > > + > > +#define CCB_SMB_SLVRXPKTCNT_MASK 0x007F0000 > > +#define CCB_SMB_SLVRXPKTCNT_SHIFT 16 > > + > > +#define CCB_SMB_SLVRXFIFOTHR_MASK 0x00003F00 > > +#define CCB_SMB_SLVRXFIFOTHR_SHIFT 8 > > + > > +#define CCB_SMB_BITBANGCTL_REG 0x14 > > + > > +#define CCB_SMB_SMBCLKIN_MASK 0x80000000 > > +#define CCB_SMB_SMBCLKIN_SHIFT 31 > > + > > +#define CCB_SMB_SMBCLKOUTEN_MASK 0x40000000 > > +#define CCB_SMB_SMBCLKOUTEN_SHIFT 30 > > + > > +#define CCB_SMB_SMBDATAIN_MASK 0x20000000 > > +#define CCB_SMB_SMBDATAIN_SHIFT 29 > > + > > +#define CCB_SMB_SMBDATAOUTEN_MASK 0x10000000 > > +#define CCB_SMB_SMBDATAOUTEN_SHIFT 28 > > + > > +#define CCB_SMB_MSTRCMD_REG 0x30 > > + > > +#define CCB_SMB_MSTRSTARTBUSYCMD_MASK 0x80000000 > > +#define CCB_SMB_MSTRSTARTBUSYCMD_SHIFT 31 > > + > > +#define CCB_SMB_MSTRABORT_MASK 0x40000000 > > +#define CCB_SMB_MSTRABORT_SHIFT 30 > > + > > +#define CCB_SMB_MSTRSTS_MASK 0x0E000000 > > +#define CCB_SMB_MSTRSTS_SHIFT 25 > > + > > +#define CCB_SMB_MSTRSMBUSPROTO_MASK 0x00001E00 > > +#define CCB_SMB_MSTRSMBUSPROTO_SHIFT 9 > > + > > +#define CCB_SMB_MSTRPEC_MASK 0x00000100 > > +#define CCB_SMB_MSTRPEC_SHIFT 8 > > + > > +#define CCB_SMB_MSTRRDBYTECNT_MASK 0x000000FF > > +#define CCB_SMB_MSTRRDBYTECNT_SHIFT 0 > > + > > +#define CCB_SMB_SLVCMD_REG 0x34 > > + > > +#define CCB_SMB_SLVSTARTBUSYCMD_MASK 0x80000000 > > +#define CCB_SMB_SLVSTARTBUSYCMD_SHIFT 31 > > + > > +#define CCB_SMB_SLVABORT_MASK 0x40000000 > > +#define CCB_SMB_SLVABORT_SHIFT 30 > > + > > +#define CCB_SMB_SLVSTS_MASK 0x03800000 > > +#define CCB_SMB_SLVSTS_SHIFT 23 > > + > > +#define CCB_SMB_SLVPEC_MASK 0x00000100 > > +#define CCB_SMB_SLVPEC_SHIFT 8 > > + > > +#define CCB_SMB_EVTEN_REG 0x38 > > + > > +#define CCB_SMB_MSTRRXFIFOFULLEN_MASK 0x80000000 > > +#define CCB_SMB_MSTRRXFIFOFULLEN_SHIFT 31 > > + > > +#define CCB_SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000 > > +#define CCB_SMB_MSTRRXFIFOTHRHITEN_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRXEVTEN_MASK 0x20000000 > > +#define CCB_SMB_MSTRRXEVTEN_SHIFT 29 > > + > > +#define CCB_SMB_MSTRSTARTBUSYEN_MASK 0x10000000 > > +#define CCB_SMB_MSTRSTARTBUSYEN_SHIFT 28 > > + > > +#define CCB_SMB_MSTRTXUNDEN_MASK 0x08000000 > > +#define CCB_SMB_MSTRTXUNDEN_SHIFT 27 > > + > > +#define CCB_SMB_SLVRXFIFOFULLEN_MASK 0x04000000 > > +#define CCB_SMB_SLVRXFIFOFULLEN_SHIFT 26 > > + > > +#define CCB_SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000 > > +#define CCB_SMB_SLVRXFIFOTHRHITEN_SHIFT 25 > > + > > +#define CCB_SMB_SLVRXEVTEN_MASK 0x01000000 > > +#define CCB_SMB_SLVRXEVTEN_SHIFT 24 > > + > > +#define CCB_SMB_SLVSTARTBUSYEN_MASK 0x00800000 > > +#define CCB_SMB_SLVSTARTBUSYEN_SHIFT 23 > > + > > +#define CCB_SMB_SLVTXUNDEN_MASK 0x00400000 > > +#define CCB_SMB_SLVTXUNDEN_SHIFT 22 > > + > > +#define CCB_SMB_SLVRDEVTEN_MASK 0x00200000 > > +#define CCB_SMB_SLVRDEVTEN_SHIFT 21 > > + > > +#define CCB_SMB_EVTSTS_REG 0x3C > > + > > +#define CCB_SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000 > > +#define CCB_SMB_MSTRRXFIFOFULLSTS_SHIFT 31 > > + > > +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000 > > +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRXEVTSTS_MASK 0x20000000 > > +#define CCB_SMB_MSTRRXEVTSTS_SHIFT 29 > > + > > +#define CCB_SMB_MSTRSTARTBUSYSTS_MASK 0x10000000 > > +#define CCB_SMB_MSTRSTARTBUSYSTS_SHIFT 28 > > + > > +#define CCB_SMB_MSTRTXUNDSTS_MASK 0x08000000 > > +#define CCB_SMB_MSTRTXUNDSTS_SHIFT 27 > > + > > +#define CCB_SMB_SLVRXFIFOFULLSTS_MASK 0x04000000 > > +#define CCB_SMB_SLVRXFIFOFULLSTS_SHIFT 26 > > + > > +#define CCB_SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000 > > +#define CCB_SMB_SLVRXFIFOTHRHITSTS_SHIFT 25 > > + > > +#define CCB_SMB_SLVRXEVTSTS_MASK 0x01000000 > > +#define CCB_SMB_SLVRXEVTSTS_SHIFT 24 > > + > > +#define CCB_SMB_SLVSTARTBUSYSTS_MASK 0x00800000 > > +#define CCB_SMB_SLVSTARTBUSYSTS_SHIFT 23 > > + > > +#define CCB_SMB_SLVTXUNDSTS_MASK 0x00400000 > > +#define CCB_SMB_SLVTXUNDSTS_SHIFT 22 > > + > > +#define CCB_SMB_SLVRDEVTSTS_MASK 0x00200000 > > +#define CCB_SMB_SLVRDEVTSTS_SHIFT 21 > > + > > +#define CCB_SMB_MSTRDATAWR_REG 0x40 > > + > > +#define CCB_SMB_MSTRWRSTS_MASK 0x80000000 > > +#define CCB_SMB_MSTRWRSTS_SHIFT 31 > > + > > +#define CCB_SMB_MSTRWRDATA_MASK 0x000000FF > > +#define CCB_SMB_MSTRWRDATA_SHIFT 0 > > + > > +#define CCB_SMB_MSTRDATARD_REG 0x44 > > + > > +#define CCB_SMB_MSTRRDSTS_MASK 0xC0000000 > > +#define CCB_SMB_MSTRRDSTS_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRDPECERR_MASK 0x20000000 > > +#define CCB_SMB_MSTRRDPECERR_SHIFT 29 > > + > > +#define CCB_SMB_MSTRRDDATA_MASK 0x000000FF > > +#define CCB_SMB_MSTRRDDATA_SHIFT 0 > > + > > +#define CCB_SMB_SLVDATAWR_REG 0x48 > > + > > +#define CCB_SMB_SLVWRSTS_MASK 0x80000000 > > +#define CCB_SMB_SLVWRSTS_SHIFT 31 > > + > > +#define CCB_SMB_SLVWRDATA_MASK 0x000000FF > > +#define CCB_SMB_SLVWRDATA_SHIFT 0 > > + > > +#define CCB_SMB_SLVDATARD_REG 0x4C > > + > > +#define CCB_SMB_SLVRDSTS_MASK 0xC0000000 > > +#define CCB_SMB_SLVRDSTS_SHIFT 30 > > + > > +#define CCB_SMB_SLVRDERRSTS_MASK 0x30000000 > > +#define CCB_SMB_SLVRDERRSTS_SHIFT 28 > > + > > +#define CCB_SMB_SLVRDDATA_MASK 0x000000FF > > +#define CCB_SMB_SLVRDDATA_SHIFT 0 > > + > > +/* --Registers-- */ > > + > > +/* Transaction error codes defined in Master command register (0x30) */ > > +#define MSTR_STS_XACT_SUCCESS 0 > > +#define MSTR_STS_LOST_ARB 1 > > +#define MSTR_STS_NACK_FIRST_BYTE 2 > > + > > +/* NACK on a byte other than > > + * the first byte > > + */ > > +#define MSTR_STS_NACK_NON_FIRST_BYTE 3 > > + > > +#define MSTR_STS_TTIMEOUT_EXCEEDED 4 > > +#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5 > > +#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6 > > + > > +/* SMBUS protocol values defined in register 0x30 */ > > +#define SMBUS_PROT_QUICK_CMD 0 > > +#define SMBUS_PROT_SEND_BYTE 1 > > +#define SMBUS_PROT_RECV_BYTE 2 > > +#define SMBUS_PROT_WR_BYTE 3 > > +#define SMBUS_PROT_RD_BYTE 4 > > +#define SMBUS_PROT_WR_WORD 5 > > +#define SMBUS_PROT_RD_WORD 6 > > +#define SMBUS_PROT_BLK_WR 7 > > +#define SMBUS_PROT_BLK_RD 8 > > +#define SMBUS_PROT_PROC_CALL 9 > > +#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10 > > + > > +/* SMBUS Block speed mode */ > > +#define SMBUS_BLOCK_MODE_100 0 > > +#define SMBUS_BLOCK_MODE_400 1 > > + > > +#define BUS_BUSY_COUNT 100000 /* Number can be changed later */ > > +#define IPROC_I2C_INVALID_ADDR 0xFF > > +#define IPROC_SMB_MAX_RETRIES 35 > > +#define I2C_SMBUS_BLOCK_MAX 32 > > +#define GETREGFLDVAL(regval, mask, startbit) \ > > + (((regval) & (mask)) >> (startbit)) > > +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ > > + ((regval) & ~(mask)) | \ > > + ((fldval) << (startbit)) > > checkpatch complains with a warning: > > CHECK: Macro argument reuse 'regval' - possible side-effects? > #1981: FILE: drivers/i2c/iproc_i2c.h:306: > +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ > > + ((regval) & ~(mask)) | \ > > + ((fldval) << (startbit)) > > > > > > + > > +/* Enum to specify clock speed. The user will provide it during initialization > > + * If needed, it can be changed dynamically > > + */ > > +enum iproc_smb_clk_freq { > > + I2C_SPEED_100KHZ = 100000, > > + I2C_SPEED_400KHZ = 400000, > > + I2C_SPEED_INVALID = 255 > > +}; > > + > > +/* This enum will be used to notify the user of status of a data transfer > > + * request > > + */ > > +enum iproc_smb_error_code { > > + I2C_NO_ERR = 0, > > + I2C_TIMEOUT_ERR = 1, > > + > > + /* Invalid parameter(s) passed to the driver */ > > + I2C_INVALID_PARAM_ERR = 2, > > + > > + /* The driver API was called before the present > > + * transfer was completed > > + */ > > + I2C_OPER_IN_PROGRESS = 3, > > + > > + /* Transfer aborted unexpectedly, for example a NACK > > + * received, before last byte was read/written > > + */ > > + I2C_OPER_ABORT_ERR = 4, > > + > > + /* Feature or function not supported > > + * (e.g., 10-bit addresses, or clock speeds > > + * other than 100KHz, 400KHz) > > + */ > > + I2C_FUNC_NOT_SUPPORTED = 5, > > +}; > > + > > +/* Structure used to pass information to read/write functions. */ > > +struct iproc_xact_info { > > + unsigned char command; > > + unsigned char *data; > > + unsigned int size; > > + unsigned short flags; /* used for specifying PEC, 10-bit addresses */ > > + unsigned char smb_proto; /* SMBus protocol */ > > + unsigned int cmd_valid; /* true if command is valid else false */ > > +}; > > + > > +#endif /* __IPROC_I2C_H__ */ > > Hi Heiko, Thank you so much for detaild review. I wil fix all these and push v2. > -- > DENX Software Engineering GmbH, Managing Director: Wolfgang Denk > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany > Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs@denx.de
On Mon, Nov 25, 2019 at 2:05 PM Heiko Schocher <hs@denx.de> wrote: > > Hello Vladimir, > > Am 22.11.2019 um 22:20 schrieb Vladimir Olovyannikov: > > From: Arjun Jyothi <arjun.jyothi@broadcom.com> > > > > Add I2C driver support for Broadcom iproc-based socs. > > > > Signed-off-by: Arjun Jyothi <arjun.jyothi@broadcom.com> > > Signed-off-by: Rayagonda Kokatanur <rayagonda.kokatanur@broadcom.com> > > Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com> > > Signed-off-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com> > > --- > > drivers/i2c/Kconfig | 623 ++++++++++++++++---------------- > > drivers/i2c/Makefile | 2 +- > > drivers/i2c/iproc_i2c.c | 765 ++++++++++++++++++++++++++++++++++++++++ > > drivers/i2c/iproc_i2c.h | 356 +++++++++++++++++++ > > 4 files changed, 1437 insertions(+), 309 deletions(-) > > create mode 100644 drivers/i2c/iproc_i2c.c > > create mode 100644 drivers/i2c/iproc_i2c.h > > > > diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig > > index 03d2fed341..7a80971b12 100644 > > --- a/drivers/i2c/Kconfig > > +++ b/drivers/i2c/Kconfig > > @@ -5,454 +5,461 @@ > > menu "I2C support" > > > > config DM_I2C > > - bool "Enable Driver Model for I2C drivers" > > - depends on DM > > - help > > - Enable driver model for I2C. The I2C uclass interface: probe, read, > > - write and speed, is implemented with the bus drivers operations, > > - which provide methods for bus setting and data transfer. Each chip > > - device (bus child) info is kept as parent platdata. The interface > > - is defined in include/i2c.h. > > + bool "Enable Driver Model for I2C drivers" > > + depends on DM > > + help > > + Enable driver model for I2C. The I2C uclass interface: probe, read, > > + write and speed, is implemented with the bus drivers operations, > > + which provide methods for bus setting and data transfer. Each chip > > + device (bus child) info is kept as parent platdata. The interface > > + is defined in include/i2c.h. > > This (and a lot of following) change removes tabs with spaces, NACK. > > Please do not remove the tabs! > > > config I2C_CROS_EC_TUNNEL > > - tristate "Chrome OS EC tunnel I2C bus" > > - depends on CROS_EC > > - help > > - This provides an I2C bus that will tunnel i2c commands through to > > - the other side of the Chrome OS EC to the I2C bus connected there. > > - This will work whatever the interface used to talk to the EC (SPI, > > - I2C or LPC). Some Chromebooks use this when the hardware design > > - does not allow direct access to the main PMIC from the AP. > > + tristate "Chrome OS EC tunnel I2C bus" > > + depends on CROS_EC > > + help > > + This provides an I2C bus that will tunnel i2c commands through to > > + the other side of the Chrome OS EC to the I2C bus connected there. > > + This will work whatever the interface used to talk to the EC (SPI, > > + I2C or LPC). Some Chromebooks use this when the hardware design > > + does not allow direct access to the main PMIC from the AP. > > > > config I2C_CROS_EC_LDO > > - bool "Provide access to LDOs on the Chrome OS EC" > > - depends on CROS_EC > > - ---help--- > > - On many Chromebooks the main PMIC is inaccessible to the AP. This is > > - often dealt with by using an I2C pass-through interface provided by > > - the EC. On some unfortunate models (e.g. Spring) the pass-through > > - is not available, and an LDO message is available instead. This > > - option enables a driver which provides very basic access to those > > - regulators, via the EC. We implement this as an I2C bus which > > - emulates just the TPS65090 messages we know about. This is done to > > - avoid duplicating the logic in the TPS65090 regulator driver for > > - enabling/disabling an LDO. > > + bool "Provide access to LDOs on the Chrome OS EC" > > + depends on CROS_EC > > + ---help--- > > + On many Chromebooks the main PMIC is inaccessible to the AP. This is > > + often dealt with by using an I2C pass-through interface provided by > > + the EC. On some unfortunate models (e.g. Spring) the pass-through > > + is not available, and an LDO message is available instead. This > > + option enables a driver which provides very basic access to those > > + regulators, via the EC. We implement this as an I2C bus which > > + emulates just the TPS65090 messages we know about. This is done to > > + avoid duplicating the logic in the TPS65090 regulator driver for > > + enabling/disabling an LDO. > > > > config I2C_SET_DEFAULT_BUS_NUM > > - bool "Set default I2C bus number" > > - depends on DM_I2C > > - help > > - Set default number of I2C bus to be accessed. This option provides > > - behaviour similar to old (i.e. pre DM) I2C bus driver. > > + bool "Set default I2C bus number" > > + depends on DM_I2C > > + help > > + Set default number of I2C bus to be accessed. This option provides > > + behaviour similar to old (i.e. pre DM) I2C bus driver. > > > > config I2C_DEFAULT_BUS_NUMBER > > - hex "I2C default bus number" > > - depends on I2C_SET_DEFAULT_BUS_NUM > > - default 0x0 > > - help > > - Number of default I2C bus to use > > + hex "I2C default bus number" > > + depends on I2C_SET_DEFAULT_BUS_NUM > > + default 0x0 > > + help > > + Number of default I2C bus to use > > > > config DM_I2C_GPIO > > - bool "Enable Driver Model for software emulated I2C bus driver" > > - depends on DM_I2C && DM_GPIO > > - help > > - Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO > > - configuration is given by the device tree. Kernel-style device tree > > - bindings are supported. > > - Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt > > + bool "Enable Driver Model for software emulated I2C bus driver" > > + depends on DM_I2C && DM_GPIO > > + help > > + Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO > > + configuration is given by the device tree. Kernel-style device tree > > + bindings are supported. > > + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt > > > > config SYS_I2C_AT91 > > - bool "Atmel I2C driver" > > - depends on DM_I2C && ARCH_AT91 > > - help > > - Add support for the Atmel I2C driver. A serious problem is that there > > - is no documented way to issue repeated START conditions for more than > > - two messages, as needed to support combined I2C messages. Use the > > - i2c-gpio driver unless your system can cope with this limitation. > > - Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > > + bool "Atmel I2C driver" > > + depends on DM_I2C && ARCH_AT91 > > + help > > + Add support for the Atmel I2C driver. A serious problem is that there > > + is no documented way to issue repeated START conditions for more than > > + two messages, as needed to support combined I2C messages. Use the > > + i2c-gpio driver unless your system can cope with this limitation. > > + Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > > + > > +config IPROC_I2C > > + bool "Broadcom iProc I2C driver" > > + depends on DM_I2C > > + help > > + Add support for Broadcom iProc I2C driver. > > + The driver is used in iProc SoCs. > > > > config SYS_I2C_FSL > > bool "Freescale I2C bus driver" > > depends on DM_I2C > > help > > - Add support for Freescale I2C busses as used on MPC8240, MPC8245, and > > - MPC85xx processors. > > + Add support for Freescale I2C busses as used on MPC8240, MPC8245, and > > + MPC85xx processors. > > > > config SYS_I2C_CADENCE > > - tristate "Cadence I2C Controller" > > - depends on DM_I2C && (ARCH_ZYNQ || ARM64) > > - help > > - Say yes here to select Cadence I2C Host Controller. This controller is > > - e.g. used by Xilinx Zynq. > > + tristate "Cadence I2C Controller" > > + depends on DM_I2C && (ARCH_ZYNQ || ARM64) > > + help > > + Say yes here to select Cadence I2C Host Controller. This controller is > > + e.g. used by Xilinx Zynq. > > > > config SYS_I2C_DAVINCI > > - bool "Davinci I2C Controller" > > - depends on (ARCH_KEYSTONE || ARCH_DAVINCI) > > - help > > - Say yes here to add support for Davinci and Keystone I2C controller > > + bool "Davinci I2C Controller" > > + depends on (ARCH_KEYSTONE || ARCH_DAVINCI) > > + help > > + Say yes here to add support for Davinci and Keystone I2C controller > > > > config SYS_I2C_DW > > - bool "Designware I2C Controller" > > - default n > > - help > > - Say yes here to select the Designware I2C Host Controller. This > > - controller is used in various SoCs, e.g. the ST SPEAr, Altera > > - SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. > > + bool "Designware I2C Controller" > > + default n > > + help > > + Say yes here to select the Designware I2C Host Controller. This > > + controller is used in various SoCs, e.g. the ST SPEAr, Altera > > + SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. > > > > config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED > > - bool "DW I2C Enable Status Register not supported" > > - depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ > > - TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) > > - default y > > - help > > - Some versions of the Designware I2C controller do not support the > > - enable status register. This config option can be enabled in such > > - cases. > > + bool "DW I2C Enable Status Register not supported" > > + depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ > > + TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) > > + default y > > + help > > + Some versions of the Designware I2C controller do not support the > > + enable status register. This config option can be enabled in such > > + cases. > > > > config SYS_I2C_ASPEED > > - bool "Aspeed I2C Controller" > > - depends on DM_I2C && ARCH_ASPEED > > - help > > - Say yes here to select Aspeed I2C Host Controller. The driver > > - supports AST2500 and AST2400 controllers, but is very limited. > > - Only single master mode is supported and only byte-by-byte > > - synchronous reads and writes are supported, no Pool Buffers or DMA. > > + bool "Aspeed I2C Controller" > > + depends on DM_I2C && ARCH_ASPEED > > + help > > + Say yes here to select Aspeed I2C Host Controller. The driver > > + supports AST2500 and AST2400 controllers, but is very limited. > > + Only single master mode is supported and only byte-by-byte > > + synchronous reads and writes are supported, no Pool Buffers or DMA. > > > > config SYS_I2C_INTEL > > - bool "Intel I2C/SMBUS driver" > > - depends on DM_I2C > > - help > > - Add support for the Intel SMBUS driver. So far this driver is just > > - a stub which perhaps some basic init. There is no implementation of > > - the I2C API meaning that any I2C operations will immediately fail > > - for now. > > + bool "Intel I2C/SMBUS driver" > > + depends on DM_I2C > > + help > > + Add support for the Intel SMBUS driver. So far this driver is just > > + a stub which perhaps some basic init. There is no implementation of > > + the I2C API meaning that any I2C operations will immediately fail > > + for now. > > > > config SYS_I2C_IMX_LPI2C > > - bool "NXP i.MX LPI2C driver" > > - help > > - Add support for the NXP i.MX LPI2C driver. > > + bool "NXP i.MX LPI2C driver" > > + help > > + Add support for the NXP i.MX LPI2C driver. > > > > config SYS_I2C_MESON > > - bool "Amlogic Meson I2C driver" > > - depends on DM_I2C && ARCH_MESON > > - help > > - Add support for the I2C controller available in Amlogic Meson > > - SoCs. The controller supports programmable bus speed including > > - standard (100kbits/s) and fast (400kbit/s) speed and allows the > > - software to define a flexible format of the bit streams. It has an > > - internal buffer holding up to 8 bytes for transfers and supports > > - both 7-bit and 10-bit addresses. > > + bool "Amlogic Meson I2C driver" > > + depends on DM_I2C && ARCH_MESON > > + help > > + Add support for the I2C controller available in Amlogic Meson > > + SoCs. The controller supports programmable bus speed including > > + standard (100kbits/s) and fast (400kbit/s) speed and allows the > > + software to define a flexible format of the bit streams. It has an > > + internal buffer holding up to 8 bytes for transfers and supports > > + both 7-bit and 10-bit addresses. > > > > config SYS_I2C_MXC > > - bool "NXP MXC I2C driver" > > - help > > - Add support for the NXP I2C driver. This supports up to four bus > > - channels and operating on standard mode up to 100 kbits/s and fast > > - mode up to 400 kbits/s. > > + bool "NXP MXC I2C driver" > > + help > > + Add support for the NXP I2C driver. This supports up to four bus > > + channels and operating on standard mode up to 100 kbits/s and fast > > + mode up to 400 kbits/s. > > > > # These settings are not used with DM_I2C, however SPL doesn't use > > # DM_I2C even if DM_I2C is enabled, and so might use these settings even > > # when main u-boot does not! > > if SYS_I2C_MXC && (!DM_I2C || SPL) > > config SYS_I2C_MXC_I2C1 > > - bool "NXP MXC I2C1" > > - help > > - Add support for NXP MXC I2C Controller 1. > > - Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A > > + bool "NXP MXC I2C1" > > + help > > + Add support for NXP MXC I2C Controller 1. > > + Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C2 > > - bool "NXP MXC I2C2" > > - help > > - Add support for NXP MXC I2C Controller 2. > > - Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A > > + bool "NXP MXC I2C2" > > + help > > + Add support for NXP MXC I2C Controller 2. > > + Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C3 > > - bool "NXP MXC I2C3" > > - help > > - Add support for NXP MXC I2C Controller 3. > > - Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A > > + bool "NXP MXC I2C3" > > + help > > + Add support for NXP MXC I2C Controller 3. > > + Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C4 > > - bool "NXP MXC I2C4" > > - help > > - Add support for NXP MXC I2C Controller 4. > > - Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A > > + bool "NXP MXC I2C4" > > + help > > + Add support for NXP MXC I2C Controller 4. > > + Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A > > > > config SYS_I2C_MXC_I2C5 > > - bool "NXP MXC I2C5" > > - help > > - Add support for NXP MXC I2C Controller 5. > > - Required for SoCs which have I2C MXC controller 5 eg LX2160A > > + bool "NXP MXC I2C5" > > + help > > + Add support for NXP MXC I2C Controller 5. > > + Required for SoCs which have I2C MXC controller 5 eg LX2160A > > > > config SYS_I2C_MXC_I2C6 > > - bool "NXP MXC I2C6" > > - help > > - Add support for NXP MXC I2C Controller 6. > > - Required for SoCs which have I2C MXC controller 6 eg LX2160A > > + bool "NXP MXC I2C6" > > + help > > + Add support for NXP MXC I2C Controller 6. > > + Required for SoCs which have I2C MXC controller 6 eg LX2160A > > > > config SYS_I2C_MXC_I2C7 > > - bool "NXP MXC I2C7" > > - help > > - Add support for NXP MXC I2C Controller 7. > > - Required for SoCs which have I2C MXC controller 7 eg LX2160A > > + bool "NXP MXC I2C7" > > + help > > + Add support for NXP MXC I2C Controller 7. > > + Required for SoCs which have I2C MXC controller 7 eg LX2160A > > > > config SYS_I2C_MXC_I2C8 > > - bool "NXP MXC I2C8" > > - help > > - Add support for NXP MXC I2C Controller 8. > > - Required for SoCs which have I2C MXC controller 8 eg LX2160A > > + bool "NXP MXC I2C8" > > + help > > + Add support for NXP MXC I2C Controller 8. > > + Required for SoCs which have I2C MXC controller 8 eg LX2160A > > endif > > > > if SYS_I2C_MXC_I2C1 > > config SYS_MXC_I2C1_SPEED > > - int "I2C Channel 1 speed" > > - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > - default 100000 > > - help > > - MXC I2C Channel 1 speed > > + int "I2C Channel 1 speed" > > + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > + default 100000 > > + help > > + MXC I2C Channel 1 speed > > > > config SYS_MXC_I2C1_SLAVE > > - int "I2C1 Slave" > > - default 0 > > - help > > - MXC I2C1 Slave > > + int "I2C1 Slave" > > + default 0 > > + help > > + MXC I2C1 Slave > > endif > > > > if SYS_I2C_MXC_I2C2 > > config SYS_MXC_I2C2_SPEED > > - int "I2C Channel 2 speed" > > - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > - default 100000 > > - help > > - MXC I2C Channel 2 speed > > + int "I2C Channel 2 speed" > > + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU > > + default 100000 > > + help > > + MXC I2C Channel 2 speed > > > > config SYS_MXC_I2C2_SLAVE > > - int "I2C2 Slave" > > - default 0 > > - help > > - MXC I2C2 Slave > > + int "I2C2 Slave" > > + default 0 > > + help > > + MXC I2C2 Slave > > endif > > > > if SYS_I2C_MXC_I2C3 > > config SYS_MXC_I2C3_SPEED > > - int "I2C Channel 3 speed" > > - default 100000 > > - help > > - MXC I2C Channel 3 speed > > + int "I2C Channel 3 speed" > > + default 100000 > > + help > > + MXC I2C Channel 3 speed > > > > config SYS_MXC_I2C3_SLAVE > > - int "I2C3 Slave" > > - default 0 > > - help > > - MXC I2C3 Slave > > + int "I2C3 Slave" > > + default 0 > > + help > > + MXC I2C3 Slave > > endif > > > > if SYS_I2C_MXC_I2C4 > > config SYS_MXC_I2C4_SPEED > > - int "I2C Channel 4 speed" > > - default 100000 > > - help > > - MXC I2C Channel 4 speed > > + int "I2C Channel 4 speed" > > + default 100000 > > + help > > + MXC I2C Channel 4 speed > > > > config SYS_MXC_I2C4_SLAVE > > - int "I2C4 Slave" > > - default 0 > > - help > > - MXC I2C4 Slave > > + int "I2C4 Slave" > > + default 0 > > + help > > + MXC I2C4 Slave > > endif > > > > if SYS_I2C_MXC_I2C5 > > config SYS_MXC_I2C5_SPEED > > - int "I2C Channel 5 speed" > > - default 100000 > > - help > > - MXC I2C Channel 5 speed > > + int "I2C Channel 5 speed" > > + default 100000 > > + help > > + MXC I2C Channel 5 speed > > > > config SYS_MXC_I2C5_SLAVE > > - int "I2C5 Slave" > > - default 0 > > - help > > - MXC I2C5 Slave > > + int "I2C5 Slave" > > + default 0 > > + help > > + MXC I2C5 Slave > > endif > > > > if SYS_I2C_MXC_I2C6 > > config SYS_MXC_I2C6_SPEED > > - int "I2C Channel 6 speed" > > - default 100000 > > - help > > - MXC I2C Channel 6 speed > > + int "I2C Channel 6 speed" > > + default 100000 > > + help > > + MXC I2C Channel 6 speed > > > > config SYS_MXC_I2C6_SLAVE > > - int "I2C6 Slave" > > - default 0 > > - help > > - MXC I2C6 Slave > > + int "I2C6 Slave" > > + default 0 > > + help > > + MXC I2C6 Slave > > endif > > > > if SYS_I2C_MXC_I2C7 > > config SYS_MXC_I2C7_SPEED > > - int "I2C Channel 7 speed" > > - default 100000 > > - help > > - MXC I2C Channel 7 speed > > + int "I2C Channel 7 speed" > > + default 100000 > > + help > > + MXC I2C Channel 7 speed > > > > config SYS_MXC_I2C7_SLAVE > > - int "I2C7 Slave" > > - default 0 > > - help > > - MXC I2C7 Slave > > + int "I2C7 Slave" > > + default 0 > > + help > > + MXC I2C7 Slave > > endif > > > > if SYS_I2C_MXC_I2C8 > > config SYS_MXC_I2C8_SPEED > > - int "I2C Channel 8 speed" > > - default 100000 > > - help > > - MXC I2C Channel 8 speed > > + int "I2C Channel 8 speed" > > + default 100000 > > + help > > + MXC I2C Channel 8 speed > > > > config SYS_MXC_I2C8_SLAVE > > - int "I2C8 Slave" > > - default 0 > > - help > > - MXC I2C8 Slave > > + int "I2C8 Slave" > > + default 0 > > + help > > + MXC I2C8 Slave > > endif > > > > config SYS_I2C_OMAP24XX > > - bool "TI OMAP2+ I2C driver" > > - depends on ARCH_OMAP2PLUS || ARCH_K3 > > - help > > - Add support for the OMAP2+ I2C driver. > > + bool "TI OMAP2+ I2C driver" > > + depends on ARCH_OMAP2PLUS || ARCH_K3 > > + help > > + Add support for the OMAP2+ I2C driver. > > > > if SYS_I2C_OMAP24XX > > config SYS_OMAP24_I2C_SLAVE > > - int "I2C Slave addr channel 0" > > - default 1 > > - help > > - OMAP24xx I2C Slave address channel 0 > > + int "I2C Slave addr channel 0" > > + default 1 > > + help > > + OMAP24xx I2C Slave address channel 0 > > > > config SYS_OMAP24_I2C_SPEED > > - int "I2C Slave channel 0 speed" > > - default 100000 > > - help > > - OMAP24xx Slave speed channel 0 > > + int "I2C Slave channel 0 speed" > > + default 100000 > > + help > > + OMAP24xx Slave speed channel 0 > > endif > > > > config SYS_I2C_RCAR_I2C > > - bool "Renesas RCar I2C driver" > > - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > - help > > - Support for Renesas RCar I2C controller. > > + bool "Renesas RCar I2C driver" > > + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > + help > > + Support for Renesas RCar I2C controller. > > > > config SYS_I2C_RCAR_IIC > > - bool "Renesas RCar Gen3 IIC driver" > > - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > - help > > - Support for Renesas RCar Gen3 IIC controller. > > + bool "Renesas RCar Gen3 IIC driver" > > + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C > > + help > > + Support for Renesas RCar Gen3 IIC controller. > > > > config SYS_I2C_ROCKCHIP > > - bool "Rockchip I2C driver" > > - depends on DM_I2C > > - help > > - Add support for the Rockchip I2C driver. This is used with various > > - Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips > > - have several I2C ports and all are provided, controlled by the > > - device tree. > > + bool "Rockchip I2C driver" > > + depends on DM_I2C > > + help > > + Add support for the Rockchip I2C driver. This is used with various > > + Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips > > + have several I2C ports and all are provided, controlled by the > > + device tree. > > > > config SYS_I2C_SANDBOX > > - bool "Sandbox I2C driver" > > - depends on SANDBOX && DM_I2C > > - help > > - Enable I2C support for sandbox. This is an emulation of a real I2C > > - bus. Devices can be attached to the bus using the device tree > > - which specifies the driver to use. See sandbox.dts as an example. > > + bool "Sandbox I2C driver" > > + depends on SANDBOX && DM_I2C > > + help > > + Enable I2C support for sandbox. This is an emulation of a real I2C > > + bus. Devices can be attached to the bus using the device tree > > + which specifies the driver to use. See sandbox.dts as an example. > > > > config SYS_I2C_S3C24X0 > > - bool "Samsung I2C driver" > > - depends on ARCH_EXYNOS4 && DM_I2C > > - help > > - Support for Samsung I2C controller as Samsung SoCs. > > + bool "Samsung I2C driver" > > + depends on ARCH_EXYNOS4 && DM_I2C > > + help > > + Support for Samsung I2C controller as Samsung SoCs. > > > > config SYS_I2C_STM32F7 > > - bool "STMicroelectronics STM32F7 I2C support" > > - depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C > > - help > > - Enable this option to add support for STM32 I2C controller > > - introduced with STM32F7/H7 SoCs. This I2C controller supports : > > - _ Slave and master modes > > - _ Multimaster capability > > - _ Standard-mode (up to 100 kHz) > > - _ Fast-mode (up to 400 kHz) > > - _ Fast-mode Plus (up to 1 MHz) > > - _ 7-bit and 10-bit addressing mode > > - _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) > > - _ All 7-bit addresses acknowledge mode > > - _ General call > > - _ Programmable setup and hold times > > - _ Easy to use event management > > - _ Optional clock stretching > > - _ Software reset > > + bool "STMicroelectronics STM32F7 I2C support" > > + depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C > > + help > > + Enable this option to add support for STM32 I2C controller > > + introduced with STM32F7/H7 SoCs. This I2C controller supports : > > + _ Slave and master modes > > + _ Multimaster capability > > + _ Standard-mode (up to 100 kHz) > > + _ Fast-mode (up to 400 kHz) > > + _ Fast-mode Plus (up to 1 MHz) > > + _ 7-bit and 10-bit addressing mode > > + _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) > > + _ All 7-bit addresses acknowledge mode > > + _ General call > > + _ Programmable setup and hold times > > + _ Easy to use event management > > + _ Optional clock stretching > > + _ Software reset > > > > config SYS_I2C_TEGRA > > - bool "NVIDIA Tegra internal I2C controller" > > - depends on TEGRA > > - help > > - Support for NVIDIA I2C controller available in Tegra SoCs. > > + bool "NVIDIA Tegra internal I2C controller" > > + depends on TEGRA > > + help > > + Support for NVIDIA I2C controller available in Tegra SoCs. > > > > config SYS_I2C_UNIPHIER > > - bool "UniPhier I2C driver" > > - depends on ARCH_UNIPHIER && DM_I2C > > - default y > > - help > > - Support for UniPhier I2C controller driver. This I2C controller > > - is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. > > + bool "UniPhier I2C driver" > > + depends on ARCH_UNIPHIER && DM_I2C > > + default y > > + help > > + Support for UniPhier I2C controller driver. This I2C controller > > + is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. > > > > config SYS_I2C_UNIPHIER_F > > - bool "UniPhier FIFO-builtin I2C driver" > > - depends on ARCH_UNIPHIER && DM_I2C > > - default y > > - help > > - Support for UniPhier FIFO-builtin I2C controller driver. > > - This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > > + bool "UniPhier FIFO-builtin I2C driver" > > + depends on ARCH_UNIPHIER && DM_I2C > > + default y > > + help > > + Support for UniPhier FIFO-builtin I2C controller driver. > > + This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > > > > config SYS_I2C_VERSATILE > > - bool "Arm Ltd Versatile I2C bus driver" > > - depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) > > - help > > - Add support for the Arm Ltd Versatile Express I2C driver. The I2C host > > - controller is present in the development boards manufactured by Arm Ltd. > > + bool "Arm Ltd Versatile I2C bus driver" > > + depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) > > + help > > + Add support for the Arm Ltd Versatile Express I2C driver. The I2C host > > + controller is present in the development boards manufactured by Arm Ltd. > > > > config SYS_I2C_MVTWSI > > - bool "Marvell I2C driver" > > - depends on DM_I2C > > - help > > - Support for Marvell I2C controllers as used on the orion5x and > > - kirkwood SoC families. > > + bool "Marvell I2C driver" > > + depends on DM_I2C > > + help > > + Support for Marvell I2C controllers as used on the orion5x and > > + kirkwood SoC families. > > > > config TEGRA186_BPMP_I2C > > - bool "Enable Tegra186 BPMP-based I2C driver" > > - depends on TEGRA186_BPMP > > - help > > - Support for Tegra I2C controllers managed by the BPMP (Boot and > > - Power Management Processor). On Tegra186, some I2C controllers are > > - directly controlled by the main CPU, whereas others are controlled > > - by the BPMP, and can only be accessed by the main CPU via IPC > > - requests to the BPMP. This driver covers the latter case. > > + bool "Enable Tegra186 BPMP-based I2C driver" > > + depends on TEGRA186_BPMP > > + help > > + Support for Tegra I2C controllers managed by the BPMP (Boot and > > + Power Management Processor). On Tegra186, some I2C controllers are > > + directly controlled by the main CPU, whereas others are controlled > > + by the BPMP, and can only be accessed by the main CPU via IPC > > + requests to the BPMP. This driver covers the latter case. > > > > config SYS_I2C_BUS_MAX > > - int "Max I2C busses" > > - depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA > > - default 2 if TI816X > > - default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE > > - default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X > > - default 5 if OMAP54XX > > - help > > - Define the maximum number of available I2C buses. > > + int "Max I2C busses" > > + depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA > > + default 2 if TI816X > > + default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE > > + default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X > > + default 5 if OMAP54XX > > + help > > + Define the maximum number of available I2C buses. > > > > config SYS_I2C_XILINX_XIIC > > - bool "Xilinx AXI I2C driver" > > - depends on DM_I2C > > - help > > - Support for Xilinx AXI I2C controller. > > + bool "Xilinx AXI I2C driver" > > + depends on DM_I2C > > + help > > + Support for Xilinx AXI I2C controller. > > > > config SYS_I2C_IHS > > bool "gdsys IHS I2C driver" > > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > > index c2f75d8755..7cfe68e088 100644 > > --- a/drivers/i2c/Makefile > > +++ b/drivers/i2c/Makefile > > @@ -38,5 +38,5 @@ obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o > > obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o > > obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o > > obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o > > - > > +obj-$(CONFIG_IPROC_I2C) += iproc_i2c.o > > please keep lists sorted! > (Same applies to your "drivers: pcie: Add Broadcom IPROC PCIe driver" patch) > > > obj-$(CONFIG_I2C_MUX) += muxes/ > > diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c > > new file mode 100644 > > index 0000000000..692035666c > > --- /dev/null > > +++ b/drivers/i2c/iproc_i2c.c > > @@ -0,0 +1,765 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright (C)) 2018 Broadcom > > + */ > > + > > +#include <common.h> > > +#include <config.h> > > +#include <dm.h> > > +#include <i2c.h> > > +#include <asm/io.h> > > +#include "errno.h" > > +#include "iproc_i2c.h" > > + > > +DECLARE_GLOBAL_DATA_PTR; > > + > > +static int i2c_init_done; > > + > > +struct iproc_i2c_regs { > > + u32 cfg_reg; > > + u32 timg_cfg; > > + u32 addr_reg; > > + u32 mstr_fifo_ctrl; > > + u32 slv_fifo_ctrl; > > + u32 bitbng_ctrl; > > + u32 blnks[6]; /* Not to be used */ > > + u32 mstr_cmd; > > + u32 slv_cmd; > > + u32 evt_en; > > + u32 evt_sts; > > + u32 mstr_datawr; > > + u32 mstr_datard; > > + u32 slv_datawr; > > + u32 slv_datard; > > +}; > > + > > +struct iproc_i2c { > > + struct iproc_i2c_regs __iomem *base; /* register base */ > > + int bus_speed; > > +}; > > + > > +/* Function to read a value from specified register. */ > > +static unsigned int iproc_i2c_reg_read(u32 *reg_addr) > > +{ > > + unsigned int val; > > + > > + val = readl((void *)(reg_addr)); > > + return cpu_to_le32(val); > > +} > > + > > +/* Function to write a value ('val') in to a specified register. */ > > +static int iproc_i2c_reg_write(u32 *reg_addr, unsigned int val) > > +{ > > + val = cpu_to_le32(val); > > + writel(val, (void *)(reg_addr)); > > + return 0; > > +} > > + > > +#ifdef IPROC_I2C_DBG > > Can you add this define at least through Kconfig ? > > Do we need this define? debug() should be dropped if DEBUG is > not defined... and you can do here > > #if defined(DEBUG) > static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) > [...] > #else > static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata){ > return 0; > } > #endif > > and drop all later "ifdef IPROC_I2C_DBG" stuff... > > > +static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > + debug("\n----------------------------------------------\n"); > > + debug("%s: Dumping SMBus registers...\n", __func__); > > + > > + regval = iproc_i2c_reg_read(&base->cfg_reg); > > + debug("CCB_SMB_CFG_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->timg_cfg); > > + debug("CCB_SMB_TIMGCFG_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->addr_reg); > > + debug("CCB_SMB_ADDR_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_fifo_ctrl); > > + debug("CCB_SMB_MSTRFIFOCTL_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_fifo_ctrl); > > + debug("CCB_SMB_SLVFIFOCTL_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->bitbng_ctrl); > > + debug("CCB_SMB_BITBANGCTL_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + debug("CCB_SMB_MSTRCMD_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_cmd); > > + debug("CCB_SMB_SLVCMD_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->evt_en); > > + debug("CCB_SMB_EVTEN_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->evt_sts); > > + debug("CCB_SMB_EVTSTS_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_datawr); > > + debug("CCB_SMB_MSTRDATAWR_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_datard); > > + debug("CCB_SMB_MSTRDATARD_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_datawr); > > + debug("CCB_SMB_SLVDATAWR_REG=0x%08X\n", regval); > > + > > + regval = iproc_i2c_reg_read(&base->slv_datard); > > + debug("CCB_SMB_SLVDATARD_REG=0x%08X\n", regval); > > + > > + debug("----------------------------------------------\n\n"); > > + return 0; > > +} > > +#endif > > + > > +/* > > + * Function to ensure that the previous transaction was completed before > > + * initiating a new transaction. It can also be used in polling mode to > > + * check status of completion of a command > > + */ > > +static int iproc_i2c_startbusy_wait(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + > > + /* Check if an operation is in progress. During probe it won't be. > > + * But when shutdown/remove was called we want to make sure that > > + * the transaction in progress completed > > + */ > > + if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > > + unsigned int i = 0; > > + > > + do { > > + mdelay(10); /* Wait for 10 msec */ > > Please remove this comment. > > > + i++; > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + > > + /* If start-busy bit cleared, exit the loop */ > > + } while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) && > > + (i < IPROC_SMB_MAX_RETRIES)); > > + > > + if (i >= IPROC_SMB_MAX_RETRIES) { > > + pr_err("%s: START_BUSY bit didn't clear, exiting\n", > > + __func__); > > + > > + return -ETIMEDOUT; > > + } > > + } > > + return 0; > > +} > > + > > +/* > > + * This function set clock frequency for SMBus block. As per hardware > > + * engineering, the clock frequency can be changed dynamically. > > + */ > > +static int iproc_i2c_set_clk_freq(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > + regval = iproc_i2c_reg_read(&base->timg_cfg); > > + > > + switch (bus_prvdata->bus_speed) { > > + case I2C_SPEED_100KHZ: > > + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_100, > > + CCB_SMB_TIMGCFG_MODE400_MASK, > > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > > + break; > > + > > + case I2C_SPEED_400KHZ: > > + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_400, > > + CCB_SMB_TIMGCFG_MODE400_MASK, > > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > > + break; > > + > > + default: > > + return -EINVAL; > > + } > > + > > + iproc_i2c_reg_write(&base->timg_cfg, regval); > > + return 0; > > +} > > + > > +static int iproc_i2c_init(struct iproc_i2c *bus_prvdata) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("\n%s: Entering", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + /* Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0. > > + * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts > > + */ > > + regval = CCB_SMB_MSTRRXFIFOFLSH_MASK | CCB_SMB_MSTRTXFIFOFLSH_MASK; > > + iproc_i2c_reg_write(&base->mstr_fifo_ctrl, regval); > > + > > + /* Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero > > + * since there will be only one master > > + */ > > + > > + regval = iproc_i2c_reg_read(&base->cfg_reg); > > + regval |= CCB_SMB_CFG_SMBEN_MASK; > > + iproc_i2c_reg_write(&base->cfg_reg, regval); > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > What are this defines? Wbere come they from ? They are not in current mainline > code: > > pollux:u-boot hs [work] $ grep -lr CONFIG_CYGNUS . > ./mbox > pollux:u-boot hs [work] $ grep -lr BCMOMEGA . > ./mbox > pollux:u-boot hs [work] $ > > please remove this code. Also this seems board specific code. We should > prevent this in common driver code! > > > + regval = iproc_i2c_reg_read(&base->cfg_reg); > > + regval |= CCB_SMB_CFG_RST_MASK; > > + iproc_i2c_reg_write(&base->cfg_reg, regval); > > + regval &= ~CCB_SMB_CFG_RST_MASK; > > + iproc_i2c_reg_write(&base->cfg_reg, regval); > > +#endif > > + /* Wait a minimum of 50 Usec, as per SMB hw doc */ > > + udelay(50); > > linux driver waits here for 100usec ... with the comment "per spec" ... > and flushes the FIFO after ... but I have no insight into this hardware, > so cannot say, what the better procedure... > > > + > > + /* Set default clock frequency */ > > + iproc_i2c_set_clk_freq(bus_prvdata); > > + > > + /* Disable intrs */ > > + iproc_i2c_reg_write(&base->evt_en, 0); > > + > > + /* Clear intrs (W1TC) */ > > + regval = iproc_i2c_reg_read(&base->evt_sts); > > + iproc_i2c_reg_write(&base->evt_sts, regval); > > + > > + i2c_init_done = 1; > > Why you need this global variable ? Please store this variable > in "iproc_i2c" > > > + > > +#ifdef IPROC_I2C_DBG > > + iproc_dump_i2c_regs(bus_prvdata); > > + > > + debug("%s: Init successful\n", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + return 0; > > +} > > + > > +/* > > + * This function copies data to SMBus's Tx FIFO. Valid for write transactions > > + * only > > + * > > + * base_addr: Mapped address of this SMBus instance > > + * dev_addr: SMBus (I2C) device address. We are assuming 7-bit addresses > > + * initially > > + * info: Data to copy in to Tx FIFO. For read commands, the size should be > > + * set to zero by the caller > > + * > > + */ > > +static void iproc_i2c_write_trans_data(struct iproc_i2c *bus_prvdata, > > + unsigned short dev_addr, > > + struct iproc_xact_info *info) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + unsigned int i; > > + unsigned int num_data_bytes = 0; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("%s: dev_addr=0x%X cmd_valid=%d cmd=0x%02x size=%u proto=%d\n" > > + "buf[] %x\n", > > + __func__, > > + dev_addr, > > + info->cmd_valid, > > + info->command, > > + info->size, > > + info->smb_proto, > > + info->data[0]); > > +#endif /* IPROC_I2C_DBG */ > > + > > + /* Write SMBus device address first */ > > + /* Note, we are assuming 7-bit addresses for now. For 10-bit addresses, > > + * we may have one more write to send the upper 3 bits of 10-bit addr > > + */ > > + iproc_i2c_reg_write(&base->mstr_datawr, dev_addr); > > + > > + /* If the protocol needs command code, copy it */ > > + if (info->cmd_valid) > > + iproc_i2c_reg_write(&base->mstr_datawr, info->command); > > + > > + /* Depending on the SMBus protocol, we need to write additional > > + * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus > > + * spec for sequence for a transaction > > + */ > > + switch (info->smb_proto) { > > + case SMBUS_PROT_RECV_BYTE: > > + /* No additional data to be written */ > > + num_data_bytes = 0; > > + break; > > + > > + case SMBUS_PROT_SEND_BYTE: > > + num_data_bytes = info->size; > > + break; > > + > > + case SMBUS_PROT_RD_BYTE: > > + case SMBUS_PROT_RD_WORD: > > + case SMBUS_PROT_BLK_RD: > > + /* Write slave address with R/W~ set (bit #0) */ > > + iproc_i2c_reg_write(&base->mstr_datawr, > > + dev_addr | 0x1); > > + num_data_bytes = 0; > > + break; > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > + case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL: > > + iproc_i2c_reg_write(&base->mstr_datawr, > > + dev_addr | 0x1 | > > + CCB_SMB_MSTRWRSTS_MASK); > > + num_data_bytes = 0; > > + break; > > +#endif > > + case SMBUS_PROT_WR_BYTE: > > + case SMBUS_PROT_WR_WORD: > > + /* No additional bytes to be written. > > + * Data portion is written in the > > + * 'for' loop below > > + */ > > + num_data_bytes = info->size; > > + break; > > + > > + case SMBUS_PROT_BLK_WR: > > + /* 3rd byte is byte count */ > > + iproc_i2c_reg_write(&base->mstr_datawr, info->size); > > + num_data_bytes = info->size; > > + break; > > + > > + default: > > + break; > > + } > > + > > + /* Copy actual data from caller, next. In general, for reads, no data is > > + * copied > > + */ > > + for (i = 0; num_data_bytes; --num_data_bytes, i++) { > > + /* For the last byte, set MASTER_WR_STATUS bit */ > > + regval = (num_data_bytes == 1) ? > > + info->data[i] | CCB_SMB_MSTRWRSTS_MASK : > > + info->data[i]; > > + > > + iproc_i2c_reg_write(&base->mstr_datawr, regval); > > + } > > +} > > + > > +static int iproc_i2c_data_send(struct iproc_i2c *bus_prvdata, > > + unsigned short addr, > > + struct iproc_xact_info *info) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + int rc, retry = 3; unsigned int regval; > > + > > + /* Make sure the previous transaction completed */ > > + rc = iproc_i2c_startbusy_wait(bus_prvdata); > > + > > + if (rc < 0) { > > + pr_err("%s: Send: bus is busy, exiting\n", __func__); > > + return rc; > > + } > > + > > + /* Write transaction bytes to Tx FIFO */ > > + iproc_i2c_write_trans_data(bus_prvdata, addr, info); > > + > > + /* Program master command register (0x30) with protocol type and set > > + * start_busy_command bit to initiate the write transaction > > + */ > > + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > > + CCB_SMB_MSTRSTARTBUSYCMD_MASK; > > + > > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > > + > > + /* Check for Master status */ > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > > + mdelay(10); > > + if (retry-- <= 0) > > + break; > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + } > > + > > + /* If start_busy bit cleared, check if there are any errors */ > > + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { > > + /* start_busy bit cleared, check master_status field now */ > > + regval &= CCB_SMB_MSTRSTS_MASK; > > + regval >>= CCB_SMB_MSTRSTS_SHIFT; > > + > > + if (regval != MSTR_STS_XACT_SUCCESS) { > > + /* Error We can flush Tx FIFO here */ > > + pr_err("%s: ERROR: Error in transaction %u, exiting\n", > > + __func__, regval); > > + return -EREMOTEIO; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int iproc_i2c_data_recv(struct iproc_i2c *bus_prvdata, > > + unsigned short addr, > > + struct iproc_xact_info *info, > > + unsigned int *num_bytes_read) > > +{ > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + int rc, retry = 3; > > + unsigned int regval; > > + > > + /* Make sure the previous transaction completed */ > > + rc = iproc_i2c_startbusy_wait(bus_prvdata); > > + > > + if (rc < 0) { > > + pr_err("%s: Receive: Bus is busy, exiting\n", __func__); > > + return rc; > > + } > > + > > + /* Program all transaction bytes into master Tx FIFO */ > > + iproc_i2c_write_trans_data(bus_prvdata, addr, info); > > + > > + /* Program master command register (0x30) with protocol type and set > > + * start_busy_command bit to initiate the write transaction > > + */ > > + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > > + CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size; > > + > > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > > + > > + /* Check for Master status */ > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { > > + udelay(1000); > > + if (retry-- <= 0) > > + break; > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + } > > + > > + /* If start_busy bit cleared, check if there are any errors */ > > + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { > > + /* start_busy bit cleared, check master_status field now */ > > + regval &= CCB_SMB_MSTRSTS_MASK; > > + regval >>= CCB_SMB_MSTRSTS_SHIFT; > > + > > + if (regval != MSTR_STS_XACT_SUCCESS) { > > + /* We can flush Tx FIFO here */ > > + pr_err("%s: Error in transaction %d, exiting\n", > > + __func__, regval); > > + return -EREMOTEIO; > > + } > > + } > > + > > + /* Read received byte(s), after TX out address etc */ > > + regval = iproc_i2c_reg_read(&base->mstr_datard); > > + > > + /* For block read, protocol (hw) returns byte count, > > + * as the first byte > > + */ > > + if (info->smb_proto == SMBUS_PROT_BLK_RD) { > > + int i; > > + > > + *num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK; > > + > > + /* Limit to reading a max of 32 bytes only; just a safeguard. > > + * If # bytes read is a number > 32, check transaction set up, > > + * and contact hw engg. Assumption: PEC is disabled > > + */ > > + for (i = 0; > > + (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX); > > + i++) { > > + /* Read Rx FIFO for data bytes */ > > + regval = iproc_i2c_reg_read(&base->mstr_datard); > > + info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK; > > + } > > + } else { > > + /* 1 Byte data */ > > + *info->data = regval & CCB_SMB_MSTRRDDATA_MASK; > > + *num_bytes_read = 1; > > + } > > + > > + return 0; > > +} > > + > > +static int i2c_write_byte(struct iproc_i2c *bus_prvdata, > > + u8 devaddr, > > + u8 regoffset, > > + u8 value) > > +{ > > + int rc; > > + struct iproc_xact_info info; > > + > > + devaddr <<= 1; > > + > > + info.cmd_valid = 1; > > + info.command = (unsigned char)regoffset; > > + info.data = &value; > > + info.size = 1; > > + info.flags = 0; > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > unknown defines ... > > > + info.smb_proto = SMBUS_PROT_WR_WORD;/*SMBUS_PROT_WR_BYTE;*/ > > +#else > > + info.smb_proto = SMBUS_PROT_WR_BYTE; > > +#endif > > + /* Refer to i2c_smbus_write_byte params passed. */ > > + rc = iproc_i2c_data_send(bus_prvdata, devaddr, &info); > > + > > + if (rc < 0) { > > + pr_err("%s: %s error accessing device 0x%X\n", > > + __func__, "Write", devaddr); > > + return -EREMOTEIO; > > + } > > + > > + return 0; > > +} > > + > > +int i2c_write(struct iproc_i2c *bus_prvdata, > > + uchar chip, > > + uint regaddr, > > + int alen, > > + uchar *buffer, > > + int len) > > +{ > > + int i, data_len; > > + u8 *data; > > + > > + if (alen > 1) { > > + pr_err("I2C write: addr len %d not supported\n", alen); > > + return 1; > > + } > > + > > + if (regaddr + len > 256) { > > + pr_err("I2C write: address out of range\n"); > > + return 1; > > + } > > + > > + if (len < 1) { > > + pr_err("I2C write: Need offset addr and value\n"); > > + return 1; > > + } > > + > > + /* buffer contains offset addr followed by value to be written */ > > + regaddr = buffer[0]; > > + data = &buffer[1]; > > + data_len = len - 1; > > + > > + for (i = 0; i < data_len; i++) { > > + if (i2c_write_byte(bus_prvdata, chip, regaddr + i, data[i])) { > > + pr_err("I2C write (%d): I/O error\n", i); > > + iproc_i2c_init(bus_prvdata); > > + return 1; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int i2c_read_byte(struct iproc_i2c *bus_prvdata, > > + u8 devaddr, > > + u8 regoffset, > > + u8 *value) > > +{ > > + int rc; > > + struct iproc_xact_info info; > > + unsigned int num_bytes_read = 0; > > + > > + devaddr <<= 1; > > + > > + info.cmd_valid = 1; > > + info.command = (unsigned char)regoffset; > > + info.data = value; > > + info.size = 1; > > + info.flags = 0; > > +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) > > + info.smb_proto = SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL; > > +#else > > + info.smb_proto = SMBUS_PROT_RD_BYTE; > > +#endif > > + /* Refer to i2c_smbus_read_byte for params passed. */ > > + rc = iproc_i2c_data_recv(bus_prvdata, devaddr, &info, &num_bytes_read); > > + > > + if (rc < 0) { > > + pr_err("%s: %s error accessing device 0x%X\n", > > + __func__, "Read", devaddr); > > + return -EREMOTEIO; > > + } > > + > > + return 0; > > +} > > + > > +int i2c_read(struct iproc_i2c *bus_prvdata, > > + uchar chip, > > + uint addr, > > + int alen, > > + uchar *buffer, > > + int len) > > +{ > > + int i; > > + > > + if (alen > 1) { > > + pr_err("I2C read: addr len %d not supported\n", alen); > > + return 1; > > + } > > + > > + if (addr + len > 256) { > > + pr_err("I2C read: address out of range\n"); > > + return 1; > > + } > > You always pass addr = 0 and alen = 0 ... so this checks are useless (beside len check) > same for i2c_write ... > > > + > > + for (i = 0; i < len; i++) { > > + if (i2c_read_byte(bus_prvdata, chip, addr + i, &buffer[i])) { > > + pr_err("I2C read: I/O error\n"); > > + iproc_i2c_init(bus_prvdata); > > + return 1; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int iproc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + int ret = 0; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("%s: %d messages\n", __func__, nmsgs); > > +#endif > > + > > + for (; nmsgs > 0; nmsgs--, msg++) { > > + if (msg->flags & I2C_M_RD) > > + ret = i2c_read(bus_prvdata, > > + msg->addr, > > + 0, > > + 0, > > + msg->buf, > > + msg->len); > > + else > > + ret = i2c_write(bus_prvdata, > > + msg->addr, > > + 0, > > + 0, > > + msg->buf, > > + msg->len); > > + } > > + > > + return ret; > > +} > > + > > +static int iproc_i2c_probe_chip(struct udevice *bus, uint chip_addr, > > + uint chip_flags) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + u32 regval; > > + > > +#ifdef IPROC_I2C_DBG > > + debug("\n%s: Entering chip probe\n", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + /* Init internal regs, disable intrs (and then clear intrs), set fifo > > + * thresholds, etc. > > + */ > > + if (!i2c_init_done) > > + iproc_i2c_init(bus_prvdata); > > Couldn;t you store this "i2c_init_done" in bus_prvdata ? > > > + > > + regval = (chip_addr << 1); > > + iproc_i2c_reg_write(&base->mstr_datawr, regval); > > + regval = ((SMBUS_PROT_QUICK_CMD << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | > > + (1 << CCB_SMB_MSTRSTARTBUSYCMD_SHIFT)); > > + iproc_i2c_reg_write(&base->mstr_cmd, regval); > > + > > + do { > > + udelay(100); > > Is this delay somewhere described in a spec? > > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + regval &= CCB_SMB_MSTRSTARTBUSYCMD_MASK; > > + } while (regval); > > + > > + regval = iproc_i2c_reg_read(&base->mstr_cmd); > > + > > + if ((regval & CCB_SMB_MSTRSTS_MASK) != 0) > > + return -1; > > + > > +#ifdef IPROC_I2C_DBG > > + iproc_dump_i2c_regs(bus_prvdata); > > + > > + debug("%s: chip probe successful\n", __func__); > > +#endif /* IPROC_I2C_DBG */ > > + > > + return 0; > > +} > > + > > +static int iproc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + > > + bus_prvdata->bus_speed = speed; > > + if (iproc_i2c_set_clk_freq(bus_prvdata)) > > + return -EINVAL; > > couldn; t you return simply the return value from iproc_i2c_set_clk_freq()? > > > + > > + return 0; > > +} > > + > > +/** > > + * i2c_get_bus_speed - get i2c bus speed > > + * > > + * This function returns the speed of operation in Hz > > + */ > > +int iproc_i2c_get_bus_speed(struct udevice *bus) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + struct iproc_i2c_regs *base = bus_prvdata->base; > > + unsigned int regval; > > + unsigned int val; > > + > > + regval = iproc_i2c_reg_read(&base->timg_cfg); > > + val = GETREGFLDVAL(regval, CCB_SMB_TIMGCFG_MODE400_MASK, > > + CCB_SMB_TIMGCFG_MODE400_SHIFT); > > + switch (val) { > > + case 0: > > + return I2C_SPEED_100KHZ; > > + case 1: > > + return I2C_SPEED_400KHZ; > > + default: > > + return -EINVAL; > > + } > > + return -EINVAL; > > +} > > + > > +static int iproc_i2c_probe(struct udevice *bus) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + > > + return iproc_i2c_init(bus_prvdata); > > +} > > + > > +static int iproc_i2c_ofdata_to_platdata(struct udevice *bus) > > +{ > > + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); > > + int node = dev_of_offset(bus); > > + const void *blob = gd->fdt_blob; > > + > > + bus_prvdata->base = map_physmem(devfdt_get_addr(bus), > > + sizeof(void *), > > + MAP_NOCACHE); > > + > > + /* default 100KHz freq */ > > + bus_prvdata->bus_speed = fdtdec_get_int(blob, node, "bus-frequency", > > + I2C_SPEED_100KHZ); > > + > > + return 0; > > +} > > + > > +static const struct dm_i2c_ops iproc_i2c_ops = { > > + .xfer = iproc_i2c_xfer, > > + .probe_chip = iproc_i2c_probe_chip, > > + .set_bus_speed = iproc_i2c_set_bus_speed, > > + .get_bus_speed = iproc_i2c_get_bus_speed, > > +}; > > + > > +static const struct udevice_id iproc_i2c_ids[] = { > > + { .compatible = "brcm,iproc-i2c" }, > > + { } > > +}; > > + > > +U_BOOT_DRIVER(iproc_i2c) = { > > + .name = "iproc_i2c", > > + .id = UCLASS_I2C, > > + .of_match = iproc_i2c_ids, > > + .ofdata_to_platdata = iproc_i2c_ofdata_to_platdata, > > + .probe = iproc_i2c_probe, > > + .priv_auto_alloc_size = sizeof(struct iproc_i2c), > > + .ops = &iproc_i2c_ops, > > + .flags = DM_FLAG_PRE_RELOC, > > +}; > > diff --git a/drivers/i2c/iproc_i2c.h b/drivers/i2c/iproc_i2c.h > > new file mode 100644 > > index 0000000000..4f8d6ba2b2 > > --- /dev/null > > +++ b/drivers/i2c/iproc_i2c.h > > @@ -0,0 +1,356 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > +/* Copyright (C) 2018 Broadcom */ > > + > > +#ifndef __IPROC_I2C_H__ > > +#define __IPROC_I2C_H__ > > + > > +#if (defined(CONFIG_NS_PLUS) || defined(CONFIG_HELIX4)) > > again defines not in mainline! Please remove! > > > +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 > > +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 > > +#define IPROC_SMBUS_BASE_ADDR1 0x18038000 > > +#define IPROC_SMBUS_BASE_ADDR2 0x1803B000 > > +#elif (defined(CONFIG_CYGNUS)) > > +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 > > +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 > > +#define IPROC_SMBUS_BASE_ADDR1 0x18008000 > > +#define IPROC_SMBUS_BASE_ADDR2 0x1800B000 > > +#endif > > Hmm... couldn;t come this values through DTS ? > > SHADOW_CPY_BUFFER_ADDR1, SHADOW_CPY_BUFFER_ADDR2, IPROC_SMBUS_BASE_ADDR1 > and IPROC_SMBUS_BASE_ADDR2 not used in this patch in other places! > > So please remove this defines complete. > > > + > > +/* Registers */ > > +#define CCB_SMB_CFG_REG 0x0 > > + > > +#define CCB_SMB_CFG_RST_MASK 0x80000000 > > +#define CCB_SMB_CFG_RST_SHIFT 31 > > + > > +#define CCB_SMB_CFG_SMBEN_MASK 0x40000000 > > +#define CCB_SMB_CFG_SMBEN_SHIFT 30 > > + > > +#define CCB_SMB_CFG_BITBANGEN_MASK 0x20000000 > > +#define CCB_SMB_CFG_BITBANGEN_SHIFT 29 > > + > > +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000 > > +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28 > > + > > +#define CCB_SMB_CFG_PROMISCMODE_MASK 0x08000000 > > +#define CCB_SMB_CFG_PROMISCMODE_SHIFT 27 > > + > > +#define CCB_SMB_CFG_TSTMPCNTEN_MASK 0x04000000 > > +#define CCB_SMB_CFG_TSTMPCNTEN_SHIFT 26 > > + > > +#define CCB_SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000 > > +#define CCB_SMB_CFG_MSTRRTRYCNT_SHIFT 16 > > + > > +#define CCB_SMB_TIMGCFG_REG 0x4 > > + > > +#define CCB_SMB_TIMGCFG_MODE400_MASK 0x80000000 > > +#define CCB_SMB_TIMGCFG_MODE400_SHIFT 31 > > + > > +#define CCB_SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000 > > +#define CCB_SMB_TIMGCFG_RNDSLVSTR_SHIFT 24 > > + > > +#define CCB_SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000 > > +#define CCB_SMB_TIMGCFG_PERSLVSTR_SHIFT 16 > > + > > +#define CCB_SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00 > > +#define CCB_SMB_TIMGCFG_IDLTIME_SHIFT 8 > > + > > +#define CCB_SMB_ADDR_REG 0x8 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR3_MASK 0x80000000 > > +#define CCB_SMB_EN_NIC_SMBADDR3_SHIFT 31 > > + > > +#define CCB_SMB_NIC_SMBADDR3_MASK 0x7F000000 > > +#define CCB_SMB_NIC_SMBADDR3_SHIFT 24 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR2_MASK 0x00800000 > > +#define CCB_SMB_EN_NIC_SMBADDR2_SHIFT 23 > > + > > +#define CCB_SMB_NIC_SMBADDR2_MASK 0x007F0000 > > +#define CCB_SMB_NIC_SMBADDR2_SHIFT 16 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR1_MASK 0x00008000 > > +#define CCB_SMB_EN_NIC_SMBADDR1_SHIFT 15 > > + > > +#define CCB_SMB_NIC_SMBADDR1_MASK 0x00007F00 > > +#define CCB_SMB_NIC_SMBADDR1_SHIFT 8 > > + > > +#define CCB_SMB_EN_NIC_SMBADDR0_MASK 0x00000080 > > +#define CCB_SMB_EN_NIC_SMBADDR0_SHIFT 7 > > + > > +#define CCB_SMB_NIC_SMBADDR0_MASK 0x0000007F > > +#define CCB_SMB_NIC_SMBADDR0_SHIFT 0 > > + > > +#define CCB_SMB_MSTRFIFOCTL_REG 0xC > > + > > +#define CCB_SMB_MSTRRXFIFOFLSH_MASK 0x80000000 > > +#define CCB_SMB_MSTRRXFIFOFLSH_SHIFT 31 > > + > > +#define CCB_SMB_MSTRTXFIFOFLSH_MASK 0x40000000 > > +#define CCB_SMB_MSTRTXFIFOFLSH_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRXPKTCNT_MASK 0x007F0000 > > +#define CCB_SMB_MSTRRXPKTCNT_SHIFT 16 > > + > > +#define CCB_SMB_MSTRRXFIFOTHR_MASK 0x00003F00 > > +#define CCB_SMB_MSTRRXFIFOTHR_SHIFT 8 > > + > > +#define CCB_SMB_SLVFIFOCTL_REG 0x10 > > + > > +#define CCB_SMB_SLVRXFIFOFLSH_MASK 0x80000000 > > +#define CCB_SMB_SLVRXFIFOFLSH_SHIFT 31 > > + > > +#define CCB_SMB_SLVTXFIFOFLSH_MASK 0x40000000 > > +#define CCB_SMB_SLVTXFIFOFLSH_SHIFT 30 > > + > > +#define CCB_SMB_SLVRXPKTCNT_MASK 0x007F0000 > > +#define CCB_SMB_SLVRXPKTCNT_SHIFT 16 > > + > > +#define CCB_SMB_SLVRXFIFOTHR_MASK 0x00003F00 > > +#define CCB_SMB_SLVRXFIFOTHR_SHIFT 8 > > + > > +#define CCB_SMB_BITBANGCTL_REG 0x14 > > + > > +#define CCB_SMB_SMBCLKIN_MASK 0x80000000 > > +#define CCB_SMB_SMBCLKIN_SHIFT 31 > > + > > +#define CCB_SMB_SMBCLKOUTEN_MASK 0x40000000 > > +#define CCB_SMB_SMBCLKOUTEN_SHIFT 30 > > + > > +#define CCB_SMB_SMBDATAIN_MASK 0x20000000 > > +#define CCB_SMB_SMBDATAIN_SHIFT 29 > > + > > +#define CCB_SMB_SMBDATAOUTEN_MASK 0x10000000 > > +#define CCB_SMB_SMBDATAOUTEN_SHIFT 28 > > + > > +#define CCB_SMB_MSTRCMD_REG 0x30 > > + > > +#define CCB_SMB_MSTRSTARTBUSYCMD_MASK 0x80000000 > > +#define CCB_SMB_MSTRSTARTBUSYCMD_SHIFT 31 > > + > > +#define CCB_SMB_MSTRABORT_MASK 0x40000000 > > +#define CCB_SMB_MSTRABORT_SHIFT 30 > > + > > +#define CCB_SMB_MSTRSTS_MASK 0x0E000000 > > +#define CCB_SMB_MSTRSTS_SHIFT 25 > > + > > +#define CCB_SMB_MSTRSMBUSPROTO_MASK 0x00001E00 > > +#define CCB_SMB_MSTRSMBUSPROTO_SHIFT 9 > > + > > +#define CCB_SMB_MSTRPEC_MASK 0x00000100 > > +#define CCB_SMB_MSTRPEC_SHIFT 8 > > + > > +#define CCB_SMB_MSTRRDBYTECNT_MASK 0x000000FF > > +#define CCB_SMB_MSTRRDBYTECNT_SHIFT 0 > > + > > +#define CCB_SMB_SLVCMD_REG 0x34 > > + > > +#define CCB_SMB_SLVSTARTBUSYCMD_MASK 0x80000000 > > +#define CCB_SMB_SLVSTARTBUSYCMD_SHIFT 31 > > + > > +#define CCB_SMB_SLVABORT_MASK 0x40000000 > > +#define CCB_SMB_SLVABORT_SHIFT 30 > > + > > +#define CCB_SMB_SLVSTS_MASK 0x03800000 > > +#define CCB_SMB_SLVSTS_SHIFT 23 > > + > > +#define CCB_SMB_SLVPEC_MASK 0x00000100 > > +#define CCB_SMB_SLVPEC_SHIFT 8 > > + > > +#define CCB_SMB_EVTEN_REG 0x38 > > + > > +#define CCB_SMB_MSTRRXFIFOFULLEN_MASK 0x80000000 > > +#define CCB_SMB_MSTRRXFIFOFULLEN_SHIFT 31 > > + > > +#define CCB_SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000 > > +#define CCB_SMB_MSTRRXFIFOTHRHITEN_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRXEVTEN_MASK 0x20000000 > > +#define CCB_SMB_MSTRRXEVTEN_SHIFT 29 > > + > > +#define CCB_SMB_MSTRSTARTBUSYEN_MASK 0x10000000 > > +#define CCB_SMB_MSTRSTARTBUSYEN_SHIFT 28 > > + > > +#define CCB_SMB_MSTRTXUNDEN_MASK 0x08000000 > > +#define CCB_SMB_MSTRTXUNDEN_SHIFT 27 > > + > > +#define CCB_SMB_SLVRXFIFOFULLEN_MASK 0x04000000 > > +#define CCB_SMB_SLVRXFIFOFULLEN_SHIFT 26 > > + > > +#define CCB_SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000 > > +#define CCB_SMB_SLVRXFIFOTHRHITEN_SHIFT 25 > > + > > +#define CCB_SMB_SLVRXEVTEN_MASK 0x01000000 > > +#define CCB_SMB_SLVRXEVTEN_SHIFT 24 > > + > > +#define CCB_SMB_SLVSTARTBUSYEN_MASK 0x00800000 > > +#define CCB_SMB_SLVSTARTBUSYEN_SHIFT 23 > > + > > +#define CCB_SMB_SLVTXUNDEN_MASK 0x00400000 > > +#define CCB_SMB_SLVTXUNDEN_SHIFT 22 > > + > > +#define CCB_SMB_SLVRDEVTEN_MASK 0x00200000 > > +#define CCB_SMB_SLVRDEVTEN_SHIFT 21 > > + > > +#define CCB_SMB_EVTSTS_REG 0x3C > > + > > +#define CCB_SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000 > > +#define CCB_SMB_MSTRRXFIFOFULLSTS_SHIFT 31 > > + > > +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000 > > +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRXEVTSTS_MASK 0x20000000 > > +#define CCB_SMB_MSTRRXEVTSTS_SHIFT 29 > > + > > +#define CCB_SMB_MSTRSTARTBUSYSTS_MASK 0x10000000 > > +#define CCB_SMB_MSTRSTARTBUSYSTS_SHIFT 28 > > + > > +#define CCB_SMB_MSTRTXUNDSTS_MASK 0x08000000 > > +#define CCB_SMB_MSTRTXUNDSTS_SHIFT 27 > > + > > +#define CCB_SMB_SLVRXFIFOFULLSTS_MASK 0x04000000 > > +#define CCB_SMB_SLVRXFIFOFULLSTS_SHIFT 26 > > + > > +#define CCB_SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000 > > +#define CCB_SMB_SLVRXFIFOTHRHITSTS_SHIFT 25 > > + > > +#define CCB_SMB_SLVRXEVTSTS_MASK 0x01000000 > > +#define CCB_SMB_SLVRXEVTSTS_SHIFT 24 > > + > > +#define CCB_SMB_SLVSTARTBUSYSTS_MASK 0x00800000 > > +#define CCB_SMB_SLVSTARTBUSYSTS_SHIFT 23 > > + > > +#define CCB_SMB_SLVTXUNDSTS_MASK 0x00400000 > > +#define CCB_SMB_SLVTXUNDSTS_SHIFT 22 > > + > > +#define CCB_SMB_SLVRDEVTSTS_MASK 0x00200000 > > +#define CCB_SMB_SLVRDEVTSTS_SHIFT 21 > > + > > +#define CCB_SMB_MSTRDATAWR_REG 0x40 > > + > > +#define CCB_SMB_MSTRWRSTS_MASK 0x80000000 > > +#define CCB_SMB_MSTRWRSTS_SHIFT 31 > > + > > +#define CCB_SMB_MSTRWRDATA_MASK 0x000000FF > > +#define CCB_SMB_MSTRWRDATA_SHIFT 0 > > + > > +#define CCB_SMB_MSTRDATARD_REG 0x44 > > + > > +#define CCB_SMB_MSTRRDSTS_MASK 0xC0000000 > > +#define CCB_SMB_MSTRRDSTS_SHIFT 30 > > + > > +#define CCB_SMB_MSTRRDPECERR_MASK 0x20000000 > > +#define CCB_SMB_MSTRRDPECERR_SHIFT 29 > > + > > +#define CCB_SMB_MSTRRDDATA_MASK 0x000000FF > > +#define CCB_SMB_MSTRRDDATA_SHIFT 0 > > + > > +#define CCB_SMB_SLVDATAWR_REG 0x48 > > + > > +#define CCB_SMB_SLVWRSTS_MASK 0x80000000 > > +#define CCB_SMB_SLVWRSTS_SHIFT 31 > > + > > +#define CCB_SMB_SLVWRDATA_MASK 0x000000FF > > +#define CCB_SMB_SLVWRDATA_SHIFT 0 > > + > > +#define CCB_SMB_SLVDATARD_REG 0x4C > > + > > +#define CCB_SMB_SLVRDSTS_MASK 0xC0000000 > > +#define CCB_SMB_SLVRDSTS_SHIFT 30 > > + > > +#define CCB_SMB_SLVRDERRSTS_MASK 0x30000000 > > +#define CCB_SMB_SLVRDERRSTS_SHIFT 28 > > + > > +#define CCB_SMB_SLVRDDATA_MASK 0x000000FF > > +#define CCB_SMB_SLVRDDATA_SHIFT 0 > > + > > +/* --Registers-- */ > > + > > +/* Transaction error codes defined in Master command register (0x30) */ > > +#define MSTR_STS_XACT_SUCCESS 0 > > +#define MSTR_STS_LOST_ARB 1 > > +#define MSTR_STS_NACK_FIRST_BYTE 2 > > + > > +/* NACK on a byte other than > > + * the first byte > > + */ > > +#define MSTR_STS_NACK_NON_FIRST_BYTE 3 > > + > > +#define MSTR_STS_TTIMEOUT_EXCEEDED 4 > > +#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5 > > +#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6 > > + > > +/* SMBUS protocol values defined in register 0x30 */ > > +#define SMBUS_PROT_QUICK_CMD 0 > > +#define SMBUS_PROT_SEND_BYTE 1 > > +#define SMBUS_PROT_RECV_BYTE 2 > > +#define SMBUS_PROT_WR_BYTE 3 > > +#define SMBUS_PROT_RD_BYTE 4 > > +#define SMBUS_PROT_WR_WORD 5 > > +#define SMBUS_PROT_RD_WORD 6 > > +#define SMBUS_PROT_BLK_WR 7 > > +#define SMBUS_PROT_BLK_RD 8 > > +#define SMBUS_PROT_PROC_CALL 9 > > +#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10 > > + > > +/* SMBUS Block speed mode */ > > +#define SMBUS_BLOCK_MODE_100 0 > > +#define SMBUS_BLOCK_MODE_400 1 > > + > > +#define BUS_BUSY_COUNT 100000 /* Number can be changed later */ > > +#define IPROC_I2C_INVALID_ADDR 0xFF > > +#define IPROC_SMB_MAX_RETRIES 35 > > +#define I2C_SMBUS_BLOCK_MAX 32 > > +#define GETREGFLDVAL(regval, mask, startbit) \ > > + (((regval) & (mask)) >> (startbit)) > > +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ > > + ((regval) & ~(mask)) | \ > > + ((fldval) << (startbit)) > > checkpatch complains with a warning: > > CHECK: Macro argument reuse 'regval' - possible side-effects? > #1981: FILE: drivers/i2c/iproc_i2c.h:306: > +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ > > + ((regval) & ~(mask)) | \ > > + ((fldval) << (startbit)) > > > > > > + > > +/* Enum to specify clock speed. The user will provide it during initialization > > + * If needed, it can be changed dynamically > > + */ > > +enum iproc_smb_clk_freq { > > + I2C_SPEED_100KHZ = 100000, > > + I2C_SPEED_400KHZ = 400000, > > + I2C_SPEED_INVALID = 255 > > +}; > > + > > +/* This enum will be used to notify the user of status of a data transfer > > + * request > > + */ > > +enum iproc_smb_error_code { > > + I2C_NO_ERR = 0, > > + I2C_TIMEOUT_ERR = 1, > > + > > + /* Invalid parameter(s) passed to the driver */ > > + I2C_INVALID_PARAM_ERR = 2, > > + > > + /* The driver API was called before the present > > + * transfer was completed > > + */ > > + I2C_OPER_IN_PROGRESS = 3, > > + > > + /* Transfer aborted unexpectedly, for example a NACK > > + * received, before last byte was read/written > > + */ > > + I2C_OPER_ABORT_ERR = 4, > > + > > + /* Feature or function not supported > > + * (e.g., 10-bit addresses, or clock speeds > > + * other than 100KHz, 400KHz) > > + */ > > + I2C_FUNC_NOT_SUPPORTED = 5, > > +}; > > + > > +/* Structure used to pass information to read/write functions. */ > > +struct iproc_xact_info { > > + unsigned char command; > > + unsigned char *data; > > + unsigned int size; > > + unsigned short flags; /* used for specifying PEC, 10-bit addresses */ > > + unsigned char smb_proto; /* SMBus protocol */ > > + unsigned int cmd_valid; /* true if command is valid else false */ > > +}; > > + > > +#endif /* __IPROC_I2C_H__ */ > > Hi Heiko, Thank you for detailed review. I will work on all your review points and send v2. > > -- > DENX Software Engineering GmbH, Managing Director: Wolfgang Denk > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany > Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs@denx.de
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 03d2fed341..7a80971b12 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -5,454 +5,461 @@ menu "I2C support" config DM_I2C - bool "Enable Driver Model for I2C drivers" - depends on DM - help - Enable driver model for I2C. The I2C uclass interface: probe, read, - write and speed, is implemented with the bus drivers operations, - which provide methods for bus setting and data transfer. Each chip - device (bus child) info is kept as parent platdata. The interface - is defined in include/i2c.h. + bool "Enable Driver Model for I2C drivers" + depends on DM + help + Enable driver model for I2C. The I2C uclass interface: probe, read, + write and speed, is implemented with the bus drivers operations, + which provide methods for bus setting and data transfer. Each chip + device (bus child) info is kept as parent platdata. The interface + is defined in include/i2c.h. config I2C_CROS_EC_TUNNEL - tristate "Chrome OS EC tunnel I2C bus" - depends on CROS_EC - help - This provides an I2C bus that will tunnel i2c commands through to - the other side of the Chrome OS EC to the I2C bus connected there. - This will work whatever the interface used to talk to the EC (SPI, - I2C or LPC). Some Chromebooks use this when the hardware design - does not allow direct access to the main PMIC from the AP. + tristate "Chrome OS EC tunnel I2C bus" + depends on CROS_EC + help + This provides an I2C bus that will tunnel i2c commands through to + the other side of the Chrome OS EC to the I2C bus connected there. + This will work whatever the interface used to talk to the EC (SPI, + I2C or LPC). Some Chromebooks use this when the hardware design + does not allow direct access to the main PMIC from the AP. config I2C_CROS_EC_LDO - bool "Provide access to LDOs on the Chrome OS EC" - depends on CROS_EC - ---help--- - On many Chromebooks the main PMIC is inaccessible to the AP. This is - often dealt with by using an I2C pass-through interface provided by - the EC. On some unfortunate models (e.g. Spring) the pass-through - is not available, and an LDO message is available instead. This - option enables a driver which provides very basic access to those - regulators, via the EC. We implement this as an I2C bus which - emulates just the TPS65090 messages we know about. This is done to - avoid duplicating the logic in the TPS65090 regulator driver for - enabling/disabling an LDO. + bool "Provide access to LDOs on the Chrome OS EC" + depends on CROS_EC + ---help--- + On many Chromebooks the main PMIC is inaccessible to the AP. This is + often dealt with by using an I2C pass-through interface provided by + the EC. On some unfortunate models (e.g. Spring) the pass-through + is not available, and an LDO message is available instead. This + option enables a driver which provides very basic access to those + regulators, via the EC. We implement this as an I2C bus which + emulates just the TPS65090 messages we know about. This is done to + avoid duplicating the logic in the TPS65090 regulator driver for + enabling/disabling an LDO. config I2C_SET_DEFAULT_BUS_NUM - bool "Set default I2C bus number" - depends on DM_I2C - help - Set default number of I2C bus to be accessed. This option provides - behaviour similar to old (i.e. pre DM) I2C bus driver. + bool "Set default I2C bus number" + depends on DM_I2C + help + Set default number of I2C bus to be accessed. This option provides + behaviour similar to old (i.e. pre DM) I2C bus driver. config I2C_DEFAULT_BUS_NUMBER - hex "I2C default bus number" - depends on I2C_SET_DEFAULT_BUS_NUM - default 0x0 - help - Number of default I2C bus to use + hex "I2C default bus number" + depends on I2C_SET_DEFAULT_BUS_NUM + default 0x0 + help + Number of default I2C bus to use config DM_I2C_GPIO - bool "Enable Driver Model for software emulated I2C bus driver" - depends on DM_I2C && DM_GPIO - help - Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO - configuration is given by the device tree. Kernel-style device tree - bindings are supported. - Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt + bool "Enable Driver Model for software emulated I2C bus driver" + depends on DM_I2C && DM_GPIO + help + Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO + configuration is given by the device tree. Kernel-style device tree + bindings are supported. + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt config SYS_I2C_AT91 - bool "Atmel I2C driver" - depends on DM_I2C && ARCH_AT91 - help - Add support for the Atmel I2C driver. A serious problem is that there - is no documented way to issue repeated START conditions for more than - two messages, as needed to support combined I2C messages. Use the - i2c-gpio driver unless your system can cope with this limitation. - Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt + bool "Atmel I2C driver" + depends on DM_I2C && ARCH_AT91 + help + Add support for the Atmel I2C driver. A serious problem is that there + is no documented way to issue repeated START conditions for more than + two messages, as needed to support combined I2C messages. Use the + i2c-gpio driver unless your system can cope with this limitation. + Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt + +config IPROC_I2C + bool "Broadcom iProc I2C driver" + depends on DM_I2C + help + Add support for Broadcom iProc I2C driver. + The driver is used in iProc SoCs. config SYS_I2C_FSL bool "Freescale I2C bus driver" depends on DM_I2C help - Add support for Freescale I2C busses as used on MPC8240, MPC8245, and - MPC85xx processors. + Add support for Freescale I2C busses as used on MPC8240, MPC8245, and + MPC85xx processors. config SYS_I2C_CADENCE - tristate "Cadence I2C Controller" - depends on DM_I2C && (ARCH_ZYNQ || ARM64) - help - Say yes here to select Cadence I2C Host Controller. This controller is - e.g. used by Xilinx Zynq. + tristate "Cadence I2C Controller" + depends on DM_I2C && (ARCH_ZYNQ || ARM64) + help + Say yes here to select Cadence I2C Host Controller. This controller is + e.g. used by Xilinx Zynq. config SYS_I2C_DAVINCI - bool "Davinci I2C Controller" - depends on (ARCH_KEYSTONE || ARCH_DAVINCI) - help - Say yes here to add support for Davinci and Keystone I2C controller + bool "Davinci I2C Controller" + depends on (ARCH_KEYSTONE || ARCH_DAVINCI) + help + Say yes here to add support for Davinci and Keystone I2C controller config SYS_I2C_DW - bool "Designware I2C Controller" - default n - help - Say yes here to select the Designware I2C Host Controller. This - controller is used in various SoCs, e.g. the ST SPEAr, Altera - SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. + bool "Designware I2C Controller" + default n + help + Say yes here to select the Designware I2C Host Controller. This + controller is used in various SoCs, e.g. the ST SPEAr, Altera + SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs. config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED - bool "DW I2C Enable Status Register not supported" - depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ - TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) - default y - help - Some versions of the Designware I2C controller do not support the - enable status register. This config option can be enabled in such - cases. + bool "DW I2C Enable Status Register not supported" + depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \ + TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600) + default y + help + Some versions of the Designware I2C controller do not support the + enable status register. This config option can be enabled in such + cases. config SYS_I2C_ASPEED - bool "Aspeed I2C Controller" - depends on DM_I2C && ARCH_ASPEED - help - Say yes here to select Aspeed I2C Host Controller. The driver - supports AST2500 and AST2400 controllers, but is very limited. - Only single master mode is supported and only byte-by-byte - synchronous reads and writes are supported, no Pool Buffers or DMA. + bool "Aspeed I2C Controller" + depends on DM_I2C && ARCH_ASPEED + help + Say yes here to select Aspeed I2C Host Controller. The driver + supports AST2500 and AST2400 controllers, but is very limited. + Only single master mode is supported and only byte-by-byte + synchronous reads and writes are supported, no Pool Buffers or DMA. config SYS_I2C_INTEL - bool "Intel I2C/SMBUS driver" - depends on DM_I2C - help - Add support for the Intel SMBUS driver. So far this driver is just - a stub which perhaps some basic init. There is no implementation of - the I2C API meaning that any I2C operations will immediately fail - for now. + bool "Intel I2C/SMBUS driver" + depends on DM_I2C + help + Add support for the Intel SMBUS driver. So far this driver is just + a stub which perhaps some basic init. There is no implementation of + the I2C API meaning that any I2C operations will immediately fail + for now. config SYS_I2C_IMX_LPI2C - bool "NXP i.MX LPI2C driver" - help - Add support for the NXP i.MX LPI2C driver. + bool "NXP i.MX LPI2C driver" + help + Add support for the NXP i.MX LPI2C driver. config SYS_I2C_MESON - bool "Amlogic Meson I2C driver" - depends on DM_I2C && ARCH_MESON - help - Add support for the I2C controller available in Amlogic Meson - SoCs. The controller supports programmable bus speed including - standard (100kbits/s) and fast (400kbit/s) speed and allows the - software to define a flexible format of the bit streams. It has an - internal buffer holding up to 8 bytes for transfers and supports - both 7-bit and 10-bit addresses. + bool "Amlogic Meson I2C driver" + depends on DM_I2C && ARCH_MESON + help + Add support for the I2C controller available in Amlogic Meson + SoCs. The controller supports programmable bus speed including + standard (100kbits/s) and fast (400kbit/s) speed and allows the + software to define a flexible format of the bit streams. It has an + internal buffer holding up to 8 bytes for transfers and supports + both 7-bit and 10-bit addresses. config SYS_I2C_MXC - bool "NXP MXC I2C driver" - help - Add support for the NXP I2C driver. This supports up to four bus - channels and operating on standard mode up to 100 kbits/s and fast - mode up to 400 kbits/s. + bool "NXP MXC I2C driver" + help + Add support for the NXP I2C driver. This supports up to four bus + channels and operating on standard mode up to 100 kbits/s and fast + mode up to 400 kbits/s. # These settings are not used with DM_I2C, however SPL doesn't use # DM_I2C even if DM_I2C is enabled, and so might use these settings even # when main u-boot does not! if SYS_I2C_MXC && (!DM_I2C || SPL) config SYS_I2C_MXC_I2C1 - bool "NXP MXC I2C1" - help - Add support for NXP MXC I2C Controller 1. - Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A + bool "NXP MXC I2C1" + help + Add support for NXP MXC I2C Controller 1. + Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C2 - bool "NXP MXC I2C2" - help - Add support for NXP MXC I2C Controller 2. - Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A + bool "NXP MXC I2C2" + help + Add support for NXP MXC I2C Controller 2. + Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C3 - bool "NXP MXC I2C3" - help - Add support for NXP MXC I2C Controller 3. - Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A + bool "NXP MXC I2C3" + help + Add support for NXP MXC I2C Controller 3. + Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C4 - bool "NXP MXC I2C4" - help - Add support for NXP MXC I2C Controller 4. - Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A + bool "NXP MXC I2C4" + help + Add support for NXP MXC I2C Controller 4. + Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C5 - bool "NXP MXC I2C5" - help - Add support for NXP MXC I2C Controller 5. - Required for SoCs which have I2C MXC controller 5 eg LX2160A + bool "NXP MXC I2C5" + help + Add support for NXP MXC I2C Controller 5. + Required for SoCs which have I2C MXC controller 5 eg LX2160A config SYS_I2C_MXC_I2C6 - bool "NXP MXC I2C6" - help - Add support for NXP MXC I2C Controller 6. - Required for SoCs which have I2C MXC controller 6 eg LX2160A + bool "NXP MXC I2C6" + help + Add support for NXP MXC I2C Controller 6. + Required for SoCs which have I2C MXC controller 6 eg LX2160A config SYS_I2C_MXC_I2C7 - bool "NXP MXC I2C7" - help - Add support for NXP MXC I2C Controller 7. - Required for SoCs which have I2C MXC controller 7 eg LX2160A + bool "NXP MXC I2C7" + help + Add support for NXP MXC I2C Controller 7. + Required for SoCs which have I2C MXC controller 7 eg LX2160A config SYS_I2C_MXC_I2C8 - bool "NXP MXC I2C8" - help - Add support for NXP MXC I2C Controller 8. - Required for SoCs which have I2C MXC controller 8 eg LX2160A + bool "NXP MXC I2C8" + help + Add support for NXP MXC I2C Controller 8. + Required for SoCs which have I2C MXC controller 8 eg LX2160A endif if SYS_I2C_MXC_I2C1 config SYS_MXC_I2C1_SPEED - int "I2C Channel 1 speed" - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU - default 100000 - help - MXC I2C Channel 1 speed + int "I2C Channel 1 speed" + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU + default 100000 + help + MXC I2C Channel 1 speed config SYS_MXC_I2C1_SLAVE - int "I2C1 Slave" - default 0 - help - MXC I2C1 Slave + int "I2C1 Slave" + default 0 + help + MXC I2C1 Slave endif if SYS_I2C_MXC_I2C2 config SYS_MXC_I2C2_SPEED - int "I2C Channel 2 speed" - default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU - default 100000 - help - MXC I2C Channel 2 speed + int "I2C Channel 2 speed" + default 40000000 if TARGET_LS2080A_SIMU || TARGET_LS2080A_EMU + default 100000 + help + MXC I2C Channel 2 speed config SYS_MXC_I2C2_SLAVE - int "I2C2 Slave" - default 0 - help - MXC I2C2 Slave + int "I2C2 Slave" + default 0 + help + MXC I2C2 Slave endif if SYS_I2C_MXC_I2C3 config SYS_MXC_I2C3_SPEED - int "I2C Channel 3 speed" - default 100000 - help - MXC I2C Channel 3 speed + int "I2C Channel 3 speed" + default 100000 + help + MXC I2C Channel 3 speed config SYS_MXC_I2C3_SLAVE - int "I2C3 Slave" - default 0 - help - MXC I2C3 Slave + int "I2C3 Slave" + default 0 + help + MXC I2C3 Slave endif if SYS_I2C_MXC_I2C4 config SYS_MXC_I2C4_SPEED - int "I2C Channel 4 speed" - default 100000 - help - MXC I2C Channel 4 speed + int "I2C Channel 4 speed" + default 100000 + help + MXC I2C Channel 4 speed config SYS_MXC_I2C4_SLAVE - int "I2C4 Slave" - default 0 - help - MXC I2C4 Slave + int "I2C4 Slave" + default 0 + help + MXC I2C4 Slave endif if SYS_I2C_MXC_I2C5 config SYS_MXC_I2C5_SPEED - int "I2C Channel 5 speed" - default 100000 - help - MXC I2C Channel 5 speed + int "I2C Channel 5 speed" + default 100000 + help + MXC I2C Channel 5 speed config SYS_MXC_I2C5_SLAVE - int "I2C5 Slave" - default 0 - help - MXC I2C5 Slave + int "I2C5 Slave" + default 0 + help + MXC I2C5 Slave endif if SYS_I2C_MXC_I2C6 config SYS_MXC_I2C6_SPEED - int "I2C Channel 6 speed" - default 100000 - help - MXC I2C Channel 6 speed + int "I2C Channel 6 speed" + default 100000 + help + MXC I2C Channel 6 speed config SYS_MXC_I2C6_SLAVE - int "I2C6 Slave" - default 0 - help - MXC I2C6 Slave + int "I2C6 Slave" + default 0 + help + MXC I2C6 Slave endif if SYS_I2C_MXC_I2C7 config SYS_MXC_I2C7_SPEED - int "I2C Channel 7 speed" - default 100000 - help - MXC I2C Channel 7 speed + int "I2C Channel 7 speed" + default 100000 + help + MXC I2C Channel 7 speed config SYS_MXC_I2C7_SLAVE - int "I2C7 Slave" - default 0 - help - MXC I2C7 Slave + int "I2C7 Slave" + default 0 + help + MXC I2C7 Slave endif if SYS_I2C_MXC_I2C8 config SYS_MXC_I2C8_SPEED - int "I2C Channel 8 speed" - default 100000 - help - MXC I2C Channel 8 speed + int "I2C Channel 8 speed" + default 100000 + help + MXC I2C Channel 8 speed config SYS_MXC_I2C8_SLAVE - int "I2C8 Slave" - default 0 - help - MXC I2C8 Slave + int "I2C8 Slave" + default 0 + help + MXC I2C8 Slave endif config SYS_I2C_OMAP24XX - bool "TI OMAP2+ I2C driver" - depends on ARCH_OMAP2PLUS || ARCH_K3 - help - Add support for the OMAP2+ I2C driver. + bool "TI OMAP2+ I2C driver" + depends on ARCH_OMAP2PLUS || ARCH_K3 + help + Add support for the OMAP2+ I2C driver. if SYS_I2C_OMAP24XX config SYS_OMAP24_I2C_SLAVE - int "I2C Slave addr channel 0" - default 1 - help - OMAP24xx I2C Slave address channel 0 + int "I2C Slave addr channel 0" + default 1 + help + OMAP24xx I2C Slave address channel 0 config SYS_OMAP24_I2C_SPEED - int "I2C Slave channel 0 speed" - default 100000 - help - OMAP24xx Slave speed channel 0 + int "I2C Slave channel 0 speed" + default 100000 + help + OMAP24xx Slave speed channel 0 endif config SYS_I2C_RCAR_I2C - bool "Renesas RCar I2C driver" - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C - help - Support for Renesas RCar I2C controller. + bool "Renesas RCar I2C driver" + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C + help + Support for Renesas RCar I2C controller. config SYS_I2C_RCAR_IIC - bool "Renesas RCar Gen3 IIC driver" - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C - help - Support for Renesas RCar Gen3 IIC controller. + bool "Renesas RCar Gen3 IIC driver" + depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C + help + Support for Renesas RCar Gen3 IIC controller. config SYS_I2C_ROCKCHIP - bool "Rockchip I2C driver" - depends on DM_I2C - help - Add support for the Rockchip I2C driver. This is used with various - Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips - have several I2C ports and all are provided, controlled by the - device tree. + bool "Rockchip I2C driver" + depends on DM_I2C + help + Add support for the Rockchip I2C driver. This is used with various + Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips + have several I2C ports and all are provided, controlled by the + device tree. config SYS_I2C_SANDBOX - bool "Sandbox I2C driver" - depends on SANDBOX && DM_I2C - help - Enable I2C support for sandbox. This is an emulation of a real I2C - bus. Devices can be attached to the bus using the device tree - which specifies the driver to use. See sandbox.dts as an example. + bool "Sandbox I2C driver" + depends on SANDBOX && DM_I2C + help + Enable I2C support for sandbox. This is an emulation of a real I2C + bus. Devices can be attached to the bus using the device tree + which specifies the driver to use. See sandbox.dts as an example. config SYS_I2C_S3C24X0 - bool "Samsung I2C driver" - depends on ARCH_EXYNOS4 && DM_I2C - help - Support for Samsung I2C controller as Samsung SoCs. + bool "Samsung I2C driver" + depends on ARCH_EXYNOS4 && DM_I2C + help + Support for Samsung I2C controller as Samsung SoCs. config SYS_I2C_STM32F7 - bool "STMicroelectronics STM32F7 I2C support" - depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C - help - Enable this option to add support for STM32 I2C controller - introduced with STM32F7/H7 SoCs. This I2C controller supports : - _ Slave and master modes - _ Multimaster capability - _ Standard-mode (up to 100 kHz) - _ Fast-mode (up to 400 kHz) - _ Fast-mode Plus (up to 1 MHz) - _ 7-bit and 10-bit addressing mode - _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) - _ All 7-bit addresses acknowledge mode - _ General call - _ Programmable setup and hold times - _ Easy to use event management - _ Optional clock stretching - _ Software reset + bool "STMicroelectronics STM32F7 I2C support" + depends on (STM32F7 || STM32H7 || ARCH_STM32MP) && DM_I2C + help + Enable this option to add support for STM32 I2C controller + introduced with STM32F7/H7 SoCs. This I2C controller supports : + _ Slave and master modes + _ Multimaster capability + _ Standard-mode (up to 100 kHz) + _ Fast-mode (up to 400 kHz) + _ Fast-mode Plus (up to 1 MHz) + _ 7-bit and 10-bit addressing mode + _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) + _ All 7-bit addresses acknowledge mode + _ General call + _ Programmable setup and hold times + _ Easy to use event management + _ Optional clock stretching + _ Software reset config SYS_I2C_TEGRA - bool "NVIDIA Tegra internal I2C controller" - depends on TEGRA - help - Support for NVIDIA I2C controller available in Tegra SoCs. + bool "NVIDIA Tegra internal I2C controller" + depends on TEGRA + help + Support for NVIDIA I2C controller available in Tegra SoCs. config SYS_I2C_UNIPHIER - bool "UniPhier I2C driver" - depends on ARCH_UNIPHIER && DM_I2C - default y - help - Support for UniPhier I2C controller driver. This I2C controller - is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. + bool "UniPhier I2C driver" + depends on ARCH_UNIPHIER && DM_I2C + default y + help + Support for UniPhier I2C controller driver. This I2C controller + is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs. config SYS_I2C_UNIPHIER_F - bool "UniPhier FIFO-builtin I2C driver" - depends on ARCH_UNIPHIER && DM_I2C - default y - help - Support for UniPhier FIFO-builtin I2C controller driver. - This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. + bool "UniPhier FIFO-builtin I2C driver" + depends on ARCH_UNIPHIER && DM_I2C + default y + help + Support for UniPhier FIFO-builtin I2C controller driver. + This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. config SYS_I2C_VERSATILE - bool "Arm Ltd Versatile I2C bus driver" - depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) - help - Add support for the Arm Ltd Versatile Express I2C driver. The I2C host - controller is present in the development boards manufactured by Arm Ltd. + bool "Arm Ltd Versatile I2C bus driver" + depends on DM_I2C && (TARGET_VEXPRESS_CA15_TC2 || TARGET_VEXPRESS64_JUNO) + help + Add support for the Arm Ltd Versatile Express I2C driver. The I2C host + controller is present in the development boards manufactured by Arm Ltd. config SYS_I2C_MVTWSI - bool "Marvell I2C driver" - depends on DM_I2C - help - Support for Marvell I2C controllers as used on the orion5x and - kirkwood SoC families. + bool "Marvell I2C driver" + depends on DM_I2C + help + Support for Marvell I2C controllers as used on the orion5x and + kirkwood SoC families. config TEGRA186_BPMP_I2C - bool "Enable Tegra186 BPMP-based I2C driver" - depends on TEGRA186_BPMP - help - Support for Tegra I2C controllers managed by the BPMP (Boot and - Power Management Processor). On Tegra186, some I2C controllers are - directly controlled by the main CPU, whereas others are controlled - by the BPMP, and can only be accessed by the main CPU via IPC - requests to the BPMP. This driver covers the latter case. + bool "Enable Tegra186 BPMP-based I2C driver" + depends on TEGRA186_BPMP + help + Support for Tegra I2C controllers managed by the BPMP (Boot and + Power Management Processor). On Tegra186, some I2C controllers are + directly controlled by the main CPU, whereas others are controlled + by the BPMP, and can only be accessed by the main CPU via IPC + requests to the BPMP. This driver covers the latter case. config SYS_I2C_BUS_MAX - int "Max I2C busses" - depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA - default 2 if TI816X - default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE - default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X - default 5 if OMAP54XX - help - Define the maximum number of available I2C buses. + int "Max I2C busses" + depends on ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_SOCFPGA + default 2 if TI816X + default 3 if OMAP34XX || AM33XX || AM43XX || ARCH_KEYSTONE + default 4 if ARCH_SOCFPGA || OMAP44XX || TI814X + default 5 if OMAP54XX + help + Define the maximum number of available I2C buses. config SYS_I2C_XILINX_XIIC - bool "Xilinx AXI I2C driver" - depends on DM_I2C - help - Support for Xilinx AXI I2C controller. + bool "Xilinx AXI I2C driver" + depends on DM_I2C + help + Support for Xilinx AXI I2C controller. config SYS_I2C_IHS bool "gdsys IHS I2C driver" diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index c2f75d8755..7cfe68e088 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -38,5 +38,5 @@ obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o - +obj-$(CONFIG_IPROC_I2C) += iproc_i2c.o obj-$(CONFIG_I2C_MUX) += muxes/ diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c new file mode 100644 index 0000000000..692035666c --- /dev/null +++ b/drivers/i2c/iproc_i2c.c @@ -0,0 +1,765 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C)) 2018 Broadcom + */ + +#include <common.h> +#include <config.h> +#include <dm.h> +#include <i2c.h> +#include <asm/io.h> +#include "errno.h" +#include "iproc_i2c.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int i2c_init_done; + +struct iproc_i2c_regs { + u32 cfg_reg; + u32 timg_cfg; + u32 addr_reg; + u32 mstr_fifo_ctrl; + u32 slv_fifo_ctrl; + u32 bitbng_ctrl; + u32 blnks[6]; /* Not to be used */ + u32 mstr_cmd; + u32 slv_cmd; + u32 evt_en; + u32 evt_sts; + u32 mstr_datawr; + u32 mstr_datard; + u32 slv_datawr; + u32 slv_datard; +}; + +struct iproc_i2c { + struct iproc_i2c_regs __iomem *base; /* register base */ + int bus_speed; +}; + +/* Function to read a value from specified register. */ +static unsigned int iproc_i2c_reg_read(u32 *reg_addr) +{ + unsigned int val; + + val = readl((void *)(reg_addr)); + return cpu_to_le32(val); +} + +/* Function to write a value ('val') in to a specified register. */ +static int iproc_i2c_reg_write(u32 *reg_addr, unsigned int val) +{ + val = cpu_to_le32(val); + writel(val, (void *)(reg_addr)); + return 0; +} + +#ifdef IPROC_I2C_DBG +static int iproc_dump_i2c_regs(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + + debug("\n----------------------------------------------\n"); + debug("%s: Dumping SMBus registers...\n", __func__); + + regval = iproc_i2c_reg_read(&base->cfg_reg); + debug("CCB_SMB_CFG_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->timg_cfg); + debug("CCB_SMB_TIMGCFG_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->addr_reg); + debug("CCB_SMB_ADDR_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_fifo_ctrl); + debug("CCB_SMB_MSTRFIFOCTL_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_fifo_ctrl); + debug("CCB_SMB_SLVFIFOCTL_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->bitbng_ctrl); + debug("CCB_SMB_BITBANGCTL_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_cmd); + debug("CCB_SMB_MSTRCMD_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_cmd); + debug("CCB_SMB_SLVCMD_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->evt_en); + debug("CCB_SMB_EVTEN_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->evt_sts); + debug("CCB_SMB_EVTSTS_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_datawr); + debug("CCB_SMB_MSTRDATAWR_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->mstr_datard); + debug("CCB_SMB_MSTRDATARD_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_datawr); + debug("CCB_SMB_SLVDATAWR_REG=0x%08X\n", regval); + + regval = iproc_i2c_reg_read(&base->slv_datard); + debug("CCB_SMB_SLVDATARD_REG=0x%08X\n", regval); + + debug("----------------------------------------------\n\n"); + return 0; +} +#endif + +/* + * Function to ensure that the previous transaction was completed before + * initiating a new transaction. It can also be used in polling mode to + * check status of completion of a command + */ +static int iproc_i2c_startbusy_wait(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + + regval = iproc_i2c_reg_read(&base->mstr_cmd); + + /* Check if an operation is in progress. During probe it won't be. + * But when shutdown/remove was called we want to make sure that + * the transaction in progress completed + */ + if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { + unsigned int i = 0; + + do { + mdelay(10); /* Wait for 10 msec */ + i++; + regval = iproc_i2c_reg_read(&base->mstr_cmd); + + /* If start-busy bit cleared, exit the loop */ + } while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) && + (i < IPROC_SMB_MAX_RETRIES)); + + if (i >= IPROC_SMB_MAX_RETRIES) { + pr_err("%s: START_BUSY bit didn't clear, exiting\n", + __func__); + + return -ETIMEDOUT; + } + } + return 0; +} + +/* + * This function set clock frequency for SMBus block. As per hardware + * engineering, the clock frequency can be changed dynamically. + */ +static int iproc_i2c_set_clk_freq(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + + regval = iproc_i2c_reg_read(&base->timg_cfg); + + switch (bus_prvdata->bus_speed) { + case I2C_SPEED_100KHZ: + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_100, + CCB_SMB_TIMGCFG_MODE400_MASK, + CCB_SMB_TIMGCFG_MODE400_SHIFT); + break; + + case I2C_SPEED_400KHZ: + SETREGFLDVAL(regval, SMBUS_BLOCK_MODE_400, + CCB_SMB_TIMGCFG_MODE400_MASK, + CCB_SMB_TIMGCFG_MODE400_SHIFT); + break; + + default: + return -EINVAL; + } + + iproc_i2c_reg_write(&base->timg_cfg, regval); + return 0; +} + +static int iproc_i2c_init(struct iproc_i2c *bus_prvdata) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + +#ifdef IPROC_I2C_DBG + debug("\n%s: Entering", __func__); +#endif /* IPROC_I2C_DBG */ + + /* Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0. + * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts + */ + regval = CCB_SMB_MSTRRXFIFOFLSH_MASK | CCB_SMB_MSTRTXFIFOFLSH_MASK; + iproc_i2c_reg_write(&base->mstr_fifo_ctrl, regval); + + /* Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero + * since there will be only one master + */ + + regval = iproc_i2c_reg_read(&base->cfg_reg); + regval |= CCB_SMB_CFG_SMBEN_MASK; + iproc_i2c_reg_write(&base->cfg_reg, regval); +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + regval = iproc_i2c_reg_read(&base->cfg_reg); + regval |= CCB_SMB_CFG_RST_MASK; + iproc_i2c_reg_write(&base->cfg_reg, regval); + regval &= ~CCB_SMB_CFG_RST_MASK; + iproc_i2c_reg_write(&base->cfg_reg, regval); +#endif + /* Wait a minimum of 50 Usec, as per SMB hw doc */ + udelay(50); + + /* Set default clock frequency */ + iproc_i2c_set_clk_freq(bus_prvdata); + + /* Disable intrs */ + iproc_i2c_reg_write(&base->evt_en, 0); + + /* Clear intrs (W1TC) */ + regval = iproc_i2c_reg_read(&base->evt_sts); + iproc_i2c_reg_write(&base->evt_sts, regval); + + i2c_init_done = 1; + +#ifdef IPROC_I2C_DBG + iproc_dump_i2c_regs(bus_prvdata); + + debug("%s: Init successful\n", __func__); +#endif /* IPROC_I2C_DBG */ + + return 0; +} + +/* + * This function copies data to SMBus's Tx FIFO. Valid for write transactions + * only + * + * base_addr: Mapped address of this SMBus instance + * dev_addr: SMBus (I2C) device address. We are assuming 7-bit addresses + * initially + * info: Data to copy in to Tx FIFO. For read commands, the size should be + * set to zero by the caller + * + */ +static void iproc_i2c_write_trans_data(struct iproc_i2c *bus_prvdata, + unsigned short dev_addr, + struct iproc_xact_info *info) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + unsigned int i; + unsigned int num_data_bytes = 0; + +#ifdef IPROC_I2C_DBG + debug("%s: dev_addr=0x%X cmd_valid=%d cmd=0x%02x size=%u proto=%d\n" + "buf[] %x\n", + __func__, + dev_addr, + info->cmd_valid, + info->command, + info->size, + info->smb_proto, + info->data[0]); +#endif /* IPROC_I2C_DBG */ + + /* Write SMBus device address first */ + /* Note, we are assuming 7-bit addresses for now. For 10-bit addresses, + * we may have one more write to send the upper 3 bits of 10-bit addr + */ + iproc_i2c_reg_write(&base->mstr_datawr, dev_addr); + + /* If the protocol needs command code, copy it */ + if (info->cmd_valid) + iproc_i2c_reg_write(&base->mstr_datawr, info->command); + + /* Depending on the SMBus protocol, we need to write additional + * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus + * spec for sequence for a transaction + */ + switch (info->smb_proto) { + case SMBUS_PROT_RECV_BYTE: + /* No additional data to be written */ + num_data_bytes = 0; + break; + + case SMBUS_PROT_SEND_BYTE: + num_data_bytes = info->size; + break; + + case SMBUS_PROT_RD_BYTE: + case SMBUS_PROT_RD_WORD: + case SMBUS_PROT_BLK_RD: + /* Write slave address with R/W~ set (bit #0) */ + iproc_i2c_reg_write(&base->mstr_datawr, + dev_addr | 0x1); + num_data_bytes = 0; + break; +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL: + iproc_i2c_reg_write(&base->mstr_datawr, + dev_addr | 0x1 | + CCB_SMB_MSTRWRSTS_MASK); + num_data_bytes = 0; + break; +#endif + case SMBUS_PROT_WR_BYTE: + case SMBUS_PROT_WR_WORD: + /* No additional bytes to be written. + * Data portion is written in the + * 'for' loop below + */ + num_data_bytes = info->size; + break; + + case SMBUS_PROT_BLK_WR: + /* 3rd byte is byte count */ + iproc_i2c_reg_write(&base->mstr_datawr, info->size); + num_data_bytes = info->size; + break; + + default: + break; + } + + /* Copy actual data from caller, next. In general, for reads, no data is + * copied + */ + for (i = 0; num_data_bytes; --num_data_bytes, i++) { + /* For the last byte, set MASTER_WR_STATUS bit */ + regval = (num_data_bytes == 1) ? + info->data[i] | CCB_SMB_MSTRWRSTS_MASK : + info->data[i]; + + iproc_i2c_reg_write(&base->mstr_datawr, regval); + } +} + +static int iproc_i2c_data_send(struct iproc_i2c *bus_prvdata, + unsigned short addr, + struct iproc_xact_info *info) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + int rc, retry = 3; unsigned int regval; + + /* Make sure the previous transaction completed */ + rc = iproc_i2c_startbusy_wait(bus_prvdata); + + if (rc < 0) { + pr_err("%s: Send: bus is busy, exiting\n", __func__); + return rc; + } + + /* Write transaction bytes to Tx FIFO */ + iproc_i2c_write_trans_data(bus_prvdata, addr, info); + + /* Program master command register (0x30) with protocol type and set + * start_busy_command bit to initiate the write transaction + */ + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | + CCB_SMB_MSTRSTARTBUSYCMD_MASK; + + iproc_i2c_reg_write(&base->mstr_cmd, regval); + + /* Check for Master status */ + regval = iproc_i2c_reg_read(&base->mstr_cmd); + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { + mdelay(10); + if (retry-- <= 0) + break; + regval = iproc_i2c_reg_read(&base->mstr_cmd); + } + + /* If start_busy bit cleared, check if there are any errors */ + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { + /* start_busy bit cleared, check master_status field now */ + regval &= CCB_SMB_MSTRSTS_MASK; + regval >>= CCB_SMB_MSTRSTS_SHIFT; + + if (regval != MSTR_STS_XACT_SUCCESS) { + /* Error We can flush Tx FIFO here */ + pr_err("%s: ERROR: Error in transaction %u, exiting\n", + __func__, regval); + return -EREMOTEIO; + } + } + + return 0; +} + +static int iproc_i2c_data_recv(struct iproc_i2c *bus_prvdata, + unsigned short addr, + struct iproc_xact_info *info, + unsigned int *num_bytes_read) +{ + struct iproc_i2c_regs *base = bus_prvdata->base; + int rc, retry = 3; + unsigned int regval; + + /* Make sure the previous transaction completed */ + rc = iproc_i2c_startbusy_wait(bus_prvdata); + + if (rc < 0) { + pr_err("%s: Receive: Bus is busy, exiting\n", __func__); + return rc; + } + + /* Program all transaction bytes into master Tx FIFO */ + iproc_i2c_write_trans_data(bus_prvdata, addr, info); + + /* Program master command register (0x30) with protocol type and set + * start_busy_command bit to initiate the write transaction + */ + regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | + CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size; + + iproc_i2c_reg_write(&base->mstr_cmd, regval); + + /* Check for Master status */ + regval = iproc_i2c_reg_read(&base->mstr_cmd); + while (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) { + udelay(1000); + if (retry-- <= 0) + break; + regval = iproc_i2c_reg_read(&base->mstr_cmd); + } + + /* If start_busy bit cleared, check if there are any errors */ + if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { + /* start_busy bit cleared, check master_status field now */ + regval &= CCB_SMB_MSTRSTS_MASK; + regval >>= CCB_SMB_MSTRSTS_SHIFT; + + if (regval != MSTR_STS_XACT_SUCCESS) { + /* We can flush Tx FIFO here */ + pr_err("%s: Error in transaction %d, exiting\n", + __func__, regval); + return -EREMOTEIO; + } + } + + /* Read received byte(s), after TX out address etc */ + regval = iproc_i2c_reg_read(&base->mstr_datard); + + /* For block read, protocol (hw) returns byte count, + * as the first byte + */ + if (info->smb_proto == SMBUS_PROT_BLK_RD) { + int i; + + *num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK; + + /* Limit to reading a max of 32 bytes only; just a safeguard. + * If # bytes read is a number > 32, check transaction set up, + * and contact hw engg. Assumption: PEC is disabled + */ + for (i = 0; + (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX); + i++) { + /* Read Rx FIFO for data bytes */ + regval = iproc_i2c_reg_read(&base->mstr_datard); + info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK; + } + } else { + /* 1 Byte data */ + *info->data = regval & CCB_SMB_MSTRRDDATA_MASK; + *num_bytes_read = 1; + } + + return 0; +} + +static int i2c_write_byte(struct iproc_i2c *bus_prvdata, + u8 devaddr, + u8 regoffset, + u8 value) +{ + int rc; + struct iproc_xact_info info; + + devaddr <<= 1; + + info.cmd_valid = 1; + info.command = (unsigned char)regoffset; + info.data = &value; + info.size = 1; + info.flags = 0; +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + info.smb_proto = SMBUS_PROT_WR_WORD;/*SMBUS_PROT_WR_BYTE;*/ +#else + info.smb_proto = SMBUS_PROT_WR_BYTE; +#endif + /* Refer to i2c_smbus_write_byte params passed. */ + rc = iproc_i2c_data_send(bus_prvdata, devaddr, &info); + + if (rc < 0) { + pr_err("%s: %s error accessing device 0x%X\n", + __func__, "Write", devaddr); + return -EREMOTEIO; + } + + return 0; +} + +int i2c_write(struct iproc_i2c *bus_prvdata, + uchar chip, + uint regaddr, + int alen, + uchar *buffer, + int len) +{ + int i, data_len; + u8 *data; + + if (alen > 1) { + pr_err("I2C write: addr len %d not supported\n", alen); + return 1; + } + + if (regaddr + len > 256) { + pr_err("I2C write: address out of range\n"); + return 1; + } + + if (len < 1) { + pr_err("I2C write: Need offset addr and value\n"); + return 1; + } + + /* buffer contains offset addr followed by value to be written */ + regaddr = buffer[0]; + data = &buffer[1]; + data_len = len - 1; + + for (i = 0; i < data_len; i++) { + if (i2c_write_byte(bus_prvdata, chip, regaddr + i, data[i])) { + pr_err("I2C write (%d): I/O error\n", i); + iproc_i2c_init(bus_prvdata); + return 1; + } + } + + return 0; +} + +static int i2c_read_byte(struct iproc_i2c *bus_prvdata, + u8 devaddr, + u8 regoffset, + u8 *value) +{ + int rc; + struct iproc_xact_info info; + unsigned int num_bytes_read = 0; + + devaddr <<= 1; + + info.cmd_valid = 1; + info.command = (unsigned char)regoffset; + info.data = value; + info.size = 1; + info.flags = 0; +#if defined(CONFIG_CYGNUS) || defined(CONFIG_TARGET_BCMOMEGA) + info.smb_proto = SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL; +#else + info.smb_proto = SMBUS_PROT_RD_BYTE; +#endif + /* Refer to i2c_smbus_read_byte for params passed. */ + rc = iproc_i2c_data_recv(bus_prvdata, devaddr, &info, &num_bytes_read); + + if (rc < 0) { + pr_err("%s: %s error accessing device 0x%X\n", + __func__, "Read", devaddr); + return -EREMOTEIO; + } + + return 0; +} + +int i2c_read(struct iproc_i2c *bus_prvdata, + uchar chip, + uint addr, + int alen, + uchar *buffer, + int len) +{ + int i; + + if (alen > 1) { + pr_err("I2C read: addr len %d not supported\n", alen); + return 1; + } + + if (addr + len > 256) { + pr_err("I2C read: address out of range\n"); + return 1; + } + + for (i = 0; i < len; i++) { + if (i2c_read_byte(bus_prvdata, chip, addr + i, &buffer[i])) { + pr_err("I2C read: I/O error\n"); + iproc_i2c_init(bus_prvdata); + return 1; + } + } + + return 0; +} + +static int iproc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + int ret = 0; + +#ifdef IPROC_I2C_DBG + debug("%s: %d messages\n", __func__, nmsgs); +#endif + + for (; nmsgs > 0; nmsgs--, msg++) { + if (msg->flags & I2C_M_RD) + ret = i2c_read(bus_prvdata, + msg->addr, + 0, + 0, + msg->buf, + msg->len); + else + ret = i2c_write(bus_prvdata, + msg->addr, + 0, + 0, + msg->buf, + msg->len); + } + + return ret; +} + +static int iproc_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + struct iproc_i2c_regs *base = bus_prvdata->base; + u32 regval; + +#ifdef IPROC_I2C_DBG + debug("\n%s: Entering chip probe\n", __func__); +#endif /* IPROC_I2C_DBG */ + + /* Init internal regs, disable intrs (and then clear intrs), set fifo + * thresholds, etc. + */ + if (!i2c_init_done) + iproc_i2c_init(bus_prvdata); + + regval = (chip_addr << 1); + iproc_i2c_reg_write(&base->mstr_datawr, regval); + regval = ((SMBUS_PROT_QUICK_CMD << CCB_SMB_MSTRSMBUSPROTO_SHIFT) | + (1 << CCB_SMB_MSTRSTARTBUSYCMD_SHIFT)); + iproc_i2c_reg_write(&base->mstr_cmd, regval); + + do { + udelay(100); + regval = iproc_i2c_reg_read(&base->mstr_cmd); + regval &= CCB_SMB_MSTRSTARTBUSYCMD_MASK; + } while (regval); + + regval = iproc_i2c_reg_read(&base->mstr_cmd); + + if ((regval & CCB_SMB_MSTRSTS_MASK) != 0) + return -1; + +#ifdef IPROC_I2C_DBG + iproc_dump_i2c_regs(bus_prvdata); + + debug("%s: chip probe successful\n", __func__); +#endif /* IPROC_I2C_DBG */ + + return 0; +} + +static int iproc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + + bus_prvdata->bus_speed = speed; + if (iproc_i2c_set_clk_freq(bus_prvdata)) + return -EINVAL; + + return 0; +} + +/** + * i2c_get_bus_speed - get i2c bus speed + * + * This function returns the speed of operation in Hz + */ +int iproc_i2c_get_bus_speed(struct udevice *bus) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + struct iproc_i2c_regs *base = bus_prvdata->base; + unsigned int regval; + unsigned int val; + + regval = iproc_i2c_reg_read(&base->timg_cfg); + val = GETREGFLDVAL(regval, CCB_SMB_TIMGCFG_MODE400_MASK, + CCB_SMB_TIMGCFG_MODE400_SHIFT); + switch (val) { + case 0: + return I2C_SPEED_100KHZ; + case 1: + return I2C_SPEED_400KHZ; + default: + return -EINVAL; + } + return -EINVAL; +} + +static int iproc_i2c_probe(struct udevice *bus) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + + return iproc_i2c_init(bus_prvdata); +} + +static int iproc_i2c_ofdata_to_platdata(struct udevice *bus) +{ + struct iproc_i2c *bus_prvdata = dev_get_priv(bus); + int node = dev_of_offset(bus); + const void *blob = gd->fdt_blob; + + bus_prvdata->base = map_physmem(devfdt_get_addr(bus), + sizeof(void *), + MAP_NOCACHE); + + /* default 100KHz freq */ + bus_prvdata->bus_speed = fdtdec_get_int(blob, node, "bus-frequency", + I2C_SPEED_100KHZ); + + return 0; +} + +static const struct dm_i2c_ops iproc_i2c_ops = { + .xfer = iproc_i2c_xfer, + .probe_chip = iproc_i2c_probe_chip, + .set_bus_speed = iproc_i2c_set_bus_speed, + .get_bus_speed = iproc_i2c_get_bus_speed, +}; + +static const struct udevice_id iproc_i2c_ids[] = { + { .compatible = "brcm,iproc-i2c" }, + { } +}; + +U_BOOT_DRIVER(iproc_i2c) = { + .name = "iproc_i2c", + .id = UCLASS_I2C, + .of_match = iproc_i2c_ids, + .ofdata_to_platdata = iproc_i2c_ofdata_to_platdata, + .probe = iproc_i2c_probe, + .priv_auto_alloc_size = sizeof(struct iproc_i2c), + .ops = &iproc_i2c_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/i2c/iproc_i2c.h b/drivers/i2c/iproc_i2c.h new file mode 100644 index 0000000000..4f8d6ba2b2 --- /dev/null +++ b/drivers/i2c/iproc_i2c.h @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (C) 2018 Broadcom */ + +#ifndef __IPROC_I2C_H__ +#define __IPROC_I2C_H__ + +#if (defined(CONFIG_NS_PLUS) || defined(CONFIG_HELIX4)) +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 +#define IPROC_SMBUS_BASE_ADDR1 0x18038000 +#define IPROC_SMBUS_BASE_ADDR2 0x1803B000 +#elif (defined(CONFIG_CYGNUS)) +#define SHADOW_CPY_BUFFER_ADDR1 0x70000000 +#define SHADOW_CPY_BUFFER_ADDR2 0x70100000 +#define IPROC_SMBUS_BASE_ADDR1 0x18008000 +#define IPROC_SMBUS_BASE_ADDR2 0x1800B000 +#endif + +/* Registers */ +#define CCB_SMB_CFG_REG 0x0 + +#define CCB_SMB_CFG_RST_MASK 0x80000000 +#define CCB_SMB_CFG_RST_SHIFT 31 + +#define CCB_SMB_CFG_SMBEN_MASK 0x40000000 +#define CCB_SMB_CFG_SMBEN_SHIFT 30 + +#define CCB_SMB_CFG_BITBANGEN_MASK 0x20000000 +#define CCB_SMB_CFG_BITBANGEN_SHIFT 29 + +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000 +#define CCB_SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28 + +#define CCB_SMB_CFG_PROMISCMODE_MASK 0x08000000 +#define CCB_SMB_CFG_PROMISCMODE_SHIFT 27 + +#define CCB_SMB_CFG_TSTMPCNTEN_MASK 0x04000000 +#define CCB_SMB_CFG_TSTMPCNTEN_SHIFT 26 + +#define CCB_SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000 +#define CCB_SMB_CFG_MSTRRTRYCNT_SHIFT 16 + +#define CCB_SMB_TIMGCFG_REG 0x4 + +#define CCB_SMB_TIMGCFG_MODE400_MASK 0x80000000 +#define CCB_SMB_TIMGCFG_MODE400_SHIFT 31 + +#define CCB_SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000 +#define CCB_SMB_TIMGCFG_RNDSLVSTR_SHIFT 24 + +#define CCB_SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000 +#define CCB_SMB_TIMGCFG_PERSLVSTR_SHIFT 16 + +#define CCB_SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00 +#define CCB_SMB_TIMGCFG_IDLTIME_SHIFT 8 + +#define CCB_SMB_ADDR_REG 0x8 + +#define CCB_SMB_EN_NIC_SMBADDR3_MASK 0x80000000 +#define CCB_SMB_EN_NIC_SMBADDR3_SHIFT 31 + +#define CCB_SMB_NIC_SMBADDR3_MASK 0x7F000000 +#define CCB_SMB_NIC_SMBADDR3_SHIFT 24 + +#define CCB_SMB_EN_NIC_SMBADDR2_MASK 0x00800000 +#define CCB_SMB_EN_NIC_SMBADDR2_SHIFT 23 + +#define CCB_SMB_NIC_SMBADDR2_MASK 0x007F0000 +#define CCB_SMB_NIC_SMBADDR2_SHIFT 16 + +#define CCB_SMB_EN_NIC_SMBADDR1_MASK 0x00008000 +#define CCB_SMB_EN_NIC_SMBADDR1_SHIFT 15 + +#define CCB_SMB_NIC_SMBADDR1_MASK 0x00007F00 +#define CCB_SMB_NIC_SMBADDR1_SHIFT 8 + +#define CCB_SMB_EN_NIC_SMBADDR0_MASK 0x00000080 +#define CCB_SMB_EN_NIC_SMBADDR0_SHIFT 7 + +#define CCB_SMB_NIC_SMBADDR0_MASK 0x0000007F +#define CCB_SMB_NIC_SMBADDR0_SHIFT 0 + +#define CCB_SMB_MSTRFIFOCTL_REG 0xC + +#define CCB_SMB_MSTRRXFIFOFLSH_MASK 0x80000000 +#define CCB_SMB_MSTRRXFIFOFLSH_SHIFT 31 + +#define CCB_SMB_MSTRTXFIFOFLSH_MASK 0x40000000 +#define CCB_SMB_MSTRTXFIFOFLSH_SHIFT 30 + +#define CCB_SMB_MSTRRXPKTCNT_MASK 0x007F0000 +#define CCB_SMB_MSTRRXPKTCNT_SHIFT 16 + +#define CCB_SMB_MSTRRXFIFOTHR_MASK 0x00003F00 +#define CCB_SMB_MSTRRXFIFOTHR_SHIFT 8 + +#define CCB_SMB_SLVFIFOCTL_REG 0x10 + +#define CCB_SMB_SLVRXFIFOFLSH_MASK 0x80000000 +#define CCB_SMB_SLVRXFIFOFLSH_SHIFT 31 + +#define CCB_SMB_SLVTXFIFOFLSH_MASK 0x40000000 +#define CCB_SMB_SLVTXFIFOFLSH_SHIFT 30 + +#define CCB_SMB_SLVRXPKTCNT_MASK 0x007F0000 +#define CCB_SMB_SLVRXPKTCNT_SHIFT 16 + +#define CCB_SMB_SLVRXFIFOTHR_MASK 0x00003F00 +#define CCB_SMB_SLVRXFIFOTHR_SHIFT 8 + +#define CCB_SMB_BITBANGCTL_REG 0x14 + +#define CCB_SMB_SMBCLKIN_MASK 0x80000000 +#define CCB_SMB_SMBCLKIN_SHIFT 31 + +#define CCB_SMB_SMBCLKOUTEN_MASK 0x40000000 +#define CCB_SMB_SMBCLKOUTEN_SHIFT 30 + +#define CCB_SMB_SMBDATAIN_MASK 0x20000000 +#define CCB_SMB_SMBDATAIN_SHIFT 29 + +#define CCB_SMB_SMBDATAOUTEN_MASK 0x10000000 +#define CCB_SMB_SMBDATAOUTEN_SHIFT 28 + +#define CCB_SMB_MSTRCMD_REG 0x30 + +#define CCB_SMB_MSTRSTARTBUSYCMD_MASK 0x80000000 +#define CCB_SMB_MSTRSTARTBUSYCMD_SHIFT 31 + +#define CCB_SMB_MSTRABORT_MASK 0x40000000 +#define CCB_SMB_MSTRABORT_SHIFT 30 + +#define CCB_SMB_MSTRSTS_MASK 0x0E000000 +#define CCB_SMB_MSTRSTS_SHIFT 25 + +#define CCB_SMB_MSTRSMBUSPROTO_MASK 0x00001E00 +#define CCB_SMB_MSTRSMBUSPROTO_SHIFT 9 + +#define CCB_SMB_MSTRPEC_MASK 0x00000100 +#define CCB_SMB_MSTRPEC_SHIFT 8 + +#define CCB_SMB_MSTRRDBYTECNT_MASK 0x000000FF +#define CCB_SMB_MSTRRDBYTECNT_SHIFT 0 + +#define CCB_SMB_SLVCMD_REG 0x34 + +#define CCB_SMB_SLVSTARTBUSYCMD_MASK 0x80000000 +#define CCB_SMB_SLVSTARTBUSYCMD_SHIFT 31 + +#define CCB_SMB_SLVABORT_MASK 0x40000000 +#define CCB_SMB_SLVABORT_SHIFT 30 + +#define CCB_SMB_SLVSTS_MASK 0x03800000 +#define CCB_SMB_SLVSTS_SHIFT 23 + +#define CCB_SMB_SLVPEC_MASK 0x00000100 +#define CCB_SMB_SLVPEC_SHIFT 8 + +#define CCB_SMB_EVTEN_REG 0x38 + +#define CCB_SMB_MSTRRXFIFOFULLEN_MASK 0x80000000 +#define CCB_SMB_MSTRRXFIFOFULLEN_SHIFT 31 + +#define CCB_SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000 +#define CCB_SMB_MSTRRXFIFOTHRHITEN_SHIFT 30 + +#define CCB_SMB_MSTRRXEVTEN_MASK 0x20000000 +#define CCB_SMB_MSTRRXEVTEN_SHIFT 29 + +#define CCB_SMB_MSTRSTARTBUSYEN_MASK 0x10000000 +#define CCB_SMB_MSTRSTARTBUSYEN_SHIFT 28 + +#define CCB_SMB_MSTRTXUNDEN_MASK 0x08000000 +#define CCB_SMB_MSTRTXUNDEN_SHIFT 27 + +#define CCB_SMB_SLVRXFIFOFULLEN_MASK 0x04000000 +#define CCB_SMB_SLVRXFIFOFULLEN_SHIFT 26 + +#define CCB_SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000 +#define CCB_SMB_SLVRXFIFOTHRHITEN_SHIFT 25 + +#define CCB_SMB_SLVRXEVTEN_MASK 0x01000000 +#define CCB_SMB_SLVRXEVTEN_SHIFT 24 + +#define CCB_SMB_SLVSTARTBUSYEN_MASK 0x00800000 +#define CCB_SMB_SLVSTARTBUSYEN_SHIFT 23 + +#define CCB_SMB_SLVTXUNDEN_MASK 0x00400000 +#define CCB_SMB_SLVTXUNDEN_SHIFT 22 + +#define CCB_SMB_SLVRDEVTEN_MASK 0x00200000 +#define CCB_SMB_SLVRDEVTEN_SHIFT 21 + +#define CCB_SMB_EVTSTS_REG 0x3C + +#define CCB_SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000 +#define CCB_SMB_MSTRRXFIFOFULLSTS_SHIFT 31 + +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000 +#define CCB_SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30 + +#define CCB_SMB_MSTRRXEVTSTS_MASK 0x20000000 +#define CCB_SMB_MSTRRXEVTSTS_SHIFT 29 + +#define CCB_SMB_MSTRSTARTBUSYSTS_MASK 0x10000000 +#define CCB_SMB_MSTRSTARTBUSYSTS_SHIFT 28 + +#define CCB_SMB_MSTRTXUNDSTS_MASK 0x08000000 +#define CCB_SMB_MSTRTXUNDSTS_SHIFT 27 + +#define CCB_SMB_SLVRXFIFOFULLSTS_MASK 0x04000000 +#define CCB_SMB_SLVRXFIFOFULLSTS_SHIFT 26 + +#define CCB_SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000 +#define CCB_SMB_SLVRXFIFOTHRHITSTS_SHIFT 25 + +#define CCB_SMB_SLVRXEVTSTS_MASK 0x01000000 +#define CCB_SMB_SLVRXEVTSTS_SHIFT 24 + +#define CCB_SMB_SLVSTARTBUSYSTS_MASK 0x00800000 +#define CCB_SMB_SLVSTARTBUSYSTS_SHIFT 23 + +#define CCB_SMB_SLVTXUNDSTS_MASK 0x00400000 +#define CCB_SMB_SLVTXUNDSTS_SHIFT 22 + +#define CCB_SMB_SLVRDEVTSTS_MASK 0x00200000 +#define CCB_SMB_SLVRDEVTSTS_SHIFT 21 + +#define CCB_SMB_MSTRDATAWR_REG 0x40 + +#define CCB_SMB_MSTRWRSTS_MASK 0x80000000 +#define CCB_SMB_MSTRWRSTS_SHIFT 31 + +#define CCB_SMB_MSTRWRDATA_MASK 0x000000FF +#define CCB_SMB_MSTRWRDATA_SHIFT 0 + +#define CCB_SMB_MSTRDATARD_REG 0x44 + +#define CCB_SMB_MSTRRDSTS_MASK 0xC0000000 +#define CCB_SMB_MSTRRDSTS_SHIFT 30 + +#define CCB_SMB_MSTRRDPECERR_MASK 0x20000000 +#define CCB_SMB_MSTRRDPECERR_SHIFT 29 + +#define CCB_SMB_MSTRRDDATA_MASK 0x000000FF +#define CCB_SMB_MSTRRDDATA_SHIFT 0 + +#define CCB_SMB_SLVDATAWR_REG 0x48 + +#define CCB_SMB_SLVWRSTS_MASK 0x80000000 +#define CCB_SMB_SLVWRSTS_SHIFT 31 + +#define CCB_SMB_SLVWRDATA_MASK 0x000000FF +#define CCB_SMB_SLVWRDATA_SHIFT 0 + +#define CCB_SMB_SLVDATARD_REG 0x4C + +#define CCB_SMB_SLVRDSTS_MASK 0xC0000000 +#define CCB_SMB_SLVRDSTS_SHIFT 30 + +#define CCB_SMB_SLVRDERRSTS_MASK 0x30000000 +#define CCB_SMB_SLVRDERRSTS_SHIFT 28 + +#define CCB_SMB_SLVRDDATA_MASK 0x000000FF +#define CCB_SMB_SLVRDDATA_SHIFT 0 + +/* --Registers-- */ + +/* Transaction error codes defined in Master command register (0x30) */ +#define MSTR_STS_XACT_SUCCESS 0 +#define MSTR_STS_LOST_ARB 1 +#define MSTR_STS_NACK_FIRST_BYTE 2 + +/* NACK on a byte other than + * the first byte + */ +#define MSTR_STS_NACK_NON_FIRST_BYTE 3 + +#define MSTR_STS_TTIMEOUT_EXCEEDED 4 +#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5 +#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6 + +/* SMBUS protocol values defined in register 0x30 */ +#define SMBUS_PROT_QUICK_CMD 0 +#define SMBUS_PROT_SEND_BYTE 1 +#define SMBUS_PROT_RECV_BYTE 2 +#define SMBUS_PROT_WR_BYTE 3 +#define SMBUS_PROT_RD_BYTE 4 +#define SMBUS_PROT_WR_WORD 5 +#define SMBUS_PROT_RD_WORD 6 +#define SMBUS_PROT_BLK_WR 7 +#define SMBUS_PROT_BLK_RD 8 +#define SMBUS_PROT_PROC_CALL 9 +#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10 + +/* SMBUS Block speed mode */ +#define SMBUS_BLOCK_MODE_100 0 +#define SMBUS_BLOCK_MODE_400 1 + +#define BUS_BUSY_COUNT 100000 /* Number can be changed later */ +#define IPROC_I2C_INVALID_ADDR 0xFF +#define IPROC_SMB_MAX_RETRIES 35 +#define I2C_SMBUS_BLOCK_MAX 32 +#define GETREGFLDVAL(regval, mask, startbit) \ + (((regval) & (mask)) >> (startbit)) +#define SETREGFLDVAL(regval, fldval, mask, startbit) (regval) = \ + ((regval) & ~(mask)) | \ + ((fldval) << (startbit)) + +/* Enum to specify clock speed. The user will provide it during initialization + * If needed, it can be changed dynamically + */ +enum iproc_smb_clk_freq { + I2C_SPEED_100KHZ = 100000, + I2C_SPEED_400KHZ = 400000, + I2C_SPEED_INVALID = 255 +}; + +/* This enum will be used to notify the user of status of a data transfer + * request + */ +enum iproc_smb_error_code { + I2C_NO_ERR = 0, + I2C_TIMEOUT_ERR = 1, + + /* Invalid parameter(s) passed to the driver */ + I2C_INVALID_PARAM_ERR = 2, + + /* The driver API was called before the present + * transfer was completed + */ + I2C_OPER_IN_PROGRESS = 3, + + /* Transfer aborted unexpectedly, for example a NACK + * received, before last byte was read/written + */ + I2C_OPER_ABORT_ERR = 4, + + /* Feature or function not supported + * (e.g., 10-bit addresses, or clock speeds + * other than 100KHz, 400KHz) + */ + I2C_FUNC_NOT_SUPPORTED = 5, +}; + +/* Structure used to pass information to read/write functions. */ +struct iproc_xact_info { + unsigned char command; + unsigned char *data; + unsigned int size; + unsigned short flags; /* used for specifying PEC, 10-bit addresses */ + unsigned char smb_proto; /* SMBus protocol */ + unsigned int cmd_valid; /* true if command is valid else false */ +}; + +#endif /* __IPROC_I2C_H__ */