diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 04:10:45 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 04:10:45 +0300 |
commit | c3a416a669eb83cfa9ccb52db030e72d654bd105 (patch) | |
tree | 518d00dc803fbb7d3772fc26a78b6bf3b797baf3 | |
parent | 8c194f3bd322a8bd44d079092d870549b8ae62d1 (diff) | |
parent | 2bbd681ba2bfa0f3805fb541b0840b96893c5727 (diff) | |
download | linux-c3a416a669eb83cfa9ccb52db030e72d654bd105.tar.xz |
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"Most notable:
- introducing the i2c_quirk infrastructure. Now, flaws of I2C
controllers can be described and the core will check if the flaws
collide with the messages to be sent
- wait_for_completion return type cleanup series
- new drivers for Digicolor, Netlogic XLP, Ingenic JZ4780
- updates to the I2C slave framework which include API changes. Its
only user was updated, too. Documentation was finally added
- changed dynamic bus numbering for the DT case. This could change
bus numbers for users. However, it fixes a collision where dynamic
and static busses request the same id.
- driver bugfixes, cleanups"
* 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (52 commits)
i2c: xlp9xx: Driver for Netlogic XLP9XX/5XX I2C controller
of: Add vendor prefix 'netlogic'
i2c: davinci: use ICPFUNC to toggle I2C as gpio for bus recovery
i2c: davinci: use bus recovery infrastructure
i2c: change input parameter to i2c_adapter for prepare/unprepare_recovery
i2c: i2c-mux-gpio: remove error messages for probe deferrals
i2c: jz4780: Add i2c bus controller driver for Ingenic JZ4780
i2c: dln2: set the device tree node of the adapter
i2c: davinci: fixup wait_for_completion_timeout handling
i2c: mpc: Fix ISR return value
i2c: slave-eeprom: add more info when to increase the pointer
i2c: slave: add documentation for i2c-slave-eeprom
Documentation: i2c: describe the new slave mode
i2c: slave: rework the slave API
i2c: add support for the Digicolor I2C controller
i2c: busses with dynamic ids should start after fixed ids for DT
of: base: add function to get highest id of an alias stem
i2c: designware: Suppress error message if platform_get_irq() < 0
i2c: mpc: assign the correct prescaler from SVR
i2c: img-scb: fixup of wait_for_completion_timeout return handling
...
46 files changed, 2483 insertions, 276 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt index 2dc935b4113d..a4e1cbc810c1 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt @@ -10,6 +10,9 @@ Required properties: Recommended properties : - interrupts : standard interrupt property. - clock-frequency : desired I2C bus clock frequency in Hz. +- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC + registers. PFUNC registers allow to switch I2C pins to function as + GPIOs, so they can by toggled manually. Example (enbw_cmc board): i2c@1c22000 { diff --git a/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt new file mode 100644 index 000000000000..457a098d4f7e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt @@ -0,0 +1,25 @@ +Conexant Digicolor I2C controller + +Required properties: + - compatible: must be "cnxt,cx92755-i2c" + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + +Optional properties: +- clock-frequency: the desired I2C bus clock frequency in Hz; in + absence of this property the default value is used (100 kHz). + +Example: + + i2c: i2c@f0000120 { + compatible = "cnxt,cx92755-i2c"; + reg = <0xf0000120 0x10>; + interrupts = <28>; + clocks = <&main_clk>; + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt b/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt new file mode 100644 index 000000000000..231e4cc4008c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt @@ -0,0 +1,35 @@ +* Ingenic JZ4780 I2C Bus controller + +Required properties: +- compatible: should be "ingenic,jz4780-i2c" +- reg: Should contain the address & size of the I2C controller registers. +- interrupts: Should specify the interrupt provided by parent. +- clocks: Should contain a single clock specifier for the JZ4780 I2C clock. +- clock-frequency: desired I2C bus clock frequency in Hz. + +Recommended properties: +- pinctrl-names: should be "default"; +- pinctrl-0: phandle to pinctrl function + +Optional properties: +- interrupt-parent: Should be the phandle of the interrupt controller that + delivers interrupts to the I2C block. + +Example + +/ { + i2c4: i2c4@0x10054000 { + compatible = "ingenic,jz4780-i2c"; + reg = <0x10054000 0x1000>; + + interrupt-parent = <&intc>; + interrupts = <56>; + + clocks = <&cgu JZ4780_CLK_SMB4>; + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pins_i2c4_data>; + + }; +}; + diff --git a/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt new file mode 100644 index 000000000000..f818ef507ab7 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt @@ -0,0 +1,22 @@ +Device tree configuration for the I2C controller on the XLP9xx/5xx SoC + +Required properties: +- compatible : should be "netlogic,xlp980-i2c" +- reg : bus address start and address range size of device +- interrupts : interrupt number + +Optional properties: +- clock-frequency : frequency of bus clock in Hz + Defaults to 100 KHz when the property is not specified + +Example: + +i2c0: i2c@113100 { + compatible = "netlogic,xlp980-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x113100 0x100>; + clock-frequency = <400000>; + interrupts = <30>; + interrupt-parent = <&pic>; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 9b98bd89cfe2..8764b5b78772 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -125,6 +125,7 @@ mxicy Macronix International Co., Ltd. national National Semiconductor neonode Neonode Inc. netgear NETGEAR +netlogic Broadcom Corporation (formerly NetLogic Microsystems) newhaven Newhaven Display International nintendo Nintendo nokia Nokia diff --git a/Documentation/i2c/slave-eeprom-backend b/Documentation/i2c/slave-eeprom-backend new file mode 100644 index 000000000000..c8444ef82acf --- /dev/null +++ b/Documentation/i2c/slave-eeprom-backend @@ -0,0 +1,14 @@ +Linux I2C slave eeprom backend +============================== + +by Wolfram Sang <wsa@sang-engineering.com> in 2014-15 + +This is a proof-of-concept backend which acts like an EEPROM on the connected +I2C bus. The memory contents can be modified from userspace via this file +located in sysfs: + + /sys/bus/i2c/devices/<device-direcory>/slave-eeprom + +As of 2015, Linux doesn't support poll on binary sysfs files, so there is no +notfication when another master changed the content. + diff --git a/Documentation/i2c/slave-interface b/Documentation/i2c/slave-interface new file mode 100644 index 000000000000..389bb5d61854 --- /dev/null +++ b/Documentation/i2c/slave-interface @@ -0,0 +1,179 @@ +Linux I2C slave interface description +===================================== + +by Wolfram Sang <wsa@sang-engineering.com> in 2014-15 + +Linux can also be an I2C slave in case I2C controllers have slave support. +Besides this HW requirement, one also needs a software backend providing the +actual functionality. An example for this is the slave-eeprom driver, which +acts as a dual memory driver. While another I2C master on the bus can access it +like a regular EEPROM, the Linux I2C slave can access the content via sysfs and +retrieve/provide information as needed. The software backend driver and the I2C +bus driver communicate via events. Here is a small graph visualizing the data +flow and the means by which data is transported. The dotted line marks only one +example. The backend could also use e.g. a character device, be in-kernel +only, or something completely different: + + + e.g. sysfs I2C slave events I/O registers + +-----------+ v +---------+ v +--------+ v +------------+ + | Userspace +........+ Backend +-----------+ Driver +-----+ Controller | + +-----------+ +---------+ +--------+ +------------+ + | | + ----------------------------------------------------------------+-- I2C + --------------------------------------------------------------+---- Bus + +Note: Technically, there is also the I2C core between the backend and the +driver. However, at this time of writing, the layer is transparent. + + +User manual +=========== + +I2C slave backends behave like standard I2C clients. So, you can instantiate +them like described in the document 'instantiating-devices'. A quick example +for instantiating the slave-eeprom driver from userspace: + + # echo 0-0064 > /sys/bus/i2c/drivers/i2c-slave-eeprom/bind + +Each backend should come with separate documentation to describe its specific +behaviour and setup. + + +Developer manual +================ + +I2C slave events +---------------- + +The bus driver sends an event to the backend using the following function: + + ret = i2c_slave_event(client, event, &val) + +'client' describes the i2c slave device. 'event' is one of the special event +types described hereafter. 'val' holds an u8 value for the data byte to be +read/written and is thus bidirectional. The pointer to val must always be +provided even if val is not used for an event, i.e. don't use NULL here. 'ret' +is the return value from the backend. Mandatory events must be provided by the +bus drivers and must be checked for by backend drivers. + +Event types: + +* I2C_SLAVE_WRITE_REQUESTED (mandatory) + +'val': unused +'ret': always 0 + +Another I2C master wants to write data to us. This event should be sent once +our own address and the write bit was detected. The data did not arrive yet, so +there is nothing to process or return. Wakeup or initialization probably needs +to be done, though. + +* I2C_SLAVE_READ_REQUESTED (mandatory) + +'val': backend returns first byte to be sent +'ret': always 0 + +Another I2C master wants to read data from us. This event should be sent once +our own address and the read bit was detected. After returning, the bus driver +should transmit the first byte. + +* I2C_SLAVE_WRITE_RECEIVED (mandatory) + +'val': bus driver delivers received byte +'ret': 0 if the byte should be acked, some errno if the byte should be nacked + +Another I2C master has sent a byte to us which needs to be set in 'val'. If 'ret' +is zero, the bus driver should ack this byte. If 'ret' is an errno, then the byte +should be nacked. + +* I2C_SLAVE_READ_PROCESSED (mandatory) + +'val': backend returns next byte to be sent +'ret': always 0 + +The bus driver requests the next byte to be sent to another I2C master in +'val'. Important: This does not mean that the previous byte has been acked, it +only means that the previous byte is shifted out to the bus! To ensure seamless +transmission, most hardware requests the next byte when the previous one is +still shifted out. If the master sends NACK and stops reading after the byte +currently shifted out, this byte requested here is never used. It very likely +needs to be sent again on the next I2C_SLAVE_READ_REQUEST, depending a bit on +your backend, though. + +* I2C_SLAVE_STOP (mandatory) + +'val': unused +'ret': always 0 + +A stop condition was received. This can happen anytime and the backend should +reset its state machine for I2C transfers to be able to receive new requests. + + +Software backends +----------------- + +If you want to write a software backend: + +* use a standard i2c_driver and its matching mechanisms +* write the slave_callback which handles the above slave events + (best using a state machine) +* register this callback via i2c_slave_register() + +Check the i2c-slave-eeprom driver as an example. + + +Bus driver support +------------------ + +If you want to add slave support to the bus driver: + +* implement calls to register/unregister the slave and add those to the + struct i2c_algorithm. When registering, you probably need to set the i2c + slave address and enable slave specific interrupts. If you use runtime pm, you + should use pm_runtime_forbid() because your device usually needs to be powered + on always to be able to detect its slave address. When unregistering, do the + inverse of the above. + +* Catch the slave interrupts and send appropriate i2c_slave_events to the backend. + +Check the i2c-rcar driver as an example. + + +About ACK/NACK +-------------- + +It is good behaviour to always ACK the address phase, so the master knows if a +device is basically present or if it mysteriously disappeared. Using NACK to +state being busy is troublesome. SMBus demands to always ACK the address phase, +while the I2C specification is more loose on that. Most I2C controllers also +automatically ACK when detecting their slave addresses, so there is no option +to NACK them. For those reasons, this API does not support NACK in the address +phase. + +Currently, there is no slave event to report if the master did ACK or NACK a +byte when it reads from us. We could make this an optional event if the need +arises. However, cases should be extremely rare because the master is expected +to send STOP after that and we have an event for that. Also, keep in mind not +all I2C controllers have the possibility to report that event. + + +About buffers +------------- + +During development of this API, the question of using buffers instead of just +bytes came up. Such an extension might be possible, usefulness is unclear at +this time of writing. Some points to keep in mind when using buffers: + +* Buffers should be opt-in and slave drivers will always have to support + byte-based transactions as the ultimate fallback because this is how the + majority of HW works. + +* For backends simulating hardware registers, buffers are not helpful because + on writes an action should be immediately triggered. For reads, the data in + the buffer might get stale. + +* A master can send STOP at any time. For partially transferred buffers, this + means additional code to handle this exception. Such code tends to be + error-prone. + diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary index 13ab076dcd92..809541ab352f 100644 --- a/Documentation/i2c/summary +++ b/Documentation/i2c/summary @@ -41,7 +41,3 @@ integrated than Algorithm and Adapter. For a given configuration, you will need a driver for your I2C bus, and drivers for your I2C devices (usually one driver for each device). - -At this time, Linux only operates I2C (or SMBus) in master mode; you can't -use these APIs to make a Linux system behave as a slave/device, either to -speak a custom protocol or to emulate some other device. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 22da9c2ffa22..2255af23b9c7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -485,6 +485,15 @@ config I2C_DESIGNWARE_BAYTRAIL the platform firmware controlling it. You should say Y if running on a BayTrail system using the AXP288. +config I2C_DIGICOLOR + tristate "Conexant Digicolor I2C driver" + depends on ARCH_DIGICOLOR + help + Support for Conexant Digicolor SoCs (CX92755) I2C controller driver. + + This driver can also be built as a module. If so, the module + will be called i2c-digicolor. + config I2C_EFM32 tristate "EFM32 I2C controller" depends on ARCH_EFM32 || COMPILE_TEST @@ -574,6 +583,15 @@ config I2C_IOP3XX This driver can also be built as a module. If so, the module will be called i2c-iop3xx. +config I2C_JZ4780 + tristate "JZ4780 I2C controller interface support" + depends on MACH_JZ4780 || COMPILE_TEST + help + If you say yes to this option, support will be included for the + Ingenic JZ4780 I2C controller. + + If you don't know what to do here, say N. + config I2C_KEMPLD tristate "Kontron COM I2C Controller" depends on MFD_KEMPLD @@ -898,6 +916,16 @@ config I2C_XLR This driver can also be built as a module. If so, the module will be called i2c-xlr. +config I2C_XLP9XX + tristate "XLP9XX I2C support" + depends on CPU_XLP || COMPILE_TEST + help + This driver enables support for the on-chip I2C interface of + the Broadcom XLP9xx/XLP5xx MIPS processors. + + This driver can also be built as a module. If so, the module will + be called i2c-xlp9xx. + config I2C_RCAR tristate "Renesas R-Car I2C Controller" depends on ARCH_SHMOBILE || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3638feb6677e..cdf941da91c6 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -45,6 +45,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-objs := i2c-designware-pcidrv.o +obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o @@ -55,6 +56,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o +obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o @@ -87,6 +89,7 @@ obj-$(CONFIG_I2C_WMT) += i2c-wmt.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o +obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o # External I2C/SMBus adapter drivers diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 636fd2efad88..ff23d1bdd230 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -381,6 +381,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) static int at91_do_twi_transfer(struct at91_twi_dev *dev) { int ret; + unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; dev_dbg(dev->dev, "transfer: %s %d bytes.\n", @@ -436,9 +437,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) } } - ret = wait_for_completion_timeout(&dev->cmd_complete, - dev->adapter.timeout); - if (ret == 0) { + time_left = wait_for_completion_timeout(&dev->cmd_complete, + dev->adapter.timeout); + if (time_left == 0) { dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; @@ -487,30 +488,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) if (ret < 0) goto out; - /* - * The hardware can handle at most two messages concatenated by a - * repeated start via it's internal address feature. - */ - if (num > 2) { - dev_err(dev->dev, - "cannot handle more than two concatenated messages.\n"); - ret = 0; - goto out; - } else if (num == 2) { + if (num == 2) { int internal_address = 0; int i; - if (msg->flags & I2C_M_RD) { - dev_err(dev->dev, "first transfer must be write.\n"); - ret = -EINVAL; - goto out; - } - if (msg->len > 3) { - dev_err(dev->dev, "first message size must be <= 3.\n"); - ret = -EINVAL; - goto out; - } - /* 1st msg is put into the internal address, start with 2nd */ m_start = &msg[1]; for (i = 0; i < msg->len; ++i) { @@ -540,6 +521,15 @@ out: return ret; } +/* + * The hardware can handle at most two messages concatenated by a + * repeated start via it's internal address feature. + */ +static struct i2c_adapter_quirks at91_twi_quirks = { + .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR, + .max_comb_1st_msg_len = 3, +}; + static u32 at91_twi_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL @@ -777,6 +767,7 @@ static int at91_twi_probe(struct platform_device *pdev) dev->adapter.owner = THIS_MODULE; dev->adapter.class = I2C_CLASS_DEPRECATED; dev->adapter.algo = &at91_twi_algorithm; + dev->adapter.quirks = &at91_twi_quirks; dev->adapter.dev.parent = dev->dev; dev->adapter.nr = pdev->id; dev->adapter.timeout = AT91_I2C_TIMEOUT; diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index 768a598d8d03..32d883490863 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -334,12 +334,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS; u32 rx_xfer, tx_xfer; u32 addr_1, addr_2; - int ret; - - if (msg->len > 255) { - dev_warn(idev->dev, "unsupported length %u\n", msg->len); - return -EINVAL; - } + unsigned long time_left; idev->msg = msg; idev->msg_xfrd = 0; @@ -388,15 +383,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) i2c_int_enable(idev, int_mask); - ret = wait_for_completion_timeout(&idev->msg_complete, - I2C_XFER_TIMEOUT); + time_left = wait_for_completion_timeout(&idev->msg_complete, + I2C_XFER_TIMEOUT); i2c_int_disable(idev, int_mask); if (readl(idev->base + MST_COMMAND) & CMD_BUSY) dev_warn(idev->dev, "busy after xfer\n"); - if (ret == 0) + if (time_left == 0) idev->msg_err = -ETIMEDOUT; if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO) @@ -408,17 +403,17 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) static int axxia_i2c_stop(struct axxia_i2c_dev *idev) { u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC; - int ret; + unsigned long time_left; reinit_completion(&idev->msg_complete); /* Issue stop */ writel(0xb, idev->base + MST_COMMAND); i2c_int_enable(idev, int_mask); - ret = wait_for_completion_timeout(&idev->msg_complete, - I2C_STOP_TIMEOUT); + time_left = wait_for_completion_timeout(&idev->msg_complete, + I2C_STOP_TIMEOUT); i2c_int_disable(idev, int_mask); - if (ret == 0) + if (time_left == 0) return -ETIMEDOUT; if (readl(idev->base + MST_COMMAND) & CMD_BUSY) @@ -454,6 +449,11 @@ static const struct i2c_algorithm axxia_i2c_algo = { .functionality = axxia_i2c_func, }; +static struct i2c_adapter_quirks axxia_i2c_quirks = { + .max_read_len = 255, + .max_write_len = 255, +}; + static int axxia_i2c_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -511,6 +511,7 @@ static int axxia_i2c_probe(struct platform_device *pdev) strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); idev->adapter.owner = THIS_MODULE; idev->adapter.algo = &axxia_i2c_algo; + idev->adapter.quirks = &axxia_i2c_quirks; idev->adapter.dev.parent = &pdev->dev; idev->adapter.dev.of_node = pdev->dev.of_node; diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index d3c89157b337..f9f2c2082151 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -160,14 +160,6 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, u32 val; unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC); - /* need to reserve one byte in the FIFO for the slave address */ - if (msg->len > M_TX_RX_FIFO_SIZE - 1) { - dev_err(iproc_i2c->device, - "only support data length up to %u bytes\n", - M_TX_RX_FIFO_SIZE - 1); - return -EOPNOTSUPP; - } - /* check if bus is busy */ if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) & BIT(M_CMD_START_BUSY_SHIFT))) { @@ -287,6 +279,12 @@ static const struct i2c_algorithm bcm_iproc_algo = { .functionality = bcm_iproc_i2c_functionality, }; +static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { + /* need to reserve one byte in the FIFO for the slave address */ + .max_read_len = M_TX_RX_FIFO_SIZE - 1, + .max_write_len = M_TX_RX_FIFO_SIZE - 1, +}; + static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) { unsigned int bus_speed; @@ -413,6 +411,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, iproc_i2c); strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name)); adap->algo = &bcm_iproc_algo; + adap->quirks = &bcm_iproc_i2c_quirks; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 5d6feb937b9d..c9336a3202d5 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -147,7 +147,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, struct i2c_msg *msg) { u32 c; - int time_left; + unsigned long time_left; i2c_dev->msg_buf = msg->buf; i2c_dev->msg_buf_remaining = msg->len; diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 7d7a14cdadfb..2ee78e099d30 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -475,7 +475,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap) static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, struct i2c_adapter *adap) { - int ret; + unsigned long time_left; u32 reg; id->p_msg = msg; @@ -501,8 +501,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, cdns_i2c_msend(id); /* Wait for the signal of completion */ - ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout); - if (!ret) { + time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout); + if (time_left == 0) { cdns_i2c_master_reset(adap); dev_err(id->adap.dev.parent, "timeout waiting on completion\n"); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 2d466538b2e2..714bdc837769 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -308,22 +308,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg; struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram; struct i2c_msg *pmsg; - int ret, i; + int ret; int tptr; int rptr; cbd_t __iomem *tbdf; cbd_t __iomem *rbdf; - if (num > CPM_MAXBD) - return -EINVAL; - - /* Check if we have any oversized READ requests */ - for (i = 0; i < num; i++) { - pmsg = &msgs[i]; - if (pmsg->len >= CPM_MAX_READ) - return -EINVAL; - } - /* Reset to use first buffer */ out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase)); out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase)); @@ -424,10 +414,18 @@ static const struct i2c_algorithm cpm_i2c_algo = { .functionality = cpm_i2c_func, }; +/* CPM_MAX_READ is also limiting writes according to the code! */ +static struct i2c_adapter_quirks cpm_i2c_quirks = { + .max_num_msgs = CPM_MAXBD, + .max_read_len = CPM_MAX_READ, + .max_write_len = CPM_MAX_READ, +}; + static const struct i2c_adapter cpm_ops = { .owner = THIS_MODULE, .name = "i2c-cpm", .algo = &cpm_i2c_algo, + .quirks = &cpm_i2c_quirks, }; static int cpm_i2c_setup(struct cpm_i2c *cpm) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 6dc7ff5d3d9a..4788a32afb86 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -60,6 +60,12 @@ #define DAVINCI_I2C_IVR_REG 0x28 #define DAVINCI_I2C_EMDR_REG 0x2c #define DAVINCI_I2C_PSC_REG 0x30 +#define DAVINCI_I2C_FUNC_REG 0x48 +#define DAVINCI_I2C_DIR_REG 0x4c +#define DAVINCI_I2C_DIN_REG 0x50 +#define DAVINCI_I2C_DOUT_REG 0x54 +#define DAVINCI_I2C_DSET_REG 0x58 +#define DAVINCI_I2C_DCLR_REG 0x5c #define DAVINCI_I2C_IVR_AAS 0x07 #define DAVINCI_I2C_IVR_SCD 0x06 @@ -93,6 +99,29 @@ #define DAVINCI_I2C_IMR_NACK BIT(1) #define DAVINCI_I2C_IMR_AL BIT(0) +/* set SDA and SCL as GPIO */ +#define DAVINCI_I2C_FUNC_PFUNC0 BIT(0) + +/* set SCL as output when used as GPIO*/ +#define DAVINCI_I2C_DIR_PDIR0 BIT(0) +/* set SDA as output when used as GPIO*/ +#define DAVINCI_I2C_DIR_PDIR1 BIT(1) + +/* read SCL GPIO level */ +#define DAVINCI_I2C_DIN_PDIN0 BIT(0) +/* read SDA GPIO level */ +#define DAVINCI_I2C_DIN_PDIN1 BIT(1) + +/*set the SCL GPIO high */ +#define DAVINCI_I2C_DSET_PDSET0 BIT(0) +/*set the SDA GPIO high */ +#define DAVINCI_I2C_DSET_PDSET1 BIT(1) + +/* set the SCL GPIO low */ +#define DAVINCI_I2C_DCLR_PDCLR0 BIT(0) +/* set the SDA GPIO low */ +#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1) + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -129,43 +158,6 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg) return readw_relaxed(i2c_dev->base + reg); } -/* Generate a pulse on the i2c clock pin. */ -static void davinci_i2c_clock_pulse(unsigned int scl_pin) -{ - u16 i; - - if (scl_pin) { - /* Send high and low on the SCL line */ - for (i = 0; i < 9; i++) { - gpio_set_value(scl_pin, 0); - udelay(20); - gpio_set_value(scl_pin, 1); - udelay(20); - } - } -} - -/* This routine does i2c bus recovery as specified in the - * i2c protocol Rev. 03 section 3.16 titled "Bus clear" - */ -static void davinci_i2c_recover_bus(struct davinci_i2c_dev *dev) -{ - u32 flag = 0; - struct davinci_i2c_platform_data *pdata = dev->pdata; - - dev_err(dev->dev, "initiating i2c bus recovery\n"); - /* Send NACK to the slave */ - flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); - flag |= DAVINCI_I2C_MDR_NACK; - /* write the data into mode register */ - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); - davinci_i2c_clock_pulse(pdata->scl_pin); - /* Send STOP */ - flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); - flag |= DAVINCI_I2C_MDR_STP; - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); -} - static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, int val) { @@ -263,6 +255,99 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) } /* + * This routine does i2c bus recovery by using i2c_generic_gpio_recovery + * which is provided by I2C Bus recovery infrastructure. + */ +static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + /* Disable interrupts */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, 0); + + /* put I2C into reset */ + davinci_i2c_reset_ctrl(dev, 0); +} + +static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_davinci_init(dev); +} + +static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { + .recover_bus = i2c_generic_gpio_recovery, + .prepare_recovery = davinci_i2c_prepare_recovery, + .unprepare_recovery = davinci_i2c_unprepare_recovery, +}; + +static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + if (val) + davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG, + DAVINCI_I2C_DSET_PDSET0); + else + davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG, + DAVINCI_I2C_DCLR_PDCLR0); +} + +static int davinci_i2c_get_scl(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int val; + + /* read the state of SCL */ + val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG); + return val & DAVINCI_I2C_DIN_PDIN0; +} + +static int davinci_i2c_get_sda(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + int val; + + /* read the state of SDA */ + val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG); + return val & DAVINCI_I2C_DIN_PDIN1; +} + +static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + davinci_i2c_prepare_recovery(adap); + + /* SCL output, SDA input */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0); + + /* change to GPIO mode */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, + DAVINCI_I2C_FUNC_PFUNC0); +} + +static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap) +{ + struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); + + /* change back to I2C mode */ + davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0); + + davinci_i2c_unprepare_recovery(adap); +} + +static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .set_scl = davinci_i2c_set_scl, + .get_scl = davinci_i2c_get_scl, + .get_sda = davinci_i2c_get_sda, + .prepare_recovery = davinci_i2c_scl_prepare_recovery, + .unprepare_recovery = davinci_i2c_scl_unprepare_recovery, +}; + +/* * Waiting for bus not busy */ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, @@ -282,8 +367,7 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, return -ETIMEDOUT; } else { to_cnt = 0; - davinci_i2c_recover_bus(dev); - i2c_davinci_init(dev); + i2c_recover_bus(&dev->adapter); } } if (allow_sleep) @@ -304,7 +388,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) struct davinci_i2c_platform_data *pdata = dev->pdata; u32 flag; u16 w; - int r; + unsigned long time_left; /* Introduce a delay, required for some boards (e.g Davinci EVM) */ if (pdata->bus_delay) @@ -368,11 +452,11 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) flag |= DAVINCI_I2C_MDR_STP; davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); - r = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout); - if (r == 0) { + time_left = wait_for_completion_timeout(&dev->cmd_complete, + dev->adapter.timeout); + if (!time_left) { dev_err(dev->dev, "controller timed out\n"); - davinci_i2c_recover_bus(dev); - i2c_davinci_init(dev); + i2c_recover_bus(adap); dev->buf_len = 0; return -ETIMEDOUT; } @@ -380,17 +464,13 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) /* This should be 0 if all bytes were transferred * or dev->cmd_err denotes an error. */ - if (r >= 0) { - dev_err(dev->dev, "abnormal termination buf_len=%i\n", - dev->buf_len); - r = -EREMOTEIO; - } + dev_err(dev->dev, "abnormal termination buf_len=%i\n", + dev->buf_len); dev->terminate = 1; wmb(); dev->buf_len = 0; + return -EREMOTEIO; } - if (r < 0) - return r; /* no error */ if (likely(!dev->cmd_err)) @@ -674,6 +754,10 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", &prop)) dev->pdata->bus_freq = prop / 1000; + + dev->pdata->has_pfunc = + of_property_read_bool(pdev->dev.of_node, + "ti,has-pfunc"); } else if (!dev->pdata) { dev->pdata = &davinci_i2c_platform_data_default; } @@ -715,6 +799,14 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->timeout = DAVINCI_I2C_TIMEOUT; adap->dev.of_node = pdev->dev.of_node; + if (dev->pdata->has_pfunc) + adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; + else if (dev->pdata->scl_pin) { + adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; + adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; + adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; + } + adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); if (r) { diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 6e25c010e690..6f19a33773fe 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -656,8 +656,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_dw_xfer_init(dev); /* wait for tx to complete */ - ret = wait_for_completion_timeout(&dev->cmd_complete, HZ); - if (ret == 0) { + if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ i2c_dw_init(dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index c270f5f9a8f9..fa4e2b521f0d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -143,10 +143,8 @@ static int dw_i2c_probe(struct platform_device *pdev) u32 clk_freq, ht = 0; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); - return irq; /* -ENXIO */ - } + if (irq < 0) + return irq; dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); if (!dev) diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c new file mode 100644 index 000000000000..03f1e5549896 --- /dev/null +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -0,0 +1,385 @@ +/* + * I2C bus driver for Conexant Digicolor SoCs + * + * Author: Baruch Siach <baruch@tkos.co.il> + * + * Copyright (C) 2015 Paradox Innovation Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define DEFAULT_FREQ 100000 +#define TIMEOUT_MS 100 + +#define II_CONTROL 0x0 +#define II_CONTROL_LOCAL_RESET BIT(0) + +#define II_CLOCKTIME 0x1 + +#define II_COMMAND 0x2 +#define II_CMD_START 1 +#define II_CMD_RESTART 2 +#define II_CMD_SEND_ACK 3 +#define II_CMD_GET_ACK 6 +#define II_CMD_GET_NOACK 7 +#define II_CMD_STOP 10 +#define II_COMMAND_GO BIT(7) +#define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3) +#define II_CMD_STATUS_NORMAL 0 +#define II_CMD_STATUS_ACK_GOOD 1 +#define II_CMD_STATUS_ACK_BAD 2 +#define II_CMD_STATUS_ABORT 3 + +#define II_DATA 0x3 +#define II_INTFLAG_CLEAR 0x8 +#define II_INTENABLE 0xa + +struct dc_i2c { + struct i2c_adapter adap; + struct device *dev; + void __iomem *regs; + struct clk *clk; + unsigned int frequency; + + struct i2c_msg *msg; + unsigned int msgbuf_ptr; + int last; + spinlock_t lock; + struct completion done; + int state; + int error; +}; + +enum { + STATE_IDLE, + STATE_START, + STATE_ADDR, + STATE_WRITE, + STATE_READ, + STATE_STOP, +}; + +static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd) +{ + writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND); +} + +static u8 dc_i2c_addr_cmd(struct i2c_msg *msg) +{ + u8 addr = (msg->addr & 0x7f) << 1; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + return addr; +} + +static void dc_i2c_data(struct dc_i2c *i2c, u8 data) +{ + writeb_relaxed(data, i2c->regs + II_DATA); +} + +static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte) +{ + dc_i2c_data(i2c, byte); + dc_i2c_cmd(i2c, II_CMD_SEND_ACK); +} + +static void dc_i2c_write_buf(struct dc_i2c *i2c) +{ + dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]); +} + +static void dc_i2c_next_read(struct dc_i2c *i2c) +{ + bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len); + + dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK); +} + +static void dc_i2c_stop(struct dc_i2c *i2c) +{ + i2c->state = STATE_STOP; + if (i2c->last) + dc_i2c_cmd(i2c, II_CMD_STOP); + else + complete(&i2c->done); +} + +static u8 dc_i2c_read_byte(struct dc_i2c *i2c) +{ + return readb_relaxed(i2c->regs + II_DATA); +} + +static void dc_i2c_read_buf(struct dc_i2c *i2c) +{ + i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c); + dc_i2c_next_read(i2c); +} + +static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable) +{ + if (enable) + writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); + writeb_relaxed(!!enable, i2c->regs + II_INTENABLE); +} + +static int dc_i2c_cmd_status(struct dc_i2c *i2c) +{ + u8 cmd = readb_relaxed(i2c->regs + II_COMMAND); + + return II_COMMAND_COMPLETION_STATUS(cmd); +} + +static void dc_i2c_start_msg(struct dc_i2c *i2c, int first) +{ + struct i2c_msg *msg = i2c->msg; + + if (!(msg->flags & I2C_M_NOSTART)) { + i2c->state = STATE_START; + dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART); + } else if (msg->flags & I2C_M_RD) { + i2c->state = STATE_READ; + dc_i2c_next_read(i2c); + } else { + i2c->state = STATE_WRITE; + dc_i2c_write_buf(i2c); + } +} + +static irqreturn_t dc_i2c_irq(int irq, void *dev_id) +{ + struct dc_i2c *i2c = dev_id; + int cmd_status = dc_i2c_cmd_status(i2c); + unsigned long flags; + u8 addr_cmd; + + writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); + + spin_lock_irqsave(&i2c->lock, flags); + + if (cmd_status == II_CMD_STATUS_ACK_BAD + || cmd_status == II_CMD_STATUS_ABORT) { + i2c->error = -EIO; + complete(&i2c->done); + goto out; + } + + switch (i2c->state) { + case STATE_START: + addr_cmd = dc_i2c_addr_cmd(i2c->msg); + dc_i2c_write_byte(i2c, addr_cmd); + i2c->state = STATE_ADDR; + break; + case STATE_ADDR: + if (i2c->msg->flags & I2C_M_RD) { + dc_i2c_next_read(i2c); + i2c->state = STATE_READ; + break; + } + i2c->state = STATE_WRITE; + /* fall through */ + case STATE_WRITE: + if (i2c->msgbuf_ptr < i2c->msg->len) + dc_i2c_write_buf(i2c); + else + dc_i2c_stop(i2c); + break; + case STATE_READ: + if (i2c->msgbuf_ptr < i2c->msg->len) + dc_i2c_read_buf(i2c); + else + dc_i2c_stop(i2c); + break; + case STATE_STOP: + i2c->state = STATE_IDLE; + complete(&i2c->done); + break; + } + +out: + spin_unlock_irqrestore(&i2c->lock, flags); + return IRQ_HANDLED; +} + +static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, + int last) +{ + unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS); + unsigned long flags; + + spin_lock_irqsave(&i2c->lock, flags); + i2c->msg = msg; + i2c->msgbuf_ptr = 0; + i2c->last = last; + i2c->error = 0; + + reinit_completion(&i2c->done); + dc_i2c_set_irq(i2c, 1); + dc_i2c_start_msg(i2c, first); + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->done, timeout); + dc_i2c_set_irq(i2c, 0); + if (timeout == 0) { + i2c->state = STATE_IDLE; + return -ETIMEDOUT; + } + + if (i2c->error) + return i2c->error; + + return 0; +} + +static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct dc_i2c *i2c = adap->algo_data; + int i, ret; + + for (i = 0; i < num; i++) { + ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1); + if (ret) + return ret; + } + + return num; +} + +static int dc_i2c_init_hw(struct dc_i2c *i2c) +{ + unsigned long clk_rate = clk_get_rate(i2c->clk); + unsigned int clocktime; + + writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL); + udelay(100); + writeb_relaxed(0, i2c->regs + II_CONTROL); + udelay(100); + + clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency); + if (clocktime < 1 || clocktime > 0xff) { + dev_err(i2c->dev, "can't set bus speed of %u Hz\n", + i2c->frequency); + return -EINVAL; + } + writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME); + + return 0; +} + +static u32 dc_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm dc_i2c_algorithm = { + .master_xfer = dc_i2c_xfer, + .functionality = dc_i2c_func, +}; + +static int dc_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct dc_i2c *i2c; + struct resource *r; + int ret = 0, irq; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->frequency)) + i2c->frequency = DEFAULT_FREQ; + + i2c->dev = &pdev->dev; + platform_set_drvdata(pdev, i2c); + + spin_lock_init(&i2c->lock); + init_completion(&i2c->done); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) + return PTR_ERR(i2c->clk); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0, + dev_name(&pdev->dev), i2c); + if (ret < 0) + return ret; + + strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter", + sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &dc_i2c_algorithm; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = np; + i2c->adap.algo_data = i2c; + + ret = dc_i2c_init_hw(i2c); + if (ret) + return ret; + + ret = clk_prepare_enable(i2c->clk); + if (ret < 0) + return ret; + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + clk_unprepare(i2c->clk); + return ret; + } + + return 0; +} + +static int dc_i2c_remove(struct platform_device *pdev) +{ + struct dc_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + clk_disable_unprepare(i2c->clk); + + return 0; +} + +static const struct of_device_id dc_i2c_match[] = { + { .compatible = "cnxt,cx92755-i2c" }, + { }, +}; + +static struct platform_driver dc_i2c_driver = { + .probe = dc_i2c_probe, + .remove = dc_i2c_remove, + .driver = { + .name = "digicolor-i2c", + .of_match_table = dc_i2c_match, + }, +}; +module_platform_driver(dc_i2c_driver); + +MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); +MODULE_DESCRIPTION("Conexant Digicolor I2C master driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index b3fb86af4cbb..1600edd57ce9 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -144,7 +144,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter, { struct dln2_i2c *dln2 = i2c_get_adapdata(adapter); struct i2c_msg *pmsg; - struct device *dev = &dln2->adapter.dev; int i; for (i = 0; i < num; i++) { @@ -152,11 +151,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter, pmsg = &msgs[i]; - if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) { - dev_warn(dev, "maximum transfer size exceeded\n"); - return -EOPNOTSUPP; - } - if (pmsg->flags & I2C_M_RD) { ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf, pmsg->len); @@ -187,6 +181,11 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = { .functionality = dln2_i2c_func, }; +static struct i2c_adapter_quirks dln2_i2c_quirks = { + .max_read_len = DLN2_I2C_MAX_XFER_SIZE, + .max_write_len = DLN2_I2C_MAX_XFER_SIZE, +}; + static int dln2_i2c_probe(struct platform_device *pdev) { int ret; @@ -209,7 +208,9 @@ static int dln2_i2c_probe(struct platform_device *pdev) dln2->adapter.owner = THIS_MODULE; dln2->adapter.class = I2C_CLASS_HWMON; dln2->adapter.algo = &dln2_i2c_usb_algorithm; + dln2->adapter.quirks = &dln2_i2c_quirks; dln2->adapter.dev.parent = dev; + dln2->adapter.dev.of_node = dev->of_node; i2c_set_adapdata(&dln2->adapter, dln2); snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d", "dln2-i2c", dev_name(pdev->dev.parent), dln2->port); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 8fafb254e42a..5ecbb3fdc27e 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -223,8 +223,6 @@ struct i801_priv { #endif }; -static struct pci_driver i801_driver; - #define FEATURE_SMBUS_PEC (1 << 0) #define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_PROC (1 << 2) @@ -1140,7 +1138,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) int err, i; struct i801_priv *priv; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1182,34 +1180,35 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) } priv->features &= ~disable_features; - err = pci_enable_device(dev); + err = pcim_enable_device(dev); if (err) { dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", err); - goto exit; + return err; } + pcim_pin_device(dev); /* Determine the address of the SMBus area */ priv->smba = pci_resource_start(dev, SMBBAR); if (!priv->smba) { - dev_err(&dev->dev, "SMBus base address uninitialized, " - "upgrade BIOS\n"); - err = -ENODEV; - goto exit; + dev_err(&dev->dev, + "SMBus base address uninitialized, upgrade BIOS\n"); + return -ENODEV; } err = acpi_check_resource_conflict(&dev->resource[SMBBAR]); if (err) { - err = -ENODEV; - goto exit; + return -ENODEV; } - err = pci_request_region(dev, SMBBAR, i801_driver.name); + err = pcim_iomap_regions(dev, 1 << SMBBAR, + dev_driver_string(&dev->dev)); if (err) { - dev_err(&dev->dev, "Failed to request SMBus region " - "0x%lx-0x%Lx\n", priv->smba, + dev_err(&dev->dev, + "Failed to request SMBus region 0x%lx-0x%Lx\n", + priv->smba, (unsigned long long)pci_resource_end(dev, SMBBAR)); - goto exit; + return err; } pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp); @@ -1254,8 +1253,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) if (priv->features & FEATURE_IRQ) { init_waitqueue_head(&priv->waitq); - err = request_irq(dev->irq, i801_isr, IRQF_SHARED, - i801_driver.name, priv); + err = devm_request_irq(&dev->dev, dev->irq, i801_isr, + IRQF_SHARED, + dev_driver_string(&dev->dev), priv); if (err) { dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", dev->irq, err); @@ -1276,7 +1276,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) err = i2c_add_adapter(&priv->adapter); if (err) { dev_err(&dev->dev, "Failed to add SMBus adapter\n"); - goto exit_free_irq; + return err; } i801_probe_optional_slaves(priv); @@ -1286,14 +1286,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_set_drvdata(dev, priv); return 0; - -exit_free_irq: - if (priv->features & FEATURE_IRQ) - free_irq(dev->irq, priv); - pci_release_region(dev, SMBBAR); -exit: - kfree(priv); - return err; } static void i801_remove(struct pci_dev *dev) @@ -1304,11 +1296,6 @@ static void i801_remove(struct pci_dev *dev) i2c_del_adapter(&priv->adapter); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); - if (priv->features & FEATURE_IRQ) - free_irq(dev->irq, priv); - pci_release_region(dev, SMBBAR); - - kfree(priv); /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) @@ -1330,7 +1317,7 @@ static int i801_resume(struct pci_dev *dev) { pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); - return pci_enable_device(dev); + return 0; } #else #define i801_suspend NULL diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index 0fcc1694c607..00ffd6613680 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -988,15 +988,16 @@ out: static int img_i2c_reset_bus(struct img_i2c *i2c) { unsigned long flags; - int ret; + unsigned long time_left; spin_lock_irqsave(&i2c->lock, flags); reinit_completion(&i2c->msg_complete); img_i2c_reset_start(i2c); spin_unlock_irqrestore(&i2c->lock, flags); - ret = wait_for_completion_timeout(&i2c->msg_complete, IMG_I2C_TIMEOUT); - if (ret == 0) + time_left = wait_for_completion_timeout(&i2c->msg_complete, + IMG_I2C_TIMEOUT); + if (time_left == 0) return -ETIMEDOUT; return 0; } @@ -1007,6 +1008,7 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, struct img_i2c *i2c = i2c_get_adapdata(adap); bool atomic = false; int i, ret; + unsigned long time_left; if (i2c->mode == MODE_SUSPEND) { WARN(1, "refusing to service transaction in suspended state\n"); @@ -1068,11 +1070,11 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, img_i2c_write(i2c); spin_unlock_irqrestore(&i2c->lock, flags); - ret = wait_for_completion_timeout(&i2c->msg_complete, - IMG_I2C_TIMEOUT); + time_left = wait_for_completion_timeout(&i2c->msg_complete, + IMG_I2C_TIMEOUT); del_timer_sync(&i2c->check_timer); - if (ret == 0) { + if (time_left == 0) { dev_err(adap->dev.parent, "i2c transfer timed out\n"); i2c->msg_status = -ETIMEDOUT; break; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d7b26fc6f432..a53a7dd66945 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -601,6 +601,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) { int result; + unsigned long time_left; unsigned int temp = 0; unsigned long orig_jiffies = jiffies; struct imx_i2c_dma *dma = i2c_imx->dma; @@ -624,10 +625,10 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, */ imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); reinit_completion(&i2c_imx->dma->cmd_complete); - result = wait_for_completion_timeout( + time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); - if (result == 0) { + if (time_left == 0) { dmaengine_terminate_all(dma->chan_using); return -ETIMEDOUT; } @@ -663,6 +664,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { int result; + unsigned long time_left; unsigned int temp; unsigned long orig_jiffies = jiffies; struct imx_i2c_dma *dma = i2c_imx->dma; @@ -682,10 +684,10 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, return result; reinit_completion(&i2c_imx->dma->cmd_complete); - result = wait_for_completion_timeout( + time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); - if (result == 0) { + if (time_left == 0) { dmaengine_terminate_all(dma->chan_using); return -ETIMEDOUT; } diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index f2b0ff011631..f994712d0904 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -380,6 +380,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, int size, union i2c_smbus_data *data) { int ret; + unsigned long time_left; dma_addr_t dma_addr = 0; /* address of the data buffer */ u8 dma_size = 0; enum dma_data_direction dma_direction = 0; @@ -578,13 +579,13 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, ismt_submit_desc(priv); /* Now we wait for interrupt completion, 1s */ - ret = wait_for_completion_timeout(&priv->cmp, HZ*1); + time_left = wait_for_completion_timeout(&priv->cmp, HZ*1); /* unmap the data buffer */ if (dma_size != 0) dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction); - if (unlikely(!ret)) { + if (unlikely(!time_left)) { dev_err(dev, "completion wait timed out\n"); ret = -ETIMEDOUT; goto out; diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c new file mode 100644 index 000000000000..ce1d69324169 --- /dev/null +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -0,0 +1,832 @@ +/* + * Ingenic JZ4780 I2C bus driver + * + * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc. + * Copyright (C) 2015 Imagination Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/time.h> + +#define JZ4780_I2C_CTRL 0x00 +#define JZ4780_I2C_TAR 0x04 +#define JZ4780_I2C_SAR 0x08 +#define JZ4780_I2C_DC 0x10 +#define JZ4780_I2C_SHCNT 0x14 +#define JZ4780_I2C_SLCNT 0x18 +#define JZ4780_I2C_FHCNT 0x1C +#define JZ4780_I2C_FLCNT 0x20 +#define JZ4780_I2C_INTST 0x2C +#define JZ4780_I2C_INTM 0x30 +#define JZ4780_I2C_RXTL 0x38 +#define JZ4780_I2C_TXTL 0x3C +#define JZ4780_I2C_CINTR 0x40 +#define JZ4780_I2C_CRXUF 0x44 +#define JZ4780_I2C_CRXOF 0x48 +#define JZ4780_I2C_CTXOF 0x4C +#define JZ4780_I2C_CRXREQ 0x50 +#define JZ4780_I2C_CTXABRT 0x54 +#define JZ4780_I2C_CRXDONE 0x58 +#define JZ4780_I2C_CACT 0x5C +#define JZ4780_I2C_CSTP 0x60 +#define JZ4780_I2C_CSTT 0x64 +#define JZ4780_I2C_CGC 0x68 +#define JZ4780_I2C_ENB 0x6C +#define JZ4780_I2C_STA 0x70 +#define JZ4780_I2C_TXABRT 0x80 +#define JZ4780_I2C_DMACR 0x88 +#define JZ4780_I2C_DMATDLR 0x8C +#define JZ4780_I2C_DMARDLR 0x90 +#define JZ4780_I2C_SDASU 0x94 +#define JZ4780_I2C_ACKGC 0x98 +#define JZ4780_I2C_ENSTA 0x9C +#define JZ4780_I2C_SDAHD 0xD0 + +#define JZ4780_I2C_CTRL_STPHLD BIT(7) +#define JZ4780_I2C_CTRL_SLVDIS BIT(6) +#define JZ4780_I2C_CTRL_REST BIT(5) +#define JZ4780_I2C_CTRL_MATP BIT(4) +#define JZ4780_I2C_CTRL_SATP BIT(3) +#define JZ4780_I2C_CTRL_SPDF BIT(2) +#define JZ4780_I2C_CTRL_SPDS BIT(1) +#define JZ4780_I2C_CTRL_MD BIT(0) + +#define JZ4780_I2C_STA_SLVACT BIT(6) +#define JZ4780_I2C_STA_MSTACT BIT(5) +#define JZ4780_I2C_STA_RFF BIT(4) +#define JZ4780_I2C_STA_RFNE BIT(3) +#define JZ4780_I2C_STA_TFE BIT(2) +#define JZ4780_I2C_STA_TFNF BIT(1) +#define JZ4780_I2C_STA_ACT BIT(0) + +static const char * const jz4780_i2c_abrt_src[] = { + "ABRT_7B_ADDR_NOACK", + "ABRT_10ADDR1_NOACK", + "ABRT_10ADDR2_NOACK", + "ABRT_XDATA_NOACK", + "ABRT_GCALL_NOACK", + "ABRT_GCALL_READ", + "ABRT_HS_ACKD", + "SBYTE_ACKDET", + "ABRT_HS_NORSTRT", + "SBYTE_NORSTRT", + "ABRT_10B_RD_NORSTRT", + "ABRT_MASTER_DIS", + "ARB_LOST", + "SLVFLUSH_TXFIFO", + "SLV_ARBLOST", + "SLVRD_INTX", +}; + +#define JZ4780_I2C_INTST_IGC BIT(11) +#define JZ4780_I2C_INTST_ISTT BIT(10) +#define JZ4780_I2C_INTST_ISTP BIT(9) +#define JZ4780_I2C_INTST_IACT BIT(8) +#define JZ4780_I2C_INTST_RXDN BIT(7) +#define JZ4780_I2C_INTST_TXABT BIT(6) +#define JZ4780_I2C_INTST_RDREQ BIT(5) +#define JZ4780_I2C_INTST_TXEMP BIT(4) +#define JZ4780_I2C_INTST_TXOF BIT(3) +#define JZ4780_I2C_INTST_RXFL BIT(2) +#define JZ4780_I2C_INTST_RXOF BIT(1) +#define JZ4780_I2C_INTST_RXUF BIT(0) + +#define JZ4780_I2C_INTM_MIGC BIT(11) +#define JZ4780_I2C_INTM_MISTT BIT(10) +#define JZ4780_I2C_INTM_MISTP BIT(9) +#define JZ4780_I2C_INTM_MIACT BIT(8) +#define JZ4780_I2C_INTM_MRXDN BIT(7) +#define JZ4780_I2C_INTM_MTXABT BIT(6) +#define JZ4780_I2C_INTM_MRDREQ BIT(5) +#define JZ4780_I2C_INTM_MTXEMP BIT(4) +#define JZ4780_I2C_INTM_MTXOF BIT(3) +#define JZ4780_I2C_INTM_MRXFL BIT(2) +#define JZ4780_I2C_INTM_MRXOF BIT(1) +#define JZ4780_I2C_INTM_MRXUF BIT(0) + +#define JZ4780_I2C_DC_READ BIT(8) + +#define JZ4780_I2C_SDAHD_HDENB BIT(8) + +#define JZ4780_I2C_ENB_I2C BIT(0) + +#define JZ4780_I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) +#define JZ4780_I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) +#define JZ4780_I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) +#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) + +#define JZ4780_I2C_FIFO_LEN 16 +#define TX_LEVEL 3 +#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1) + +#define JZ4780_I2C_TIMEOUT 300 + +#define BUFSIZE 200 + +struct jz4780_i2c { + void __iomem *iomem; + int irq; + struct clk *clk; + struct i2c_adapter adap; + + /* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */ + spinlock_t lock; + + /* beginning of lock scope */ + unsigned char *rbuf; + int rd_total_len; + int rd_data_xfered; + int rd_cmd_xfered; + + unsigned char *wbuf; + int wt_len; + + int is_write; + int stop_hold; + int speed; + + int data_buf[BUFSIZE]; + int cmd_buf[BUFSIZE]; + int cmd; + + /* end of lock scope */ + struct completion trans_waitq; +}; + +static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c, + unsigned long offset) +{ + return readw(i2c->iomem + offset); +} + +static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c, + unsigned long offset, unsigned short val) +{ + writew(val, i2c->iomem + offset); +} + +static int jz4780_i2c_disable(struct jz4780_i2c *i2c) +{ + unsigned short regval; + unsigned long loops = 5; + + jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0); + + do { + regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA); + if (!(regval & JZ4780_I2C_ENB_I2C)) + return 0; + + usleep_range(5000, 15000); + } while (--loops); + + dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval); + return -ETIMEDOUT; +} + +static int jz4780_i2c_enable(struct jz4780_i2c *i2c) +{ + unsigned short regval; + unsigned long loops = 5; + + jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1); + + do { + regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA); + if (regval & JZ4780_I2C_ENB_I2C) + return 0; + + usleep_range(5000, 15000); + } while (--loops); + + dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval); + return -ETIMEDOUT; +} + +static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address) +{ + unsigned short regval; + unsigned long loops = 5; + + do { + regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + if ((regval & JZ4780_I2C_STA_TFE) && + !(regval & JZ4780_I2C_STA_MSTACT)) + break; + + usleep_range(5000, 15000); + } while (--loops); + + if (loops) { + jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address); + return 0; + } + + dev_err(&i2c->adap.dev, + "set device to address 0x%02x failed, STA=0x%04x\n", + address, regval); + + return -ENXIO; +} + +static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c) +{ + int dev_clk_khz = clk_get_rate(i2c->clk) / 1000; + int cnt_high = 0; /* HIGH period count of the SCL clock */ + int cnt_low = 0; /* LOW period count of the SCL clock */ + int cnt_period = 0; /* period count of the SCL clock */ + int setup_time = 0; + int hold_time = 0; + unsigned short tmp = 0; + int i2c_clk = i2c->speed; + + if (jz4780_i2c_disable(i2c)) + dev_dbg(&i2c->adap.dev, "i2c not disabled\n"); + + /* + * 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk) + * standard mode, min LOW and HIGH period are 4700 ns and 4000 ns + * fast mode, min LOW and HIGH period are 1300 ns and 600 ns + */ + cnt_period = dev_clk_khz / i2c_clk; + + if (i2c_clk <= 100) + cnt_high = (cnt_period * 4000) / (4700 + 4000); + else + cnt_high = (cnt_period * 600) / (1300 + 600); + + cnt_low = cnt_period - cnt_high; + + /* + * NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because + * normal read are 2 messages, we cannot disable i2c controller + * between these two messages, this means that we must always set + * JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL + * + */ + if (i2c_clk <= 100) { + tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST + | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT, + JZ4780_I2CSHCNT_ADJUST(cnt_high)); + jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT, + JZ4780_I2CSLCNT_ADJUST(cnt_low)); + } else { + tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST + | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT, + JZ4780_I2CFHCNT_ADJUST(cnt_high)); + jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT, + JZ4780_I2CFLCNT_ADJUST(cnt_low)); + } + + /* + * a i2c device must internally provide a hold time at least 300ns + * tHD:DAT + * Standard Mode: min=300ns, max=3450ns + * Fast Mode: min=0ns, max=900ns + * tSU:DAT + * Standard Mode: min=250ns, max=infinite + * Fast Mode: min=100(250ns is recommended), max=infinite + * + * 1i2c_clk = 10^6 / dev_clk_khz + * on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns + * on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns + * + * The actual hold time is (SDAHD + 1) * (i2c_clk period). + * + * Length of setup time calculated using (SDASU - 1) * (ic_clk_period) + * + */ + if (i2c_clk <= 100) { /* standard mode */ + setup_time = 300; + hold_time = 400; + } else { + setup_time = 450; + hold_time = 450; + } + + hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1; + setup_time = ((setup_time * dev_clk_khz) / 1000000) + 1; + + if (setup_time > 255) + setup_time = 255; + + if (setup_time <= 0) + setup_time = 1; + + jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time); + + if (hold_time > 255) + hold_time = 255; + + if (hold_time >= 0) { + /*i2c hold time enable */ + hold_time |= JZ4780_I2C_SDAHD_HDENB; + jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time); + } else { + /* disable hold time */ + jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0); + } + + return 0; +} + +static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c) +{ + int ret; + unsigned long flags; + unsigned short tmp; + + spin_lock_irqsave(&i2c->lock, flags); + + /* can send stop now if need */ + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + /* disable all interrupts first */ + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0); + + /* then clear all interrupts */ + jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT); + jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR); + + /* then disable the controller */ + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_ENB_I2C; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + udelay(10); + tmp |= JZ4780_I2C_ENB_I2C; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + spin_unlock_irqrestore(&i2c->lock, flags); + + ret = jz4780_i2c_disable(i2c); + if (ret) + dev_err(&i2c->adap.dev, + "unable to disable device during cleanup!\n"); + + if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM) + & jz4780_i2c_readw(i2c, JZ4780_I2C_INTST))) + dev_err(&i2c->adap.dev, + "device has interrupts after a complete cleanup!\n"); + + return ret; +} + +static int jz4780_i2c_prepare(struct jz4780_i2c *i2c) +{ + jz4780_i2c_set_speed(i2c); + return jz4780_i2c_enable(i2c); +} + +static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count) +{ + int i; + + for (i = 0; i < cmd_count; i++) + jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ); +} + +static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c) +{ + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0); + complete(&i2c->trans_waitq); +} + +static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id) +{ + unsigned short tmp; + unsigned short intst; + unsigned short intmsk; + struct jz4780_i2c *i2c = dev_id; + unsigned long flags; + + spin_lock_irqsave(&i2c->lock, flags); + intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); + intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST); + + intst &= intmsk; + + if (intst & JZ4780_I2C_INTST_TXABT) { + jz4780_i2c_trans_done(i2c); + goto done; + } + + if (intst & JZ4780_I2C_INTST_RXOF) { + dev_dbg(&i2c->adap.dev, "received fifo overflow!\n"); + jz4780_i2c_trans_done(i2c); + goto done; + } + + /* + * When reading, always drain RX FIFO before we send more Read + * Commands to avoid fifo overrun + */ + if (i2c->is_write == 0) { + int rd_left; + + while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA) + & JZ4780_I2C_STA_RFNE)) { + *(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC) + & 0xff; + i2c->rd_data_xfered++; + if (i2c->rd_data_xfered == i2c->rd_total_len) { + jz4780_i2c_trans_done(i2c); + goto done; + } + } + + rd_left = i2c->rd_total_len - i2c->rd_data_xfered; + + if (rd_left <= JZ4780_I2C_FIFO_LEN) + jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1); + } + + if (intst & JZ4780_I2C_INTST_TXEMP) { + if (i2c->is_write == 0) { + int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered; + int max_send = (JZ4780_I2C_FIFO_LEN - 1) + - (i2c->rd_cmd_xfered + - i2c->rd_data_xfered); + int cmd_to_send = min(cmd_left, max_send); + + if (i2c->rd_cmd_xfered != 0) + cmd_to_send = min(cmd_to_send, + JZ4780_I2C_FIFO_LEN + - TX_LEVEL - 1); + + if (cmd_to_send) { + jz4780_i2c_send_rcmd(i2c, cmd_to_send); + i2c->rd_cmd_xfered += cmd_to_send; + } + + cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered; + if (cmd_left == 0) { + intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); + intmsk &= ~JZ4780_I2C_INTM_MTXEMP; + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + } + } else { + unsigned short data; + unsigned short i2c_sta; + + i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + + while ((i2c_sta & JZ4780_I2C_STA_TFNF) && + (i2c->wt_len > 0)) { + i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + data = *i2c->wbuf; + data &= ~JZ4780_I2C_DC_READ; + jz4780_i2c_writew(i2c, JZ4780_I2C_DC, + data); + i2c->wbuf++; + i2c->wt_len--; + } + + if (i2c->wt_len == 0) { + if (!i2c->stop_hold) { + tmp = jz4780_i2c_readw(i2c, + JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, + tmp); + } + + jz4780_i2c_trans_done(i2c); + goto done; + } + } + } + +done: + spin_unlock_irqrestore(&i2c->lock, flags); + return IRQ_HANDLED; +} + +static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src) +{ + int i; + + dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src); + dev_err(&i2c->adap.dev, "device addr=%x\n", + jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)); + dev_err(&i2c->adap.dev, "send cmd count:%d %d\n", + i2c->cmd, i2c->cmd_buf[i2c->cmd]); + dev_err(&i2c->adap.dev, "receive data count:%d %d\n", + i2c->cmd, i2c->data_buf[i2c->cmd]); + + for (i = 0; i < 16; i++) { + if (src & BIT(i)) + dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n", + i, jz4780_i2c_abrt_src[i]); + } +} + +static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, + unsigned char *buf, int len, int cnt, + int idx) +{ + int ret = 0; + long timeout; + int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); + unsigned short tmp; + unsigned long flags; + + memset(buf, 0, len); + + spin_lock_irqsave(&i2c->lock, flags); + + i2c->stop_hold = 0; + i2c->is_write = 0; + i2c->rbuf = buf; + i2c->rd_total_len = len; + i2c->rd_data_xfered = 0; + i2c->rd_cmd_xfered = 0; + + if (len <= JZ4780_I2C_FIFO_LEN) + jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1); + else + jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL); + + jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL); + + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, + JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP + | JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp |= JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); + + if (!timeout) { + dev_err(&i2c->adap.dev, "irq read timeout\n"); + dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n", + i2c->cmd, i2c->cmd_buf[i2c->cmd]); + dev_dbg(&i2c->adap.dev, "receive data count:%d %d\n", + i2c->cmd, i2c->data_buf[i2c->cmd]); + ret = -EIO; + } + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT); + if (tmp) { + jz4780_i2c_txabrt(i2c, tmp); + ret = -EIO; + } + + return ret; +} + +static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, + unsigned char *buf, int len, + int cnt, int idx) +{ + int ret = 0; + int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); + long timeout; + unsigned short tmp; + unsigned long flags; + + spin_lock_irqsave(&i2c->lock, flags); + + if (idx < (cnt - 1)) + i2c->stop_hold = 1; + else + i2c->stop_hold = 0; + + i2c->is_write = 1; + i2c->wbuf = buf; + i2c->wt_len = len; + + jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL); + + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP + | JZ4780_I2C_INTM_MTXABT); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp |= JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + spin_unlock_irqrestore(&i2c->lock, flags); + + timeout = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); + if (timeout && !i2c->stop_hold) { + unsigned short i2c_sta; + int write_in_process; + + timeout = JZ4780_I2C_TIMEOUT * 100; + for (; timeout > 0; timeout--) { + i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); + + write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) || + !(i2c_sta & JZ4780_I2C_STA_TFE); + if (!write_in_process) + break; + udelay(10); + } + } + + if (!timeout) { + dev_err(&i2c->adap.dev, "write wait timeout\n"); + ret = -EIO; + } + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT); + if (tmp) { + jz4780_i2c_txabrt(i2c, tmp); + ret = -EIO; + } + + return ret; +} + +static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int count) +{ + int i = -EIO; + int ret = 0; + struct jz4780_i2c *i2c = adap->algo_data; + + ret = jz4780_i2c_prepare(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "I2C prepare failed\n"); + goto out; + } + + if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) { + ret = jz4780_i2c_set_target(i2c, msg->addr); + if (ret) + goto out; + } + for (i = 0; i < count; i++, msg++) { + if (msg->flags & I2C_M_RD) + ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len, + count, i); + else + ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len, + count, i); + + if (ret) + goto out; + } + + ret = i; + +out: + jz4780_i2c_cleanup(i2c); + return ret; +} + +static u32 jz4780_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm jz4780_i2c_algorithm = { + .master_xfer = jz4780_i2c_xfer, + .functionality = jz4780_i2c_functionality, +}; + +static const struct of_device_id jz4780_i2c_of_matches[] = { + { .compatible = "ingenic,jz4780-i2c", }, + { /* sentinel */ } +}; + +static int jz4780_i2c_probe(struct platform_device *pdev) +{ + int ret = 0; + unsigned int clk_freq = 0; + unsigned short tmp; + struct resource *r; + struct jz4780_i2c *i2c; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &jz4780_i2c_algorithm; + i2c->adap.algo_data = i2c; + i2c->adap.retries = 5; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + sprintf(i2c->adap.name, "%s", pdev->name); + + init_completion(&i2c->trans_waitq); + spin_lock_init(&i2c->lock); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->iomem = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(i2c->iomem)) + return PTR_ERR(i2c->iomem); + + platform_set_drvdata(pdev, i2c); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) + return PTR_ERR(i2c->clk); + + clk_prepare_enable(i2c->clk); + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &clk_freq)) { + dev_err(&pdev->dev, "clock-frequency not specified in DT"); + return clk_freq; + } + + i2c->speed = clk_freq / 1000; + jz4780_i2c_set_speed(i2c); + + dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed); + + tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); + tmp &= ~JZ4780_I2C_CTRL_STPHLD; + jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); + + jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0); + + i2c->cmd = 0; + memset(i2c->cmd_buf, 0, BUFSIZE); + memset(i2c->data_buf, 0, BUFSIZE); + + i2c->irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, + dev_name(&pdev->dev), i2c); + if (ret) { + ret = -ENODEV; + goto err; + } + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to add bus\n"); + goto err; + } + + return 0; + +err: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int jz4780_i2c_remove(struct platform_device *pdev) +{ + struct jz4780_i2c *i2c = platform_get_drvdata(pdev); + + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adap); + return 0; +} + +static struct platform_driver jz4780_i2c_driver = { + .probe = jz4780_i2c_probe, + .remove = jz4780_i2c_remove, + .driver = { + .name = "jz4780-i2c", + .of_match_table = of_match_ptr(jz4780_i2c_of_matches), + }, +}; + +module_platform_driver(jz4780_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("ztyan<ztyan@ingenic.cn>"); +MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs"); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index c74cc2be613b..48ecffecc0ed 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -29,6 +29,7 @@ #include <linux/delay.h> #include <asm/mpc52xx.h> +#include <asm/mpc85xx.h> #include <sysdev/fsl_soc.h> #define DRV_NAME "mpc-i2c" @@ -95,8 +96,9 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id) i2c->interrupt = readb(i2c->base + MPC_I2C_SR); writeb(0, i2c->base + MPC_I2C_SR); wake_up(&i2c->queue); + return IRQ_HANDLED; } - return IRQ_HANDLED; + return IRQ_NONE; } /* Sometimes 9th clock pulse isn't generated, and slave doesn't release @@ -346,6 +348,33 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) return val; } +static u32 mpc_i2c_get_prescaler_8xxx(void) +{ + /* mpc83xx and mpc82xx all have prescaler 1 */ + u32 prescaler = 1; + + /* mpc85xx */ + if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2) + || pvr_version_is(PVR_VER_E500MC) + || pvr_version_is(PVR_VER_E5500) + || pvr_version_is(PVR_VER_E6500)) { + unsigned int svr = mfspr(SPRN_SVR); + + if ((SVR_SOC_VER(svr) == SVR_8540) + || (SVR_SOC_VER(svr) == SVR_8541) + || (SVR_SOC_VER(svr) == SVR_8560) + || (SVR_SOC_VER(svr) == SVR_8555) + || (SVR_SOC_VER(svr) == SVR_8610)) + /* the above 85xx SoCs have prescaler 1 */ + prescaler = 1; + else + /* all the other 85xx have prescaler 2 */ + prescaler = 2; + } + + return prescaler; +} + static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler, u32 *real_clk) { @@ -363,7 +392,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, if (of_device_is_compatible(node, "fsl,mpc8544-i2c")) prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; if (!prescaler) - prescaler = 1; + prescaler = mpc_i2c_get_prescaler_8xxx(); divider = fsl_get_sys_freq() / clock / prescaler; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index ff8b12c8d25f..56fceff6ba14 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -568,6 +568,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int ret; int flags; int use_pio = 0; + unsigned long time_left; flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; @@ -599,9 +600,9 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, if (ret) return ret; - ret = wait_for_completion_timeout(&i2c->cmd_complete, + time_left = wait_for_completion_timeout(&i2c->cmd_complete, msecs_to_jiffies(1000)); - if (ret == 0) + if (!time_left) goto timeout; ret = i2c->cmd_err; diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 97998946c4f6..bcd17e8cbcb4 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -446,9 +446,9 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) */ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) { - u32 status = 0; + int status = 0; u32 mcr, irq_mask; - int timeout; + unsigned long timeout; mcr = load_i2c_mcr_reg(dev, flags); writel(mcr, dev->virtbase + I2C_MCR); @@ -517,7 +517,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; u32 mcr, irq_mask; - int timeout; + unsigned long timeout; mcr = load_i2c_mcr_reg(dev, flags); diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index 16f90b1a7508..75dd6d041241 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -104,18 +104,8 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf)); break; case 2: - /* For two messages, we basically support only simple - * smbus transactions of a write plus a read. We might - * want to allow also two writes but we'd have to bounce - * the data into a single buffer. - */ - if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) - return -EOPNOTSUPP; - if (msgs[0].len > 4) - return -EOPNOTSUPP; - if (msgs[0].addr != msgs[1].addr) - return -EOPNOTSUPP; - req.type = OPAL_I2C_SM_READ; + req.type = (msgs[1].flags & I2C_M_RD) ? + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; req.addr = cpu_to_be16(msgs[0].addr); req.subaddr_sz = msgs[0].len; for (i = 0; i < msgs[0].len; i++) @@ -210,6 +200,15 @@ static const struct i2c_algorithm i2c_opal_algo = { .functionality = i2c_opal_func, }; +/* + * For two messages, we basically support simple smbus transactions of a + * write-then-anything. + */ +static struct i2c_adapter_quirks i2c_opal_quirks = { + .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR, + .max_comb_1st_msg_len = 4, +}; + static int i2c_opal_probe(struct platform_device *pdev) { struct i2c_adapter *adapter; @@ -232,6 +231,7 @@ static int i2c_opal_probe(struct platform_device *pdev) adapter->algo = &i2c_opal_algo; adapter->algo_data = (void *)(unsigned long)opal_id; + adapter->quirks = &i2c_opal_quirks; adapter->dev.parent = &pdev->dev; adapter->dev.of_node = of_node_get(pdev->dev.of_node); pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL); diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index d37d9db6681e..2c40edbf6224 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -456,14 +456,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd( return -EINVAL; } - if (cmd->read_len > MSP_MAX_BYTES_PER_RW || - cmd->write_len > MSP_MAX_BYTES_PER_RW) { - dev_err(&pmcmsptwi_adapter.dev, - "%s: Cannot transfer more than %d bytes\n", - __func__, MSP_MAX_BYTES_PER_RW); - return -EINVAL; - } - mutex_lock(&data->lock); dev_dbg(&pmcmsptwi_adapter.dev, "Setting address to 0x%04x\n", cmd->addr); @@ -520,25 +512,14 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, struct pmcmsptwi_cfg oldcfg, newcfg; int ret; - if (num > 2) { - dev_dbg(&adap->dev, "%d messages unsupported\n", num); - return -EINVAL; - } else if (num == 2) { - /* Check for a dual write-then-read command */ + if (num == 2) { struct i2c_msg *nextmsg = msg + 1; - if (!(msg->flags & I2C_M_RD) && - (nextmsg->flags & I2C_M_RD) && - msg->addr == nextmsg->addr) { - cmd.type = MSP_TWI_CMD_WRITE_READ; - cmd.write_len = msg->len; - cmd.write_data = msg->buf; - cmd.read_len = nextmsg->len; - cmd.read_data = nextmsg->buf; - } else { - dev_dbg(&adap->dev, - "Non write-read dual messages unsupported\n"); - return -EINVAL; - } + + cmd.type = MSP_TWI_CMD_WRITE_READ; + cmd.write_len = msg->len; + cmd.write_data = msg->buf; + cmd.read_len = nextmsg->len; + cmd.read_data = nextmsg->buf; } else if (msg->flags & I2C_M_RD) { cmd.type = MSP_TWI_CMD_READ; cmd.read_len = msg->len; @@ -598,6 +579,14 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL; } +static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_write_len = MSP_MAX_BYTES_PER_RW, + .max_read_len = MSP_MAX_BYTES_PER_RW, + .max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW, + .max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW, +}; + /* -- Initialization -- */ static struct i2c_algorithm pmcmsptwi_algo = { @@ -609,6 +598,7 @@ static struct i2c_adapter pmcmsptwi_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .algo = &pmcmsptwi_algo, + .quirks = &pmcmsptwi_i2c_quirks, .name = DRV_NAME, }; diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 60a53c169ed2..6abcf696e359 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -153,12 +153,6 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap, int read; int addrdir; - if (num != 1) { - dev_err(&adap->dev, - "Multi-message I2C transactions not supported\n"); - return -EOPNOTSUPP; - } - if (msgs->flags & I2C_M_TEN) return -EINVAL; read = (msgs->flags & I2C_M_RD) != 0; @@ -205,6 +199,9 @@ static const struct i2c_algorithm i2c_powermac_algorithm = { .functionality = i2c_powermac_func, }; +static struct i2c_adapter_quirks i2c_powermac_quirks = { + .max_num_msgs = 1, +}; static int i2c_powermac_remove(struct platform_device *dev) { @@ -434,6 +431,7 @@ static int i2c_powermac_probe(struct platform_device *dev) platform_set_drvdata(dev, adapter); adapter->algo = &i2c_powermac_algorithm; + adapter->quirks = &i2c_powermac_quirks; i2c_set_adapdata(adapter, bus); adapter->dev.parent = &dev->dev; diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 4dad23bdffbe..fdcbdab808e9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -412,17 +412,6 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg) unsigned long left; int ret; - /* - * The QUP block will issue a NACK and STOP on the bus when reaching - * the end of the read, the length of the read is specified as one byte - * which limits the possible read to 256 (QUP_READ_LIMIT) bytes. - */ - if (msg->len > QUP_READ_LIMIT) { - dev_err(qup->dev, "HW not capable of reads over %d bytes\n", - QUP_READ_LIMIT); - return -EINVAL; - } - qup->msg = msg; qup->pos = 0; @@ -534,6 +523,15 @@ static const struct i2c_algorithm qup_i2c_algo = { .functionality = qup_i2c_func, }; +/* + * The QUP block will issue a NACK and STOP on the bus when reaching + * the end of the read, the length of the read is specified as one byte + * which limits the possible read to 256 (QUP_READ_LIMIT) bytes. + */ +static struct i2c_adapter_quirks qup_i2c_quirks = { + .max_read_len = QUP_READ_LIMIT, +}; + static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup) { clk_prepare_enable(qup->clk); @@ -670,6 +668,7 @@ static int qup_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&qup->adap, qup); qup->adap.algo = &qup_i2c_algo; + qup->adap.quirks = &qup_i2c_quirks; qup->adap.dev.parent = qup->dev; qup->adap.dev.of_node = pdev->dev.of_node; strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name)); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 71a6e07eb7ab..5a84bea5b845 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -382,11 +382,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) if (ssr_filtered & SAR) { /* read or write request */ if (ssr_raw & STM) { - i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value); + i2c_slave_event(priv->slave, I2C_SLAVE_READ_REQUESTED, &value); rcar_i2c_write(priv, ICRXTX, value); rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR); } else { - i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value); + i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); rcar_i2c_read(priv, ICRXTX); /* dummy read */ rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR); } @@ -406,17 +406,15 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) int ret; value = rcar_i2c_read(priv, ICRXTX); - ret = i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_END, &value); + ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value); /* Send NACK in case of error */ rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0)); - i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value); rcar_i2c_write(priv, ICSSR, ~SDR & 0xff); } /* master wants to read from us */ if (ssr_filtered & SDE) { - i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_END, &value); - i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value); + i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value); rcar_i2c_write(priv, ICRXTX, value); rcar_i2c_write(priv, ICSSR, ~SDE & 0xff); } diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 29f14331dd9d..1bcd75ea0b4c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -532,7 +532,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, { u32 packet_header; u32 int_mask; - int ret; + unsigned long time_left; tegra_i2c_flush_fifos(i2c_dev); @@ -585,18 +585,20 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n", i2c_readl(i2c_dev, I2C_INT_MASK)); - ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT); + time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, + TEGRA_I2C_TIMEOUT); tegra_i2c_mask_irq(i2c_dev, int_mask); - if (ret == 0) { + if (time_left == 0) { dev_err(i2c_dev->dev, "i2c transfer timed out\n"); tegra_i2c_init(i2c_dev); return -ETIMEDOUT; } - dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n", - ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err); + dev_dbg(i2c_dev->dev, "transfer complete: %lu %d %d\n", + time_left, completion_done(&i2c_dev->msg_complete), + i2c_dev->msg_err); if (likely(i2c_dev->msg_err == I2C_ERR_NONE)) return 0; diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 7533fa34d737..47e88adf2011 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -288,10 +288,6 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, i, pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->flags, pmsg->len, pmsg->addr); - /* msgs longer than 2048 bytes are not supported by adapter */ - if (pmsg->len > 2048) - return -EINVAL; - mutex_lock(&vb->lock); /* directly send the message */ if (pmsg->flags & I2C_M_RD) { @@ -358,6 +354,11 @@ static const struct i2c_algorithm vprbrd_algorithm = { .functionality = vprbrd_i2c_func, }; +static struct i2c_adapter_quirks vprbrd_quirks = { + .max_read_len = 2048, + .max_write_len = 2048, +}; + static int vprbrd_i2c_probe(struct platform_device *pdev) { struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent); @@ -373,6 +374,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev) vb_i2c->i2c.owner = THIS_MODULE; vb_i2c->i2c.class = I2C_CLASS_HWMON; vb_i2c->i2c.algo = &vprbrd_algorithm; + vb_i2c->i2c.quirks = &vprbrd_quirks; vb_i2c->i2c.algo_data = vb; /* save the param in usb capabable memory */ vb_i2c->bus_freq_param = i2c_bus_param; diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 82ea34925489..e1e3a85596c5 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -128,7 +128,8 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, { struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u16 val, tcr_val; - int ret, wait_result; + int ret; + unsigned long wait_result; int xfer_len = 0; if (!(pmsg->flags & I2C_M_NOSTART)) { @@ -177,7 +178,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, while (xfer_len < pmsg->len) { wait_result = wait_for_completion_timeout(&i2c_dev->complete, - 500 * HZ / 1000); + msecs_to_jiffies(500)); if (wait_result == 0) return -ETIMEDOUT; @@ -218,7 +219,8 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, { struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u16 val, tcr_val; - int ret, wait_result; + int ret; + unsigned long wait_result; u32 xfer_len = 0; if (!(pmsg->flags & I2C_M_NOSTART)) { @@ -266,7 +268,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, while (xfer_len < pmsg->len) { wait_result = wait_for_completion_timeout(&i2c_dev->complete, - 500 * HZ / 1000); + msecs_to_jiffies(500)); if (!wait_result) return -ETIMEDOUT; diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c new file mode 100644 index 000000000000..c941418f06f5 --- /dev/null +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2003-2015 Broadcom Corporation + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/completion.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define XLP9XX_I2C_DIV 0x0 +#define XLP9XX_I2C_CTRL 0x1 +#define XLP9XX_I2C_CMD 0x2 +#define XLP9XX_I2C_STATUS 0x3 +#define XLP9XX_I2C_MTXFIFO 0x4 +#define XLP9XX_I2C_MRXFIFO 0x5 +#define XLP9XX_I2C_MFIFOCTRL 0x6 +#define XLP9XX_I2C_STXFIFO 0x7 +#define XLP9XX_I2C_SRXFIFO 0x8 +#define XLP9XX_I2C_SFIFOCTRL 0x9 +#define XLP9XX_I2C_SLAVEADDR 0xA +#define XLP9XX_I2C_OWNADDR 0xB +#define XLP9XX_I2C_FIFOWCNT 0xC +#define XLP9XX_I2C_INTEN 0xD +#define XLP9XX_I2C_INTST 0xE +#define XLP9XX_I2C_WAITCNT 0xF +#define XLP9XX_I2C_TIMEOUT 0X10 +#define XLP9XX_I2C_GENCALLADDR 0x11 + +#define XLP9XX_I2C_CMD_START BIT(7) +#define XLP9XX_I2C_CMD_STOP BIT(6) +#define XLP9XX_I2C_CMD_READ BIT(5) +#define XLP9XX_I2C_CMD_WRITE BIT(4) +#define XLP9XX_I2C_CMD_ACK BIT(3) + +#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16 +#define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000 +#define XLP9XX_I2C_CTRL_RST BIT(8) +#define XLP9XX_I2C_CTRL_EN BIT(6) +#define XLP9XX_I2C_CTRL_MASTER BIT(4) +#define XLP9XX_I2C_CTRL_FIFORD BIT(1) +#define XLP9XX_I2C_CTRL_ADDMODE BIT(0) + +#define XLP9XX_I2C_INTEN_NACKADDR BIT(25) +#define XLP9XX_I2C_INTEN_SADDR BIT(13) +#define XLP9XX_I2C_INTEN_DATADONE BIT(12) +#define XLP9XX_I2C_INTEN_ARLOST BIT(11) +#define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4) +#define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3) +#define XLP9XX_I2C_INTEN_MFIFOHI BIT(2) +#define XLP9XX_I2C_INTEN_BUSERR BIT(0) + +#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8 +#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0 +#define XLP9XX_I2C_MFIFOCTRL_RST BIT(16) + +#define XLP9XX_I2C_SLAVEADDR_RW BIT(0) +#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1 + +#define XLP9XX_I2C_IP_CLK_FREQ 133000000UL +#define XLP9XX_I2C_DEFAULT_FREQ 100000 +#define XLP9XX_I2C_HIGH_FREQ 400000 +#define XLP9XX_I2C_FIFO_SIZE 0x80U +#define XLP9XX_I2C_TIMEOUT_MS 1000 + +#define XLP9XX_I2C_FIFO_WCNT_MASK 0xff +#define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \ + XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR) + +struct xlp9xx_i2c_dev { + struct device *dev; + struct i2c_adapter adapter; + struct completion msg_complete; + int irq; + bool msg_read; + u32 __iomem *base; + u32 msg_buf_remaining; + u32 msg_len; + u32 clk_hz; + u32 msg_err; + u8 *msg_buf; +}; + +static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv, + unsigned long reg, u32 val) +{ + writel(val, priv->base + reg); +} + +static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv, + unsigned long reg) +{ + return readl(priv->base + reg); +} + +static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) +{ + u32 inten; + + inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); +} + +static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask) +{ + u32 inten; + + inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten); +} + +static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv) +{ + u32 thres; + + thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, + thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT); +} + +static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) +{ + u32 len, i; + u8 *buf = priv->msg_buf; + + len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE); + for (i = 0; i < len; i++) + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]); + priv->msg_buf_remaining -= len; + priv->msg_buf += len; +} + +static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) +{ + u32 len, i; + u8 *buf = priv->msg_buf; + + len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & + XLP9XX_I2C_FIFO_WCNT_MASK; + len = min(priv->msg_buf_remaining, len); + for (i = 0; i < len; i++, buf++) + *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + + priv->msg_buf_remaining -= len; + priv->msg_buf = buf; + + if (priv->msg_buf_remaining) + xlp9xx_i2c_update_rx_fifo_thres(priv); +} + +static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id) +{ + struct xlp9xx_i2c_dev *priv = dev_id; + u32 status; + + status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST); + if (status == 0) + return IRQ_NONE; + + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status); + if (status & XLP9XX_I2C_STATUS_ERRMASK) { + priv->msg_err = status; + goto xfer_done; + } + + /* SADDR ACK for SMBUS_QUICK */ + if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0)) + goto xfer_done; + + if (!priv->msg_read) { + if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) { + /* TX FIFO got empty, fill it up again */ + if (priv->msg_buf_remaining) + xlp9xx_i2c_fill_tx_fifo(priv); + else + xlp9xx_i2c_mask_irq(priv, + XLP9XX_I2C_INTEN_MFIFOEMTY); + } + } else { + if (status & (XLP9XX_I2C_INTEN_DATADONE | + XLP9XX_I2C_INTEN_MFIFOHI)) { + /* data is in FIFO, read it */ + if (priv->msg_buf_remaining) + xlp9xx_i2c_drain_rx_fifo(priv); + } + } + + /* Transfer complete */ + if (status & XLP9XX_I2C_INTEN_DATADONE) + goto xfer_done; + + return IRQ_HANDLED; + +xfer_done: + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); + complete(&priv->msg_complete); + return IRQ_HANDLED; +} + +static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) +{ + u32 prescale; + + /* + * The controller uses 5 * SCL clock internally. + * So prescale value should be divided by 5. + */ + prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz); + prescale = ((prescale - 8) / 5) - 1; + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | + XLP9XX_I2C_CTRL_MASTER); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); + + return 0; +} + +static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, + int last_msg) +{ + unsigned long timeleft; + u32 intr_mask, cmd, val; + + priv->msg_buf = msg->buf; + priv->msg_buf_remaining = priv->msg_len = msg->len; + priv->msg_err = 0; + priv->msg_read = (msg->flags & I2C_M_RD); + reinit_completion(&priv->msg_complete); + + /* Reset FIFO */ + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, + XLP9XX_I2C_MFIFOCTRL_RST); + + /* set FIFO threshold if reading */ + if (priv->msg_read) + xlp9xx_i2c_update_rx_fifo_thres(priv); + + /* set slave addr */ + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, + (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | + (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0)); + + /* Build control word for transfer */ + val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); + if (!priv->msg_read) + val &= ~XLP9XX_I2C_CTRL_FIFORD; + else + val |= XLP9XX_I2C_CTRL_FIFORD; /* read */ + + if (msg->flags & I2C_M_TEN) + val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/ + else + val &= ~XLP9XX_I2C_CTRL_ADDMODE; + + /* set data length to be transferred */ + val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | + (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); + + /* fill fifo during tx */ + if (!priv->msg_read) + xlp9xx_i2c_fill_tx_fifo(priv); + + /* set interrupt mask */ + intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR | + XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE); + + if (priv->msg_read) { + intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI; + if (msg->len == 0) + intr_mask |= XLP9XX_I2C_INTEN_SADDR; + } else { + if (msg->len == 0) + intr_mask |= XLP9XX_I2C_INTEN_SADDR; + else + intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY; + } + xlp9xx_i2c_unmask_irq(priv, intr_mask); + + /* set cmd reg */ + cmd = XLP9XX_I2C_CMD_START; + cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); + if (last_msg) + cmd |= XLP9XX_I2C_CMD_STOP; + + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd); + + timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS); + timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft); + + if (priv->msg_err) { + dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); + if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) + xlp9xx_i2c_init(priv); + return -EIO; + } + + if (timeleft == 0) { + dev_dbg(priv->dev, "i2c transfer timed out!\n"); + xlp9xx_i2c_init(priv); + return -ETIMEDOUT; + } + + return 0; +} + +static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int i, ret; + struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap); + + for (i = 0; i < num; i++) { + ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1); + if (ret != 0) + return ret; + } + + return num; +} + +static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | + I2C_FUNC_10BIT_ADDR; +} + +static struct i2c_algorithm xlp9xx_i2c_algo = { + .master_xfer = xlp9xx_i2c_xfer, + .functionality = xlp9xx_i2c_functionality, +}; + +static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, + struct xlp9xx_i2c_dev *priv) +{ + struct device_node *np = pdev->dev.of_node; + u32 freq; + int err; + + err = of_property_read_u32(np, "clock-frequency", &freq); + if (err) { + freq = XLP9XX_I2C_DEFAULT_FREQ; + dev_dbg(&pdev->dev, "using default frequency %u\n", freq); + } else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) { + dev_warn(&pdev->dev, "invalid frequency %u, using default\n", + freq); + freq = XLP9XX_I2C_DEFAULT_FREQ; + } + priv->clk_hz = freq; + + return 0; +} + +static int xlp9xx_i2c_probe(struct platform_device *pdev) +{ + struct xlp9xx_i2c_dev *priv; + struct resource *res; + int err = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq <= 0) { + dev_err(&pdev->dev, "invalid irq!\n"); + return priv->irq; + } + + xlp9xx_i2c_get_frequency(pdev, priv); + xlp9xx_i2c_init(priv); + + err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, + pdev->name, priv); + if (err) { + dev_err(&pdev->dev, "IRQ request failed!\n"); + return err; + } + + init_completion(&priv->msg_complete); + priv->adapter.dev.parent = &pdev->dev; + priv->adapter.algo = &xlp9xx_i2c_algo; + priv->adapter.dev.of_node = pdev->dev.of_node; + priv->dev = &pdev->dev; + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c"); + i2c_set_adapdata(&priv->adapter, priv); + + err = i2c_add_adapter(&priv->adapter); + if (err) { + dev_err(&pdev->dev, "failed to add I2C adapter!\n"); + return err; + } + + platform_set_drvdata(pdev, priv); + dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); + + return 0; +} + +static int xlp9xx_i2c_remove(struct platform_device *pdev) +{ + struct xlp9xx_i2c_dev *priv; + + priv = platform_get_drvdata(pdev); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0); + synchronize_irq(priv->irq); + i2c_del_adapter(&priv->adapter); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0); + + return 0; +} + +static const struct of_device_id xlp9xx_i2c_of_match[] = { + { .compatible = "netlogic,xlp980-i2c", }, + { /* sentinel */ }, +}; + +static struct platform_driver xlp9xx_i2c_driver = { + .probe = xlp9xx_i2c_probe, + .remove = xlp9xx_i2c_remove, + .driver = { + .name = "xlp9xx-i2c", + .of_match_table = xlp9xx_i2c_of_match, + }, +}; + +module_platform_driver(xlp9xx_i2c_driver); + +MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>"); +MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index edf274cabe81..68f687733379 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -561,7 +561,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) int i = 0, val = 1, ret = 0; if (bri->prepare_recovery) - bri->prepare_recovery(bri); + bri->prepare_recovery(adap); /* * By this time SCL is high, as we need to give 9 falling-rising edges @@ -586,7 +586,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) } if (bri->unprepare_recovery) - bri->unprepare_recovery(bri); + bri->unprepare_recovery(adap); return ret; } @@ -1875,6 +1875,13 @@ static int __init i2c_init(void) { int retval; + retval = of_alias_get_highest_id("i2c"); + + down_write(&__i2c_board_lock); + if (retval >= __i2c_first_dynamic_bus_num) + __i2c_first_dynamic_bus_num = retval + 1; + up_write(&__i2c_board_lock); + retval = bus_register(&i2c_bus_type); if (retval) return retval; @@ -1926,6 +1933,65 @@ module_exit(i2c_exit); * ---------------------------------------------------- */ +/* Check if val is exceeding the quirk IFF quirk is non 0 */ +#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk))) + +static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg) +{ + dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u, %s)\n", + err_msg, msg->addr, msg->len, + msg->flags & I2C_M_RD ? "read" : "write"); + return -EOPNOTSUPP; +} + +static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + const struct i2c_adapter_quirks *q = adap->quirks; + int max_num = q->max_num_msgs, i; + bool do_len_check = true; + + if (q->flags & I2C_AQ_COMB) { + max_num = 2; + + /* special checks for combined messages */ + if (num == 2) { + if (q->flags & I2C_AQ_COMB_WRITE_FIRST && msgs[0].flags & I2C_M_RD) + return i2c_quirk_error(adap, &msgs[0], "1st comb msg must be write"); + + if (q->flags & I2C_AQ_COMB_READ_SECOND && !(msgs[1].flags & I2C_M_RD)) + return i2c_quirk_error(adap, &msgs[1], "2nd comb msg must be read"); + + if (q->flags & I2C_AQ_COMB_SAME_ADDR && msgs[0].addr != msgs[1].addr) + return i2c_quirk_error(adap, &msgs[0], "comb msg only to same addr"); + + if (i2c_quirk_exceeded(msgs[0].len, q->max_comb_1st_msg_len)) + return i2c_quirk_error(adap, &msgs[0], "msg too long"); + + if (i2c_quirk_exceeded(msgs[1].len, q->max_comb_2nd_msg_len)) + return i2c_quirk_error(adap, &msgs[1], "msg too long"); + + do_len_check = false; + } + } + + if (i2c_quirk_exceeded(num, max_num)) + return i2c_quirk_error(adap, &msgs[0], "too many messages"); + + for (i = 0; i < num; i++) { + u16 len = msgs[i].len; + + if (msgs[i].flags & I2C_M_RD) { + if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len)) + return i2c_quirk_error(adap, &msgs[i], "msg too long"); + } else { + if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len)) + return i2c_quirk_error(adap, &msgs[i], "msg too long"); + } + } + + return 0; +} + /** * __i2c_transfer - unlocked flavor of i2c_transfer * @adap: Handle to I2C bus @@ -1943,6 +2009,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try; + if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) + return -EOPNOTSUPP; + /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed. diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index cf9b09db092f..822374654609 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -36,7 +36,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client, struct eeprom_data *eeprom = i2c_get_clientdata(client); switch (event) { - case I2C_SLAVE_REQ_WRITE_END: + case I2C_SLAVE_WRITE_RECEIVED: if (eeprom->first_write) { eeprom->buffer_idx = *val; eeprom->first_write = false; @@ -47,17 +47,23 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client, } break; - case I2C_SLAVE_REQ_READ_START: + case I2C_SLAVE_READ_PROCESSED: + /* The previous byte made it to the bus, get next one */ + eeprom->buffer_idx++; + /* fallthrough */ + case I2C_SLAVE_READ_REQUESTED: spin_lock(&eeprom->buffer_lock); *val = eeprom->buffer[eeprom->buffer_idx]; spin_unlock(&eeprom->buffer_lock); - break; - - case I2C_SLAVE_REQ_READ_END: - eeprom->buffer_idx++; + /* + * Do not increment buffer_idx here, because we don't know if + * this byte will be actually used. Read Linux I2C slave docs + * for details. + */ break; case I2C_SLAVE_STOP: + case I2C_SLAVE_WRITE_REQUESTED: eeprom->first_write = true; break; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index f5798eb4076b..70db99264339 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -76,10 +76,9 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, return -ENODEV; } adapter = of_find_i2c_adapter_by_node(adapter_np); - if (!adapter) { - dev_err(&pdev->dev, "Cannot find parent bus\n"); + if (!adapter) return -EPROBE_DEFER; - } + mux->data.parent = i2c_adapter_id(adapter); put_device(&adapter->dev); @@ -177,11 +176,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) } parent = i2c_get_adapter(mux->data.parent); - if (!parent) { - dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - mux->data.parent); + if (!parent) return -EPROBE_DEFER; - } mux->parent = parent; mux->gpio_base = gpio_base; diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 3d8f4fe2e47e..bea0d2de2993 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -204,9 +204,9 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, data); /* Get the mux out of reset if a reset GPIO is specified. */ - gpio = devm_gpiod_get(&client->dev, "reset"); - if (!IS_ERR(gpio)) - gpiod_direction_output(gpio, 0); + gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); /* Write the mux register at addr to verify * that the mux is in fact present. This also diff --git a/drivers/of/base.c b/drivers/of/base.c index 8f165b112e03..4cc06c702c41 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1960,6 +1960,32 @@ int of_alias_get_id(struct device_node *np, const char *stem) } EXPORT_SYMBOL_GPL(of_alias_get_id); +/** + * of_alias_get_highest_id - Get highest alias id for the given stem + * @stem: Alias stem to be examined + * + * The function travels the lookup table to get the highest alias id for the + * given alias stem. It returns the alias id if found. + */ +int of_alias_get_highest_id(const char *stem) +{ + struct alias_prop *app; + int id = -ENODEV; + + mutex_lock(&of_mutex); + list_for_each_entry(app, &aliases_lookup, link) { + if (strcmp(app->stem, stem) != 0) + continue; + + if (app->id > id) + id = app->id; + } + mutex_unlock(&of_mutex); + + return id; +} +EXPORT_SYMBOL_GPL(of_alias_get_highest_id); + const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, u32 *pu) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index f17da50402a4..898033f41d76 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -253,10 +253,10 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) #if IS_ENABLED(CONFIG_I2C_SLAVE) enum i2c_slave_event { - I2C_SLAVE_REQ_READ_START, - I2C_SLAVE_REQ_READ_END, - I2C_SLAVE_REQ_WRITE_START, - I2C_SLAVE_REQ_WRITE_END, + I2C_SLAVE_READ_REQUESTED, + I2C_SLAVE_WRITE_REQUESTED, + I2C_SLAVE_READ_PROCESSED, + I2C_SLAVE_WRITE_RECEIVED, I2C_SLAVE_STOP, }; @@ -435,8 +435,8 @@ struct i2c_bus_recovery_info { void (*set_scl)(struct i2c_adapter *, int val); int (*get_sda)(struct i2c_adapter *); - void (*prepare_recovery)(struct i2c_bus_recovery_info *bri); - void (*unprepare_recovery)(struct i2c_bus_recovery_info *bri); + void (*prepare_recovery)(struct i2c_adapter *); + void (*unprepare_recovery)(struct i2c_adapter *); /* gpio recovery */ int scl_gpio; @@ -449,6 +449,48 @@ int i2c_recover_bus(struct i2c_adapter *adap); int i2c_generic_gpio_recovery(struct i2c_adapter *adap); int i2c_generic_scl_recovery(struct i2c_adapter *adap); +/** + * struct i2c_adapter_quirks - describe flaws of an i2c adapter + * @flags: see I2C_AQ_* for possible flags and read below + * @max_num_msgs: maximum number of messages per transfer + * @max_write_len: maximum length of a write message + * @max_read_len: maximum length of a read message + * @max_comb_1st_msg_len: maximum length of the first msg in a combined message + * @max_comb_2nd_msg_len: maximum length of the second msg in a combined message + * + * Note about combined messages: Some I2C controllers can only send one message + * per transfer, plus something called combined message or write-then-read. + * This is (usually) a small write message followed by a read message and + * barely enough to access register based devices like EEPROMs. There is a flag + * to support this mode. It implies max_num_msg = 2 and does the length checks + * with max_comb_*_len because combined message mode usually has its own + * limitations. Because of HW implementations, some controllers can actually do + * write-then-anything or other variants. To support that, write-then-read has + * been broken out into smaller bits like write-first and read-second which can + * be combined as needed. + */ + +struct i2c_adapter_quirks { + u64 flags; + int max_num_msgs; + u16 max_write_len; + u16 max_read_len; + u16 max_comb_1st_msg_len; + u16 max_comb_2nd_msg_len; +}; + +/* enforce max_num_msgs = 2 and use max_comb_*_len for length checks */ +#define I2C_AQ_COMB BIT(0) +/* first combined message must be write */ +#define I2C_AQ_COMB_WRITE_FIRST BIT(1) +/* second combined message must be read */ +#define I2C_AQ_COMB_READ_SECOND BIT(2) +/* both combined messages must have the same target address */ +#define I2C_AQ_COMB_SAME_ADDR BIT(3) +/* convenience macro for typical write-then read case */ +#define I2C_AQ_COMB_WRITE_THEN_READ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \ + I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR) + /* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. @@ -474,6 +516,7 @@ struct i2c_adapter { struct list_head userspace_clients; struct i2c_bus_recovery_info *bus_recovery_info; + const struct i2c_adapter_quirks *quirks; }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) diff --git a/include/linux/of.h b/include/linux/of.h index dfde07e77a63..9bfcc18ceab3 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -332,6 +332,7 @@ extern int of_count_phandle_with_args(const struct device_node *np, extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)); extern int of_alias_get_id(struct device_node *np, const char *stem); +extern int of_alias_get_highest_id(const char *stem); extern int of_machine_is_compatible(const char *compat); @@ -594,6 +595,11 @@ static inline int of_alias_get_id(struct device_node *np, const char *stem) return -ENOSYS; } +static inline int of_alias_get_highest_id(const char *stem) +{ + return -ENOSYS; +} + static inline int of_machine_is_compatible(const char *compat) { return 0; diff --git a/include/linux/platform_data/i2c-davinci.h b/include/linux/platform_data/i2c-davinci.h index 2312d197dfb7..89fd34727a24 100644 --- a/include/linux/platform_data/i2c-davinci.h +++ b/include/linux/platform_data/i2c-davinci.h @@ -18,6 +18,7 @@ struct davinci_i2c_platform_data { unsigned int bus_delay; /* post-transaction delay (usec) */ unsigned int sda_pin; /* GPIO pin ID to use for SDA */ unsigned int scl_pin; /* GPIO pin ID to use for SCL */ + bool has_pfunc; /*chip has a ICPFUNC register */ }; /* for board setup code */ |