Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c changes from Wolfram Sang: - new drivers for exynos5, bcm kona, and st micro - bigger overhauls for drivers mxs and rcar - typical driver bugfixes, cleanups, improvements - got rid of the superfluous 'driver' member in i2c_client struct This touches a few drivers in other subsystems. All acked. * 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (38 commits) i2c: bcm-kona: fix error return code in bcm_kona_i2c_probe() i2c: i2c-eg20t: do not print error message in syslog if no ACK received i2c: bcm-kona: Introduce Broadcom I2C Driver i2c: cbus-gpio: Fix device tree binding i2c: wmt: add missing clk_disable_unprepare() on error i2c: designware: add new ACPI IDs i2c: i801: Add Device IDs for Intel Wildcat Point-LP PCH i2c: exynos5: Remove incorrect clk_disable_unprepare i2c: i2c-st: Add ST I2C controller i2c: exynos5: add High Speed I2C controller driver i2c: rcar: fixup rcar type naming i2c: scmi: remove some bogus NULL checks i2c: sh_mobile & rcar: Enable the driver on all ARM platforms i2c: sh_mobile: Convert to clk_prepare/unprepare i2c: mux: gpio: use reg value for i2c_add_mux_adapter i2c: mux: gpio: use gpio_set_value_cansleep() i2c: Include linux/of.h header i2c: mxs: Fix PIO mode on i.MX23 i2c: mxs: Rework the PIO mode operation i2c: mxs: distinguish i.MX23 and i.MX28 based I2C controller ...
This commit is contained in:
Коммит
13509c3a9d
|
@ -0,0 +1,35 @@
|
|||
Broadcom Kona Family I2C
|
||||
=========================
|
||||
|
||||
This I2C controller is used in the following Broadcom SoCs:
|
||||
|
||||
BCM11130
|
||||
BCM11140
|
||||
BCM11351
|
||||
BCM28145
|
||||
BCM28155
|
||||
|
||||
Required Properties
|
||||
-------------------
|
||||
- compatible: "brcm,bcm11351-i2c", "brcm,kona-i2c"
|
||||
- reg: Physical base address and length of controller registers
|
||||
- interrupts: The interrupt number used by the controller
|
||||
- clocks: clock specifier for the kona i2c external clock
|
||||
- clock-frequency: The I2C bus frequency in Hz
|
||||
- #address-cells: Should be <1>
|
||||
- #size-cells: Should be <0>
|
||||
|
||||
Refer to clocks/clock-bindings.txt for generic clock consumer
|
||||
properties.
|
||||
|
||||
Example:
|
||||
|
||||
i2c@3e016000 {
|
||||
compatible = "brcm,bcm11351-i2c","brcm,kona-i2c";
|
||||
reg = <0x3e016000 0x80>;
|
||||
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&bsc1_clk>;
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
* Samsung's High Speed I2C controller
|
||||
|
||||
The Samsung's High Speed I2C controller is used to interface with I2C devices
|
||||
at various speeds ranging from 100khz to 3.4Mhz.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be.
|
||||
-> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
- #address-cells: always 1 (for i2c addresses)
|
||||
- #size-cells: always 0
|
||||
|
||||
- Pinctrl:
|
||||
- pinctrl-0: Pin control group to be used for this controller.
|
||||
- pinctrl-names: Should contain only one value - "default".
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency: Desired operating frequency in Hz of the bus.
|
||||
-> If not specified, the bus operates in fast-speed mode at
|
||||
at 100khz.
|
||||
-> If specified, the bus operates in high-speed mode only if the
|
||||
clock-frequency is >= 1Mhz.
|
||||
|
||||
Example:
|
||||
|
||||
hsi2c@12ca0000 {
|
||||
compatible = "samsung,exynos5-hsi2c";
|
||||
reg = <0x12ca0000 0x100>;
|
||||
interrupts = <56>;
|
||||
clock-frequency = <100000>;
|
||||
|
||||
pinctrl-0 = <&i2c4_bus>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
s2mps11_pmic@66 {
|
||||
compatible = "samsung,s2mps11-pmic";
|
||||
reg = <0x66>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
I2C for R-Car platforms
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of
|
||||
"renesas,i2c-rcar"
|
||||
"renesas,i2c-r8a7778"
|
||||
"renesas,i2c-r8a7779"
|
||||
"renesas,i2c-r8a7790"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt specifier.
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
|
||||
propoerty indicates the default frequency 100 kHz.
|
||||
|
||||
Examples :
|
||||
|
||||
i2c0: i2c@e6500000 {
|
||||
compatible = "renesas,i2c-rcar-h2";
|
||||
reg = <0 0xe6500000 0 0x428>;
|
||||
interrupts = <0 174 0x4>;
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
ST SSC binding, for I2C mode operation
|
||||
|
||||
Required properties :
|
||||
- compatible : Must be "st,comms-ssc-i2c" or "st,comms-ssc4-i2c"
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : the interrupt specifier
|
||||
- clock-names: Must contain "ssc".
|
||||
- clocks: Must contain an entry for each name in clock-names. See the common
|
||||
clock bindings.
|
||||
- A pinctrl state named "default" must be defined to set pins in mode of
|
||||
operation for I2C transfer.
|
||||
|
||||
Optional properties :
|
||||
- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
|
||||
the default 100 kHz frequency will be used. As only Normal and Fast modes
|
||||
are supported, possible values are 100000 and 400000.
|
||||
- st,i2c-min-scl-pulse-width-us : The minimum valid SCL pulse width that is
|
||||
allowed through the deglitch circuit. In units of us.
|
||||
- st,i2c-min-sda-pulse-width-us : The minimum valid SDA pulse width that is
|
||||
allowed through the deglitch circuit. In units of us.
|
||||
- A pinctrl state named "idle" could be defined to set pins in idle state
|
||||
when I2C instance is not performing a transfer.
|
||||
- A pinctrl state named "sleep" could be defined to set pins in sleep state
|
||||
when driver enters in suspend.
|
||||
|
||||
|
||||
|
||||
Example :
|
||||
|
||||
i2c0: i2c@fed40000 {
|
||||
compatible = "st,comms-ssc4-i2c";
|
||||
reg = <0xfed40000 0x110>;
|
||||
interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&CLK_S_ICN_REG_0>;
|
||||
clock-names = "ssc";
|
||||
clock-frequency = <400000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_i2c0_default>;
|
||||
st,i2c-min-scl-pulse-width-us = <0>;
|
||||
st,i2c-min-sda-pulse-width-us = <5>;
|
||||
};
|
|
@ -25,6 +25,7 @@ Supported adapters:
|
|||
* Intel Avoton (SOC)
|
||||
* Intel Wellsburg (PCH)
|
||||
* Intel Coleto Creek (PCH)
|
||||
* Intel Wildcat Point-LP (PCH)
|
||||
Datasheets: Publicly available at the Intel website
|
||||
|
||||
On Intel Patsburg and later chipsets, both the normal host SMBus controller
|
||||
|
|
|
@ -1425,7 +1425,7 @@ M: Wolfram Sang <wsa@the-dreams.de>
|
|||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/misc/eeprom/at24.c
|
||||
F: include/linux/i2c/at24.h
|
||||
F: include/linux/platform_data/at24.h
|
||||
|
||||
ATA OVER ETHERNET (AOE) DRIVER
|
||||
M: "Ed L. Cashin" <ecashin@coraid.com>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/at73c213.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/input.h>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/tps6507x-ts.h>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
|
||||
#include <media/tvp514x.h>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/eeprom.h>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/smsc911x.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mtd/plat-ram.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/ulpi.h>
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include <asm/mach/time.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/mfd/mc13xxx.h>
|
||||
|
||||
#include "common.h"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <linux/spi/flash.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <mach/kirkwood.h>
|
||||
|
|
|
@ -300,7 +300,7 @@ static struct omap_lcd_config osk_lcd_config __initdata = {
|
|||
#ifdef CONFIG_OMAP_OSK_MISTRAL
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smsc911x.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/leds.h>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/i2c.h>
|
||||
|
|
|
@ -67,12 +67,12 @@ int drm_i2c_encoder_init(struct drm_device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (!client->driver) {
|
||||
if (!client->dev.driver) {
|
||||
err = -ENODEV;
|
||||
goto fail_unregister;
|
||||
}
|
||||
|
||||
module = client->driver->driver.owner;
|
||||
module = client->dev.driver->owner;
|
||||
if (!try_module_get(module)) {
|
||||
err = -ENODEV;
|
||||
goto fail_unregister;
|
||||
|
@ -80,7 +80,7 @@ int drm_i2c_encoder_init(struct drm_device *dev,
|
|||
|
||||
encoder->bus_priv = client;
|
||||
|
||||
encoder_drv = to_drm_i2c_encoder_driver(client->driver);
|
||||
encoder_drv = to_drm_i2c_encoder_driver(to_i2c_driver(client->dev.driver));
|
||||
|
||||
err = encoder_drv->encoder_init(client, dev, encoder);
|
||||
if (err)
|
||||
|
@ -111,7 +111,7 @@ void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
|
|||
{
|
||||
struct drm_encoder_slave *encoder = to_encoder_slave(drm_encoder);
|
||||
struct i2c_client *client = drm_i2c_encoder_get_client(drm_encoder);
|
||||
struct module *module = client->driver->driver.owner;
|
||||
struct module *module = client->dev.driver->owner;
|
||||
|
||||
i2c_unregister_device(client);
|
||||
encoder->bus_priv = NULL;
|
||||
|
|
|
@ -41,7 +41,8 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
|
|||
if (!client)
|
||||
return false;
|
||||
|
||||
if (!client->driver || client->driver->detect(client, info)) {
|
||||
if (!client->dev.driver ||
|
||||
to_i2c_driver(client->dev.driver)->detect(client, info)) {
|
||||
i2c_unregister_device(client);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ config I2C_I801
|
|||
Avoton (SOC)
|
||||
Wellsburg (PCH)
|
||||
Coleto Creek (PCH)
|
||||
Wildcat Point-LP (PCH)
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
|
@ -345,6 +346,16 @@ config I2C_BCM2835
|
|||
This support is also available as a module. If so, the module
|
||||
will be called i2c-bcm2835.
|
||||
|
||||
config I2C_BCM_KONA
|
||||
tristate "BCM Kona I2C adapter"
|
||||
depends on ARCH_BCM_MOBILE
|
||||
default y
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Broadcom Kona family of processors.
|
||||
|
||||
If you do not need KONA I2C inteface, say N.
|
||||
|
||||
config I2C_BLACKFIN_TWI
|
||||
tristate "Blackfin TWI I2C support"
|
||||
depends on BLACKFIN
|
||||
|
@ -436,6 +447,13 @@ config I2C_EG20T
|
|||
ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
|
||||
ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
|
||||
|
||||
config I2C_EXYNOS5
|
||||
tristate "Exynos5 high-speed I2C driver"
|
||||
depends on ARCH_EXYNOS5 && OF
|
||||
help
|
||||
Say Y here to include support for high-speed I2C controller in the
|
||||
Exynos5 based Samsung SoCs.
|
||||
|
||||
config I2C_GPIO
|
||||
tristate "GPIO-based bitbanging I2C"
|
||||
depends on GPIOLIB
|
||||
|
@ -665,7 +683,7 @@ config I2C_SH7760
|
|||
|
||||
config I2C_SH_MOBILE
|
||||
tristate "SuperH Mobile I2C Controller"
|
||||
depends on SUPERH || ARCH_SHMOBILE
|
||||
depends on SUPERH || ARM || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Renesas SH-Mobile processor.
|
||||
|
@ -695,6 +713,16 @@ config I2C_SIRF
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sirf.
|
||||
|
||||
config I2C_ST
|
||||
tristate "STMicroelectronics SSC I2C support"
|
||||
depends on ARCH_STI
|
||||
help
|
||||
Enable this option to add support for STMicroelectronics SoCs
|
||||
hardware SSC (Synchronous Serial Controller) as an I2C controller.
|
||||
|
||||
This driver can also be built as module. If so, the module
|
||||
will be called i2c-st.
|
||||
|
||||
config I2C_STU300
|
||||
tristate "ST Microelectronics DDC I2C interface"
|
||||
depends on MACH_U300
|
||||
|
@ -768,7 +796,7 @@ config I2C_XLR
|
|||
|
||||
config I2C_RCAR
|
||||
tristate "Renesas R-Car I2C Controller"
|
||||
depends on ARCH_SHMOBILE && I2C
|
||||
depends on ARM || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
R-Car I2C controller.
|
||||
|
|
|
@ -42,6 +42,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o
|
|||
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
|
||||
i2c-designware-pci-objs := i2c-designware-pcidrv.o
|
||||
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
|
||||
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
|
||||
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
|
||||
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
|
||||
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
|
||||
|
@ -68,6 +69,7 @@ obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
|||
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
|
||||
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
|
||||
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
|
||||
obj-$(CONFIG_I2C_ST) += i2c-st.o
|
||||
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
|
||||
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
|
||||
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
|
||||
|
@ -87,6 +89,7 @@ obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o
|
|||
|
||||
# Other I2C/SMBus bus drivers
|
||||
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
|
||||
obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o
|
||||
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
|
|
|
@ -0,0 +1,909 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Hardware register offsets and field defintions */
|
||||
#define CS_OFFSET 0x00000020
|
||||
#define CS_ACK_SHIFT 3
|
||||
#define CS_ACK_MASK 0x00000008
|
||||
#define CS_ACK_CMD_GEN_START 0x00000000
|
||||
#define CS_ACK_CMD_GEN_RESTART 0x00000001
|
||||
#define CS_CMD_SHIFT 1
|
||||
#define CS_CMD_CMD_NO_ACTION 0x00000000
|
||||
#define CS_CMD_CMD_START_RESTART 0x00000001
|
||||
#define CS_CMD_CMD_STOP 0x00000002
|
||||
#define CS_EN_SHIFT 0
|
||||
#define CS_EN_CMD_ENABLE_BSC 0x00000001
|
||||
|
||||
#define TIM_OFFSET 0x00000024
|
||||
#define TIM_PRESCALE_SHIFT 6
|
||||
#define TIM_P_SHIFT 3
|
||||
#define TIM_NO_DIV_SHIFT 2
|
||||
#define TIM_DIV_SHIFT 0
|
||||
|
||||
#define DAT_OFFSET 0x00000028
|
||||
|
||||
#define TOUT_OFFSET 0x0000002c
|
||||
|
||||
#define TXFCR_OFFSET 0x0000003c
|
||||
#define TXFCR_FIFO_FLUSH_MASK 0x00000080
|
||||
#define TXFCR_FIFO_EN_MASK 0x00000040
|
||||
|
||||
#define IER_OFFSET 0x00000044
|
||||
#define IER_READ_COMPLETE_INT_MASK 0x00000010
|
||||
#define IER_I2C_INT_EN_MASK 0x00000008
|
||||
#define IER_FIFO_INT_EN_MASK 0x00000002
|
||||
#define IER_NOACK_EN_MASK 0x00000001
|
||||
|
||||
#define ISR_OFFSET 0x00000048
|
||||
#define ISR_RESERVED_MASK 0xffffff60
|
||||
#define ISR_CMDBUSY_MASK 0x00000080
|
||||
#define ISR_READ_COMPLETE_MASK 0x00000010
|
||||
#define ISR_SES_DONE_MASK 0x00000008
|
||||
#define ISR_ERR_MASK 0x00000004
|
||||
#define ISR_TXFIFOEMPTY_MASK 0x00000002
|
||||
#define ISR_NOACK_MASK 0x00000001
|
||||
|
||||
#define CLKEN_OFFSET 0x0000004C
|
||||
#define CLKEN_AUTOSENSE_OFF_MASK 0x00000080
|
||||
#define CLKEN_M_SHIFT 4
|
||||
#define CLKEN_N_SHIFT 1
|
||||
#define CLKEN_CLKEN_MASK 0x00000001
|
||||
|
||||
#define FIFO_STATUS_OFFSET 0x00000054
|
||||
#define FIFO_STATUS_RXFIFO_EMPTY_MASK 0x00000004
|
||||
#define FIFO_STATUS_TXFIFO_EMPTY_MASK 0x00000010
|
||||
|
||||
#define HSTIM_OFFSET 0x00000058
|
||||
#define HSTIM_HS_MODE_MASK 0x00008000
|
||||
#define HSTIM_HS_HOLD_SHIFT 10
|
||||
#define HSTIM_HS_HIGH_PHASE_SHIFT 5
|
||||
#define HSTIM_HS_SETUP_SHIFT 0
|
||||
|
||||
#define PADCTL_OFFSET 0x0000005c
|
||||
#define PADCTL_PAD_OUT_EN_MASK 0x00000004
|
||||
|
||||
#define RXFCR_OFFSET 0x00000068
|
||||
#define RXFCR_NACK_EN_SHIFT 7
|
||||
#define RXFCR_READ_COUNT_SHIFT 0
|
||||
#define RXFIFORDOUT_OFFSET 0x0000006c
|
||||
|
||||
/* Locally used constants */
|
||||
#define MAX_RX_FIFO_SIZE 64U /* bytes */
|
||||
#define MAX_TX_FIFO_SIZE 64U /* bytes */
|
||||
|
||||
#define STD_EXT_CLK_FREQ 13000000UL
|
||||
#define HS_EXT_CLK_FREQ 104000000UL
|
||||
|
||||
#define MASTERCODE 0x08 /* Mastercodes are 0000_1xxxb */
|
||||
|
||||
#define I2C_TIMEOUT 100 /* msecs */
|
||||
|
||||
/* Operations that can be commanded to the controller */
|
||||
enum bcm_kona_cmd_t {
|
||||
BCM_CMD_NOACTION = 0,
|
||||
BCM_CMD_START,
|
||||
BCM_CMD_RESTART,
|
||||
BCM_CMD_STOP,
|
||||
};
|
||||
|
||||
enum bus_speed_index {
|
||||
BCM_SPD_100K = 0,
|
||||
BCM_SPD_400K,
|
||||
BCM_SPD_1MHZ,
|
||||
};
|
||||
|
||||
enum hs_bus_speed_index {
|
||||
BCM_SPD_3P4MHZ = 0,
|
||||
};
|
||||
|
||||
/* Internal divider settings for standard mode, fast mode and fast mode plus */
|
||||
struct bus_speed_cfg {
|
||||
uint8_t time_m; /* Number of cycles for setup time */
|
||||
uint8_t time_n; /* Number of cycles for hold time */
|
||||
uint8_t prescale; /* Prescale divider */
|
||||
uint8_t time_p; /* Timing coefficient */
|
||||
uint8_t no_div; /* Disable clock divider */
|
||||
uint8_t time_div; /* Post-prescale divider */
|
||||
};
|
||||
|
||||
/* Internal divider settings for high-speed mode */
|
||||
struct hs_bus_speed_cfg {
|
||||
uint8_t hs_hold; /* Number of clock cycles SCL stays low until
|
||||
the end of bit period */
|
||||
uint8_t hs_high_phase; /* Number of clock cycles SCL stays high
|
||||
before it falls */
|
||||
uint8_t hs_setup; /* Number of clock cycles SCL stays low
|
||||
before it rises */
|
||||
uint8_t prescale; /* Prescale divider */
|
||||
uint8_t time_p; /* Timing coefficient */
|
||||
uint8_t no_div; /* Disable clock divider */
|
||||
uint8_t time_div; /* Post-prescale divider */
|
||||
};
|
||||
|
||||
static const struct bus_speed_cfg std_cfg_table[] = {
|
||||
[BCM_SPD_100K] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02},
|
||||
[BCM_SPD_400K] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02},
|
||||
[BCM_SPD_1MHZ] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03},
|
||||
};
|
||||
|
||||
static const struct hs_bus_speed_cfg hs_cfg_table[] = {
|
||||
[BCM_SPD_3P4MHZ] = {0x01, 0x08, 0x14, 0x00, 0x06, 0x01, 0x00},
|
||||
};
|
||||
|
||||
struct bcm_kona_i2c_dev {
|
||||
struct device *device;
|
||||
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
struct clk *external_clk;
|
||||
|
||||
struct i2c_adapter adapter;
|
||||
|
||||
struct completion done;
|
||||
|
||||
const struct bus_speed_cfg *std_cfg;
|
||||
const struct hs_bus_speed_cfg *hs_cfg;
|
||||
};
|
||||
|
||||
static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev,
|
||||
enum bcm_kona_cmd_t cmd)
|
||||
{
|
||||
dev_dbg(dev->device, "%s, %d\n", __func__, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case BCM_CMD_NOACTION:
|
||||
writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) |
|
||||
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
|
||||
dev->base + CS_OFFSET);
|
||||
break;
|
||||
|
||||
case BCM_CMD_START:
|
||||
writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) |
|
||||
(CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
|
||||
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
|
||||
dev->base + CS_OFFSET);
|
||||
break;
|
||||
|
||||
case BCM_CMD_RESTART:
|
||||
writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) |
|
||||
(CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
|
||||
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
|
||||
dev->base + CS_OFFSET);
|
||||
break;
|
||||
|
||||
case BCM_CMD_STOP:
|
||||
writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) |
|
||||
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
|
||||
dev->base + CS_OFFSET);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev->device, "Unknown command %d\n", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK,
|
||||
dev->base + CLKEN_OFFSET);
|
||||
}
|
||||
|
||||
static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK,
|
||||
dev->base + CLKEN_OFFSET);
|
||||
}
|
||||
|
||||
static irqreturn_t bcm_kona_i2c_isr(int irq, void *devid)
|
||||
{
|
||||
struct bcm_kona_i2c_dev *dev = devid;
|
||||
uint32_t status = readl(dev->base + ISR_OFFSET);
|
||||
|
||||
if ((status & ~ISR_RESERVED_MASK) == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Must flush the TX FIFO when NAK detected */
|
||||
if (status & ISR_NOACK_MASK)
|
||||
writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
|
||||
dev->base + TXFCR_OFFSET);
|
||||
|
||||
writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET);
|
||||
complete_all(&dev->done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Wait for ISR_CMDBUSY_MASK to go low before writing to CS, DAT, or RCD */
|
||||
static int bcm_kona_i2c_wait_if_busy(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT);
|
||||
|
||||
while (readl(dev->base + ISR_OFFSET) & ISR_CMDBUSY_MASK)
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(dev->device, "CMDBUSY timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send command to I2C bus */
|
||||
static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev,
|
||||
enum bcm_kona_cmd_t cmd)
|
||||
{
|
||||
int rc;
|
||||
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT);
|
||||
|
||||
/* Make sure the hardware is ready */
|
||||
rc = bcm_kona_i2c_wait_if_busy(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Unmask the session done interrupt */
|
||||
writel(IER_I2C_INT_EN_MASK, dev->base + IER_OFFSET);
|
||||
|
||||
/* Mark as incomplete before sending the command */
|
||||
reinit_completion(&dev->done);
|
||||
|
||||
/* Send the command */
|
||||
bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd);
|
||||
|
||||
/* Wait for transaction to finish or timeout */
|
||||
time_left = wait_for_completion_timeout(&dev->done, time_left);
|
||||
|
||||
/* Mask all interrupts */
|
||||
writel(0, dev->base + IER_OFFSET);
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(dev->device, "controller timed out\n");
|
||||
rc = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Clear command */
|
||||
bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Read a single RX FIFO worth of data from the i2c bus */
|
||||
static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev,
|
||||
uint8_t *buf, unsigned int len,
|
||||
unsigned int last_byte_nak)
|
||||
{
|
||||
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT);
|
||||
|
||||
/* Mark as incomplete before starting the RX FIFO */
|
||||
reinit_completion(&dev->done);
|
||||
|
||||
/* Unmask the read complete interrupt */
|
||||
writel(IER_READ_COMPLETE_INT_MASK, dev->base + IER_OFFSET);
|
||||
|
||||
/* Start the RX FIFO */
|
||||
writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) |
|
||||
(len << RXFCR_READ_COUNT_SHIFT),
|
||||
dev->base + RXFCR_OFFSET);
|
||||
|
||||
/* Wait for FIFO read to complete */
|
||||
time_left = wait_for_completion_timeout(&dev->done, time_left);
|
||||
|
||||
/* Mask all interrupts */
|
||||
writel(0, dev->base + IER_OFFSET);
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(dev->device, "RX FIFO time out\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* Read data from FIFO */
|
||||
for (; len > 0; len--, buf++)
|
||||
*buf = readl(dev->base + RXFIFORDOUT_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read any amount of data using the RX FIFO from the i2c bus */
|
||||
static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
unsigned int bytes_to_read = MAX_RX_FIFO_SIZE;
|
||||
unsigned int last_byte_nak = 0;
|
||||
unsigned int bytes_read = 0;
|
||||
int rc;
|
||||
|
||||
uint8_t *tmp_buf = msg->buf;
|
||||
|
||||
while (bytes_read < msg->len) {
|
||||
if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) {
|
||||
last_byte_nak = 1; /* NAK last byte of transfer */
|
||||
bytes_to_read = msg->len - bytes_read;
|
||||
}
|
||||
|
||||
rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read,
|
||||
last_byte_nak);
|
||||
if (rc < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
bytes_read += bytes_to_read;
|
||||
tmp_buf += bytes_to_read;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a single byte of data to the i2c bus */
|
||||
static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data,
|
||||
unsigned int nak_expected)
|
||||
{
|
||||
int rc;
|
||||
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT);
|
||||
unsigned int nak_received;
|
||||
|
||||
/* Make sure the hardware is ready */
|
||||
rc = bcm_kona_i2c_wait_if_busy(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Clear pending session done interrupt */
|
||||
writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET);
|
||||
|
||||
/* Unmask the session done interrupt */
|
||||
writel(IER_I2C_INT_EN_MASK, dev->base + IER_OFFSET);
|
||||
|
||||
/* Mark as incomplete before sending the data */
|
||||
reinit_completion(&dev->done);
|
||||
|
||||
/* Send one byte of data */
|
||||
writel(data, dev->base + DAT_OFFSET);
|
||||
|
||||
/* Wait for byte to be written */
|
||||
time_left = wait_for_completion_timeout(&dev->done, time_left);
|
||||
|
||||
/* Mask all interrupts */
|
||||
writel(0, dev->base + IER_OFFSET);
|
||||
|
||||
if (!time_left) {
|
||||
dev_dbg(dev->device, "controller timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0;
|
||||
|
||||
if (nak_received ^ nak_expected) {
|
||||
dev_dbg(dev->device, "unexpected NAK/ACK\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a single TX FIFO worth of data to the i2c bus */
|
||||
static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
|
||||
uint8_t *buf, unsigned int len)
|
||||
{
|
||||
int k;
|
||||
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT);
|
||||
unsigned int fifo_status;
|
||||
|
||||
/* Mark as incomplete before sending data to the TX FIFO */
|
||||
reinit_completion(&dev->done);
|
||||
|
||||
/* Unmask the fifo empty and nak interrupt */
|
||||
writel(IER_FIFO_INT_EN_MASK | IER_NOACK_EN_MASK,
|
||||
dev->base + IER_OFFSET);
|
||||
|
||||
/* Disable IRQ to load a FIFO worth of data without interruption */
|
||||
disable_irq(dev->irq);
|
||||
|
||||
/* Write data into FIFO */
|
||||
for (k = 0; k < len; k++)
|
||||
writel(buf[k], (dev->base + DAT_OFFSET));
|
||||
|
||||
/* Enable IRQ now that data has been loaded */
|
||||
enable_irq(dev->irq);
|
||||
|
||||
/* Wait for FIFO to empty */
|
||||
do {
|
||||
time_left = wait_for_completion_timeout(&dev->done, time_left);
|
||||
fifo_status = readl(dev->base + FIFO_STATUS_OFFSET);
|
||||
} while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK));
|
||||
|
||||
/* Mask all interrupts */
|
||||
writel(0, dev->base + IER_OFFSET);
|
||||
|
||||
/* Check if there was a NAK */
|
||||
if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) {
|
||||
dev_err(dev->device, "unexpected NAK\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* Check if a timeout occured */
|
||||
if (!time_left) {
|
||||
dev_err(dev->device, "completion timed out\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Write any amount of data using TX FIFO to the i2c bus */
|
||||
static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
unsigned int bytes_to_write = MAX_TX_FIFO_SIZE;
|
||||
unsigned int bytes_written = 0;
|
||||
int rc;
|
||||
|
||||
uint8_t *tmp_buf = msg->buf;
|
||||
|
||||
while (bytes_written < msg->len) {
|
||||
if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE)
|
||||
bytes_to_write = msg->len - bytes_written;
|
||||
|
||||
rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf,
|
||||
bytes_to_write);
|
||||
if (rc < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
bytes_written += bytes_to_write;
|
||||
tmp_buf += bytes_to_write;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send i2c address */
|
||||
static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
unsigned char addr;
|
||||
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
/* First byte is 11110XX0 where XX is upper 2 bits */
|
||||
addr = 0xF0 | ((msg->addr & 0x300) >> 7);
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
/* Second byte is the remaining 8 bits */
|
||||
addr = msg->addr & 0xFF;
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
/* For read, send restart command */
|
||||
if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
/* Then re-send the first byte with the read bit set */
|
||||
addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
} else {
|
||||
addr = msg->addr << 1;
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK,
|
||||
dev->base + CLKEN_OFFSET);
|
||||
}
|
||||
|
||||
static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK,
|
||||
dev->base + HSTIM_OFFSET);
|
||||
|
||||
writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) |
|
||||
(dev->std_cfg->time_p << TIM_P_SHIFT) |
|
||||
(dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) |
|
||||
(dev->std_cfg->time_div << TIM_DIV_SHIFT),
|
||||
dev->base + TIM_OFFSET);
|
||||
|
||||
writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) |
|
||||
(dev->std_cfg->time_n << CLKEN_N_SHIFT) |
|
||||
CLKEN_CLKEN_MASK,
|
||||
dev->base + CLKEN_OFFSET);
|
||||
}
|
||||
|
||||
static void bcm_kona_i2c_config_timing_hs(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
writel((dev->hs_cfg->prescale << TIM_PRESCALE_SHIFT) |
|
||||
(dev->hs_cfg->time_p << TIM_P_SHIFT) |
|
||||
(dev->hs_cfg->no_div << TIM_NO_DIV_SHIFT) |
|
||||
(dev->hs_cfg->time_div << TIM_DIV_SHIFT),
|
||||
dev->base + TIM_OFFSET);
|
||||
|
||||
writel((dev->hs_cfg->hs_hold << HSTIM_HS_HOLD_SHIFT) |
|
||||
(dev->hs_cfg->hs_high_phase << HSTIM_HS_HIGH_PHASE_SHIFT) |
|
||||
(dev->hs_cfg->hs_setup << HSTIM_HS_SETUP_SHIFT),
|
||||
dev->base + HSTIM_OFFSET);
|
||||
|
||||
writel(readl(dev->base + HSTIM_OFFSET) | HSTIM_HS_MODE_MASK,
|
||||
dev->base + HSTIM_OFFSET);
|
||||
}
|
||||
|
||||
static int bcm_kona_i2c_switch_to_hs(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Send mastercode at standard speed */
|
||||
rc = bcm_kona_i2c_write_byte(dev, MASTERCODE, 1);
|
||||
if (rc < 0) {
|
||||
pr_err("High speed handshake failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Configure external clock to higher frequency */
|
||||
rc = clk_set_rate(dev->external_clk, HS_EXT_CLK_FREQ);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "%s: clk_set_rate returned %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Reconfigure internal dividers */
|
||||
bcm_kona_i2c_config_timing_hs(dev);
|
||||
|
||||
/* Send a restart command */
|
||||
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
|
||||
if (rc < 0)
|
||||
dev_err(dev->device, "High speed restart command failed\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bcm_kona_i2c_switch_to_std(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Reconfigure internal dividers */
|
||||
bcm_kona_i2c_config_timing(dev);
|
||||
|
||||
/* Configure external clock to lower frequency */
|
||||
rc = clk_set_rate(dev->external_clk, STD_EXT_CLK_FREQ);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "%s: clk_set_rate returned %d\n",
|
||||
__func__, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Master transfer function */
|
||||
static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct bcm_kona_i2c_dev *dev = i2c_get_adapdata(adapter);
|
||||
struct i2c_msg *pmsg;
|
||||
int rc = 0;
|
||||
int i;
|
||||
|
||||
rc = clk_prepare_enable(dev->external_clk);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "%s: peri clock enable failed. err %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Enable pad output */
|
||||
writel(0, dev->base + PADCTL_OFFSET);
|
||||
|
||||
/* Enable internal clocks */
|
||||
bcm_kona_i2c_enable_clock(dev);
|
||||
|
||||
/* Send start command */
|
||||
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START);
|
||||
if (rc < 0) {
|
||||
dev_err(dev->device, "Start command failed rc = %d\n", rc);
|
||||
goto xfer_disable_pad;
|
||||
}
|
||||
|
||||
/* Switch to high speed if applicable */
|
||||
if (dev->hs_cfg) {
|
||||
rc = bcm_kona_i2c_switch_to_hs(dev);
|
||||
if (rc < 0)
|
||||
goto xfer_send_stop;
|
||||
}
|
||||
|
||||
/* Loop through all messages */
|
||||
for (i = 0; i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
|
||||
/* Send restart for subsequent messages */
|
||||
if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) {
|
||||
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
|
||||
if (rc < 0) {
|
||||
dev_err(dev->device,
|
||||
"restart cmd failed rc = %d\n", rc);
|
||||
goto xfer_send_stop;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send slave address */
|
||||
if (!(pmsg->flags & I2C_M_NOSTART)) {
|
||||
rc = bcm_kona_i2c_do_addr(dev, pmsg);
|
||||
if (rc < 0) {
|
||||
dev_err(dev->device,
|
||||
"NAK from addr %2.2x msg#%d rc = %d\n",
|
||||
pmsg->addr, i, rc);
|
||||
goto xfer_send_stop;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform data transfer */
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
rc = bcm_kona_i2c_read_fifo(dev, pmsg);
|
||||
if (rc < 0) {
|
||||
dev_err(dev->device, "read failure\n");
|
||||
goto xfer_send_stop;
|
||||
}
|
||||
} else {
|
||||
rc = bcm_kona_i2c_write_fifo(dev, pmsg);
|
||||
if (rc < 0) {
|
||||
dev_err(dev->device, "write failure");
|
||||
goto xfer_send_stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = num;
|
||||
|
||||
xfer_send_stop:
|
||||
/* Send a STOP command */
|
||||
bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP);
|
||||
|
||||
/* Return from high speed if applicable */
|
||||
if (dev->hs_cfg) {
|
||||
int hs_rc = bcm_kona_i2c_switch_to_std(dev);
|
||||
|
||||
if (hs_rc)
|
||||
rc = hs_rc;
|
||||
}
|
||||
|
||||
xfer_disable_pad:
|
||||
/* Disable pad output */
|
||||
writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
|
||||
|
||||
/* Stop internal clock */
|
||||
bcm_kona_i2c_disable_clock(dev);
|
||||
|
||||
clk_disable_unprepare(dev->external_clk);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static uint32_t bcm_kona_i2c_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
|
||||
I2C_FUNC_NOSTART;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm bcm_algo = {
|
||||
.master_xfer = bcm_kona_i2c_xfer,
|
||||
.functionality = bcm_kona_i2c_functionality,
|
||||
};
|
||||
|
||||
static int bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev)
|
||||
{
|
||||
unsigned int bus_speed;
|
||||
int ret = of_property_read_u32(dev->device->of_node, "clock-frequency",
|
||||
&bus_speed);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->device, "missing clock-frequency property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (bus_speed) {
|
||||
case 100000:
|
||||
dev->std_cfg = &std_cfg_table[BCM_SPD_100K];
|
||||
break;
|
||||
case 400000:
|
||||
dev->std_cfg = &std_cfg_table[BCM_SPD_400K];
|
||||
break;
|
||||
case 1000000:
|
||||
dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ];
|
||||
break;
|
||||
case 3400000:
|
||||
/* Send mastercode at 100k */
|
||||
dev->std_cfg = &std_cfg_table[BCM_SPD_100K];
|
||||
dev->hs_cfg = &hs_cfg_table[BCM_SPD_3P4MHZ];
|
||||
break;
|
||||
default:
|
||||
pr_err("%d hz bus speed not supported\n", bus_speed);
|
||||
pr_err("Valid speeds are 100khz, 400khz, 1mhz, and 3.4mhz\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_kona_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct bcm_kona_i2c_dev *dev;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *iomem;
|
||||
|
||||
/* Allocate memory for private data structure */
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
dev->device = &pdev->dev;
|
||||
init_completion(&dev->done);
|
||||
|
||||
/* Map hardware registers */
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->base = devm_ioremap_resource(dev->device, iomem);
|
||||
if (IS_ERR(dev->base))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get and enable external clock */
|
||||
dev->external_clk = devm_clk_get(dev->device, NULL);
|
||||
if (IS_ERR(dev->external_clk)) {
|
||||
dev_err(dev->device, "couldn't get clock\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = clk_set_rate(dev->external_clk, STD_EXT_CLK_FREQ);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "%s: clk_set_rate returned %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = clk_prepare_enable(dev->external_clk);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "couldn't enable clock\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Parse bus speed */
|
||||
rc = bcm_kona_i2c_assign_bus_speed(dev);
|
||||
if (rc)
|
||||
goto probe_disable_clk;
|
||||
|
||||
/* Enable internal clocks */
|
||||
bcm_kona_i2c_enable_clock(dev);
|
||||
|
||||
/* Configure internal dividers */
|
||||
bcm_kona_i2c_config_timing(dev);
|
||||
|
||||
/* Disable timeout */
|
||||
writel(0, dev->base + TOUT_OFFSET);
|
||||
|
||||
/* Enable autosense */
|
||||
bcm_kona_i2c_enable_autosense(dev);
|
||||
|
||||
/* Enable TX FIFO */
|
||||
writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
|
||||
dev->base + TXFCR_OFFSET);
|
||||
|
||||
/* Mask all interrupts */
|
||||
writel(0, dev->base + IER_OFFSET);
|
||||
|
||||
/* Clear all pending interrupts */
|
||||
writel(ISR_CMDBUSY_MASK |
|
||||
ISR_READ_COMPLETE_MASK |
|
||||
ISR_SES_DONE_MASK |
|
||||
ISR_ERR_MASK |
|
||||
ISR_TXFIFOEMPTY_MASK |
|
||||
ISR_NOACK_MASK,
|
||||
dev->base + ISR_OFFSET);
|
||||
|
||||
/* Get the interrupt number */
|
||||
dev->irq = platform_get_irq(pdev, 0);
|
||||
if (dev->irq < 0) {
|
||||
dev_err(dev->device, "no irq resource\n");
|
||||
rc = -ENODEV;
|
||||
goto probe_disable_clk;
|
||||
}
|
||||
|
||||
/* register the ISR handler */
|
||||
rc = devm_request_irq(&pdev->dev, dev->irq, bcm_kona_i2c_isr,
|
||||
IRQF_SHARED, pdev->name, dev);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "failed to request irq %i\n", dev->irq);
|
||||
goto probe_disable_clk;
|
||||
}
|
||||
|
||||
/* Enable the controller but leave it idle */
|
||||
bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
|
||||
|
||||
/* Disable pad output */
|
||||
writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
|
||||
|
||||
/* Disable internal clock */
|
||||
bcm_kona_i2c_disable_clock(dev);
|
||||
|
||||
/* Disable external clock */
|
||||
clk_disable_unprepare(dev->external_clk);
|
||||
|
||||
/* Add the i2c adapter */
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
strlcpy(adap->name, "Broadcom I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &bcm_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
rc = i2c_add_adapter(adap);
|
||||
if (rc) {
|
||||
dev_err(dev->device, "failed to add adapter\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_info(dev->device, "device registered successfully\n");
|
||||
|
||||
return 0;
|
||||
|
||||
probe_disable_clk:
|
||||
bcm_kona_i2c_disable_clock(dev);
|
||||
clk_disable_unprepare(dev->external_clk);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bcm_kona_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm_kona_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm_kona_i2c_of_match[] = {
|
||||
{.compatible = "brcm,kona-i2c",},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kona_i2c_of_match);
|
||||
|
||||
static struct platform_driver bcm_kona_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "bcm-kona-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = bcm_kona_i2c_of_match,
|
||||
},
|
||||
.probe = bcm_kona_i2c_probe,
|
||||
.remove = bcm_kona_i2c_remove,
|
||||
};
|
||||
module_platform_driver(bcm_kona_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Tim Kryger <tkryger@broadcom.com>");
|
||||
MODULE_DESCRIPTION("Broadcom Kona I2C Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -675,7 +675,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
|||
p_adap->retries = 3;
|
||||
|
||||
rc = peripheral_request_list(
|
||||
(unsigned short *)dev_get_platdata(&pdev->dev),
|
||||
dev_get_platdata(&pdev->dev),
|
||||
"i2c-bfin-twi");
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Can't setup pin mux!\n");
|
||||
|
@ -723,7 +723,7 @@ out_error_add_adapter:
|
|||
free_irq(iface->irq, iface);
|
||||
out_error_req_irq:
|
||||
out_error_no_irq:
|
||||
peripheral_free_list((unsigned short *)dev_get_platdata(&pdev->dev));
|
||||
peripheral_free_list(dev_get_platdata(&pdev->dev));
|
||||
out_error_pin_mux:
|
||||
iounmap(iface->regs_base);
|
||||
out_error_ioremap:
|
||||
|
@ -739,7 +739,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
|
|||
|
||||
i2c_del_adapter(&(iface->adap));
|
||||
free_irq(iface->irq, iface);
|
||||
peripheral_free_list((unsigned short *)dev_get_platdata(&pdev->dev));
|
||||
peripheral_free_list(dev_get_platdata(&pdev->dev));
|
||||
iounmap(iface->regs_base);
|
||||
kfree(iface);
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ static int cbus_i2c_probe(struct platform_device *pdev)
|
|||
adapter->owner = THIS_MODULE;
|
||||
adapter->class = I2C_CLASS_HWMON;
|
||||
adapter->dev.parent = &pdev->dev;
|
||||
adapter->dev.of_node = pdev->dev.of_node;
|
||||
adapter->nr = pdev->id;
|
||||
adapter->timeout = HZ;
|
||||
adapter->algo = &cbus_i2c_algo;
|
||||
|
@ -289,6 +290,7 @@ static struct platform_driver cbus_i2c_driver = {
|
|||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-cbus-gpio",
|
||||
.of_match_table = of_match_ptr(i2c_cbus_dt_ids),
|
||||
},
|
||||
};
|
||||
module_platform_driver(cbus_i2c_driver);
|
||||
|
|
|
@ -795,7 +795,7 @@ static struct platform_driver davinci_i2c_driver = {
|
|||
.name = "i2c_davinci",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = davinci_i2c_pm_ops,
|
||||
.of_match_table = of_match_ptr(davinci_i2c_of_match),
|
||||
.of_match_table = davinci_i2c_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -103,6 +103,8 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
|
|||
static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
||||
{ "INT33C2", 0 },
|
||||
{ "INT33C3", 0 },
|
||||
{ "INT3432", 0 },
|
||||
{ "INT3433", 0 },
|
||||
{ "80860F41", 0 },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -311,24 +311,6 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap)
|
|||
pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_i2c_getack() - to confirm ACK/NACK
|
||||
* @adap: Pointer to struct i2c_algo_pch_data.
|
||||
*/
|
||||
static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap)
|
||||
{
|
||||
u32 reg_val;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK;
|
||||
|
||||
if (reg_val != 0) {
|
||||
pch_err(adap, "return%d\n", -EPROTO);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_i2c_stop() - generate stop condition in normal mode.
|
||||
* @adap: Pointer to struct i2c_algo_pch_data.
|
||||
|
@ -344,6 +326,7 @@ static void pch_i2c_stop(struct i2c_algo_pch_data *adap)
|
|||
static int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap)
|
||||
{
|
||||
long ret;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
|
||||
ret = wait_event_timeout(pch_event,
|
||||
(adap->pch_event_flag != 0), msecs_to_jiffies(1000));
|
||||
|
@ -366,10 +349,9 @@ static int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap)
|
|||
|
||||
adap->pch_event_flag = 0;
|
||||
|
||||
if (pch_i2c_getack(adap)) {
|
||||
pch_dbg(adap, "Receive NACK for slave address"
|
||||
"setting\n");
|
||||
return -EIO;
|
||||
if (ioread32(p + PCH_I2CSR) & PCH_GETACK) {
|
||||
pch_dbg(adap, "Receive NACK for slave address setting\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,769 @@
|
|||
/**
|
||||
* i2c-exynos5.c - Samsung Exynos5 I2C Controller Driver
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/*
|
||||
* HSI2C controller from Samsung supports 2 modes of operation
|
||||
* 1. Auto mode: Where in master automatically controls the whole transaction
|
||||
* 2. Manual mode: Software controls the transaction by issuing commands
|
||||
* START, READ, WRITE, STOP, RESTART in I2C_MANUAL_CMD register.
|
||||
*
|
||||
* Operation mode can be selected by setting AUTO_MODE bit in I2C_CONF register
|
||||
*
|
||||
* Special bits are available for both modes of operation to set commands
|
||||
* and for checking transfer status
|
||||
*/
|
||||
|
||||
/* Register Map */
|
||||
#define HSI2C_CTL 0x00
|
||||
#define HSI2C_FIFO_CTL 0x04
|
||||
#define HSI2C_TRAILIG_CTL 0x08
|
||||
#define HSI2C_CLK_CTL 0x0C
|
||||
#define HSI2C_CLK_SLOT 0x10
|
||||
#define HSI2C_INT_ENABLE 0x20
|
||||
#define HSI2C_INT_STATUS 0x24
|
||||
#define HSI2C_ERR_STATUS 0x2C
|
||||
#define HSI2C_FIFO_STATUS 0x30
|
||||
#define HSI2C_TX_DATA 0x34
|
||||
#define HSI2C_RX_DATA 0x38
|
||||
#define HSI2C_CONF 0x40
|
||||
#define HSI2C_AUTO_CONF 0x44
|
||||
#define HSI2C_TIMEOUT 0x48
|
||||
#define HSI2C_MANUAL_CMD 0x4C
|
||||
#define HSI2C_TRANS_STATUS 0x50
|
||||
#define HSI2C_TIMING_HS1 0x54
|
||||
#define HSI2C_TIMING_HS2 0x58
|
||||
#define HSI2C_TIMING_HS3 0x5C
|
||||
#define HSI2C_TIMING_FS1 0x60
|
||||
#define HSI2C_TIMING_FS2 0x64
|
||||
#define HSI2C_TIMING_FS3 0x68
|
||||
#define HSI2C_TIMING_SLA 0x6C
|
||||
#define HSI2C_ADDR 0x70
|
||||
|
||||
/* I2C_CTL Register bits */
|
||||
#define HSI2C_FUNC_MODE_I2C (1u << 0)
|
||||
#define HSI2C_MASTER (1u << 3)
|
||||
#define HSI2C_RXCHON (1u << 6)
|
||||
#define HSI2C_TXCHON (1u << 7)
|
||||
#define HSI2C_SW_RST (1u << 31)
|
||||
|
||||
/* I2C_FIFO_CTL Register bits */
|
||||
#define HSI2C_RXFIFO_EN (1u << 0)
|
||||
#define HSI2C_TXFIFO_EN (1u << 1)
|
||||
#define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4)
|
||||
#define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16)
|
||||
|
||||
/* As per user manual FIFO max depth is 64bytes */
|
||||
#define HSI2C_FIFO_MAX 0x40
|
||||
/* default trigger levels for Tx and Rx FIFOs */
|
||||
#define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30)
|
||||
#define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10)
|
||||
|
||||
/* I2C_TRAILING_CTL Register bits */
|
||||
#define HSI2C_TRAILING_COUNT (0xf)
|
||||
|
||||
/* I2C_INT_EN Register bits */
|
||||
#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0)
|
||||
#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1)
|
||||
#define HSI2C_INT_TRAILING_EN (1u << 6)
|
||||
#define HSI2C_INT_I2C_EN (1u << 9)
|
||||
|
||||
/* I2C_INT_STAT Register bits */
|
||||
#define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0)
|
||||
#define HSI2C_INT_RX_ALMOSTFULL (1u << 1)
|
||||
#define HSI2C_INT_TX_UNDERRUN (1u << 2)
|
||||
#define HSI2C_INT_TX_OVERRUN (1u << 3)
|
||||
#define HSI2C_INT_RX_UNDERRUN (1u << 4)
|
||||
#define HSI2C_INT_RX_OVERRUN (1u << 5)
|
||||
#define HSI2C_INT_TRAILING (1u << 6)
|
||||
#define HSI2C_INT_I2C (1u << 9)
|
||||
|
||||
/* I2C_FIFO_STAT Register bits */
|
||||
#define HSI2C_RX_FIFO_EMPTY (1u << 24)
|
||||
#define HSI2C_RX_FIFO_FULL (1u << 23)
|
||||
#define HSI2C_RX_FIFO_LVL(x) ((x >> 16) & 0x7f)
|
||||
#define HSI2C_TX_FIFO_EMPTY (1u << 8)
|
||||
#define HSI2C_TX_FIFO_FULL (1u << 7)
|
||||
#define HSI2C_TX_FIFO_LVL(x) ((x >> 0) & 0x7f)
|
||||
|
||||
/* I2C_CONF Register bits */
|
||||
#define HSI2C_AUTO_MODE (1u << 31)
|
||||
#define HSI2C_10BIT_ADDR_MODE (1u << 30)
|
||||
#define HSI2C_HS_MODE (1u << 29)
|
||||
|
||||
/* I2C_AUTO_CONF Register bits */
|
||||
#define HSI2C_READ_WRITE (1u << 16)
|
||||
#define HSI2C_STOP_AFTER_TRANS (1u << 17)
|
||||
#define HSI2C_MASTER_RUN (1u << 31)
|
||||
|
||||
/* I2C_TIMEOUT Register bits */
|
||||
#define HSI2C_TIMEOUT_EN (1u << 31)
|
||||
#define HSI2C_TIMEOUT_MASK 0xff
|
||||
|
||||
/* I2C_TRANS_STATUS register bits */
|
||||
#define HSI2C_MASTER_BUSY (1u << 17)
|
||||
#define HSI2C_SLAVE_BUSY (1u << 16)
|
||||
#define HSI2C_TIMEOUT_AUTO (1u << 4)
|
||||
#define HSI2C_NO_DEV (1u << 3)
|
||||
#define HSI2C_NO_DEV_ACK (1u << 2)
|
||||
#define HSI2C_TRANS_ABORT (1u << 1)
|
||||
#define HSI2C_TRANS_DONE (1u << 0)
|
||||
|
||||
/* I2C_ADDR register bits */
|
||||
#define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0)
|
||||
#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
|
||||
#define HSI2C_MASTER_ID(x) ((x & 0xff) << 24)
|
||||
#define MASTER_ID(x) ((x & 0x7) + 0x08)
|
||||
|
||||
/*
|
||||
* Controller operating frequency, timing values for operation
|
||||
* are calculated against this frequency
|
||||
*/
|
||||
#define HSI2C_HS_TX_CLOCK 1000000
|
||||
#define HSI2C_FS_TX_CLOCK 100000
|
||||
#define HSI2C_HIGH_SPD 1
|
||||
#define HSI2C_FAST_SPD 0
|
||||
|
||||
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
struct exynos5_i2c {
|
||||
struct i2c_adapter adap;
|
||||
unsigned int suspended:1;
|
||||
|
||||
struct i2c_msg *msg;
|
||||
struct completion msg_complete;
|
||||
unsigned int msg_ptr;
|
||||
|
||||
unsigned int irq;
|
||||
|
||||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
int state;
|
||||
|
||||
spinlock_t lock; /* IRQ synchronization */
|
||||
|
||||
/*
|
||||
* Since the TRANS_DONE bit is cleared on read, and we may read it
|
||||
* either during an IRQ or after a transaction, keep track of its
|
||||
* state here.
|
||||
*/
|
||||
int trans_done;
|
||||
|
||||
/* Controller operating frequency */
|
||||
unsigned int fs_clock;
|
||||
unsigned int hs_clock;
|
||||
|
||||
/*
|
||||
* HSI2C Controller can operate in
|
||||
* 1. High speed upto 3.4Mbps
|
||||
* 2. Fast speed upto 1Mbps
|
||||
*/
|
||||
int speed_mode;
|
||||
};
|
||||
|
||||
static const struct of_device_id exynos5_i2c_match[] = {
|
||||
{ .compatible = "samsung,exynos5-hsi2c" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
|
||||
|
||||
static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
|
||||
{
|
||||
writel(readl(i2c->regs + HSI2C_INT_STATUS),
|
||||
i2c->regs + HSI2C_INT_STATUS);
|
||||
}
|
||||
|
||||
/*
|
||||
* exynos5_i2c_set_timing: updates the registers with appropriate
|
||||
* timing values calculated
|
||||
*
|
||||
* Returns 0 on success, -EINVAL if the cycle length cannot
|
||||
* be calculated.
|
||||
*/
|
||||
static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
|
||||
{
|
||||
u32 i2c_timing_s1;
|
||||
u32 i2c_timing_s2;
|
||||
u32 i2c_timing_s3;
|
||||
u32 i2c_timing_sla;
|
||||
unsigned int t_start_su, t_start_hd;
|
||||
unsigned int t_stop_su;
|
||||
unsigned int t_data_su, t_data_hd;
|
||||
unsigned int t_scl_l, t_scl_h;
|
||||
unsigned int t_sr_release;
|
||||
unsigned int t_ftl_cycle;
|
||||
unsigned int clkin = clk_get_rate(i2c->clk);
|
||||
unsigned int div, utemp0 = 0, utemp1 = 0, clk_cycle;
|
||||
unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ?
|
||||
i2c->hs_clock : i2c->fs_clock;
|
||||
|
||||
/*
|
||||
* FPCLK / FI2C =
|
||||
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
|
||||
* utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
|
||||
* utemp1 = (TSCLK_L + TSCLK_H + 2)
|
||||
*/
|
||||
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
|
||||
utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle;
|
||||
|
||||
/* CLK_DIV max is 256 */
|
||||
for (div = 0; div < 256; div++) {
|
||||
utemp1 = utemp0 / (div + 1);
|
||||
|
||||
/*
|
||||
* SCL_L and SCL_H each has max value of 255
|
||||
* Hence, For the clk_cycle to the have right value
|
||||
* utemp1 has to be less then 512 and more than 4.
|
||||
*/
|
||||
if ((utemp1 < 512) && (utemp1 > 4)) {
|
||||
clk_cycle = utemp1 - 2;
|
||||
break;
|
||||
} else if (div == 255) {
|
||||
dev_warn(i2c->dev, "Failed to calculate divisor");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
t_scl_l = clk_cycle / 2;
|
||||
t_scl_h = clk_cycle / 2;
|
||||
t_start_su = t_scl_l;
|
||||
t_start_hd = t_scl_l;
|
||||
t_stop_su = t_scl_l;
|
||||
t_data_su = t_scl_l / 2;
|
||||
t_data_hd = t_scl_l / 2;
|
||||
t_sr_release = clk_cycle;
|
||||
|
||||
i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8;
|
||||
i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0;
|
||||
i2c_timing_s3 = div << 16 | t_sr_release << 0;
|
||||
i2c_timing_sla = t_data_hd << 0;
|
||||
|
||||
dev_dbg(i2c->dev, "tSTART_SU: %X, tSTART_HD: %X, tSTOP_SU: %X\n",
|
||||
t_start_su, t_start_hd, t_stop_su);
|
||||
dev_dbg(i2c->dev, "tDATA_SU: %X, tSCL_L: %X, tSCL_H: %X\n",
|
||||
t_data_su, t_scl_l, t_scl_h);
|
||||
dev_dbg(i2c->dev, "nClkDiv: %X, tSR_RELEASE: %X\n",
|
||||
div, t_sr_release);
|
||||
dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd);
|
||||
|
||||
if (mode == HSI2C_HIGH_SPD) {
|
||||
writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1);
|
||||
writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2);
|
||||
writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3);
|
||||
} else {
|
||||
writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_FS1);
|
||||
writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_FS2);
|
||||
writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3);
|
||||
}
|
||||
writel(i2c_timing_sla, i2c->regs + HSI2C_TIMING_SLA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c)
|
||||
{
|
||||
/*
|
||||
* Configure the Fast speed timing values
|
||||
* Even the High Speed mode initially starts with Fast mode
|
||||
*/
|
||||
if (exynos5_i2c_set_timing(i2c, HSI2C_FAST_SPD)) {
|
||||
dev_err(i2c->dev, "HSI2C FS Clock set up failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* configure the High speed timing values */
|
||||
if (i2c->speed_mode == HSI2C_HIGH_SPD) {
|
||||
if (exynos5_i2c_set_timing(i2c, HSI2C_HIGH_SPD)) {
|
||||
dev_err(i2c->dev, "HSI2C HS Clock set up failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* exynos5_i2c_init: configures the controller for I2C functionality
|
||||
* Programs I2C controller for Master mode operation
|
||||
*/
|
||||
static void exynos5_i2c_init(struct exynos5_i2c *i2c)
|
||||
{
|
||||
u32 i2c_conf = readl(i2c->regs + HSI2C_CONF);
|
||||
u32 i2c_timeout = readl(i2c->regs + HSI2C_TIMEOUT);
|
||||
|
||||
/* Clear to disable Timeout */
|
||||
i2c_timeout &= ~HSI2C_TIMEOUT_EN;
|
||||
writel(i2c_timeout, i2c->regs + HSI2C_TIMEOUT);
|
||||
|
||||
writel((HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
|
||||
i2c->regs + HSI2C_CTL);
|
||||
writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL);
|
||||
|
||||
if (i2c->speed_mode == HSI2C_HIGH_SPD) {
|
||||
writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)),
|
||||
i2c->regs + HSI2C_ADDR);
|
||||
i2c_conf |= HSI2C_HS_MODE;
|
||||
}
|
||||
|
||||
writel(i2c_conf | HSI2C_AUTO_MODE, i2c->regs + HSI2C_CONF);
|
||||
}
|
||||
|
||||
static void exynos5_i2c_reset(struct exynos5_i2c *i2c)
|
||||
{
|
||||
u32 i2c_ctl;
|
||||
|
||||
/* Set and clear the bit for reset */
|
||||
i2c_ctl = readl(i2c->regs + HSI2C_CTL);
|
||||
i2c_ctl |= HSI2C_SW_RST;
|
||||
writel(i2c_ctl, i2c->regs + HSI2C_CTL);
|
||||
|
||||
i2c_ctl = readl(i2c->regs + HSI2C_CTL);
|
||||
i2c_ctl &= ~HSI2C_SW_RST;
|
||||
writel(i2c_ctl, i2c->regs + HSI2C_CTL);
|
||||
|
||||
/* We don't expect calculations to fail during the run */
|
||||
exynos5_hsi2c_clock_setup(i2c);
|
||||
/* Initialize the configure registers */
|
||||
exynos5_i2c_init(i2c);
|
||||
}
|
||||
|
||||
/*
|
||||
* exynos5_i2c_irq: top level IRQ servicing routine
|
||||
*
|
||||
* INT_STATUS registers gives the interrupt details. Further,
|
||||
* FIFO_STATUS or TRANS_STATUS registers are to be check for detailed
|
||||
* state of the bus.
|
||||
*/
|
||||
static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
|
||||
{
|
||||
struct exynos5_i2c *i2c = dev_id;
|
||||
u32 fifo_level, int_status, fifo_status, trans_status;
|
||||
unsigned char byte;
|
||||
int len = 0;
|
||||
|
||||
i2c->state = -EINVAL;
|
||||
|
||||
spin_lock(&i2c->lock);
|
||||
|
||||
int_status = readl(i2c->regs + HSI2C_INT_STATUS);
|
||||
writel(int_status, i2c->regs + HSI2C_INT_STATUS);
|
||||
fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
|
||||
|
||||
/* handle interrupt related to the transfer status */
|
||||
if (int_status & HSI2C_INT_I2C) {
|
||||
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
|
||||
if (trans_status & HSI2C_NO_DEV_ACK) {
|
||||
dev_dbg(i2c->dev, "No ACK from device\n");
|
||||
i2c->state = -ENXIO;
|
||||
goto stop;
|
||||
} else if (trans_status & HSI2C_NO_DEV) {
|
||||
dev_dbg(i2c->dev, "No device\n");
|
||||
i2c->state = -ENXIO;
|
||||
goto stop;
|
||||
} else if (trans_status & HSI2C_TRANS_ABORT) {
|
||||
dev_dbg(i2c->dev, "Deal with arbitration lose\n");
|
||||
i2c->state = -EAGAIN;
|
||||
goto stop;
|
||||
} else if (trans_status & HSI2C_TIMEOUT_AUTO) {
|
||||
dev_dbg(i2c->dev, "Accessing device timed out\n");
|
||||
i2c->state = -EAGAIN;
|
||||
goto stop;
|
||||
} else if (trans_status & HSI2C_TRANS_DONE) {
|
||||
i2c->trans_done = 1;
|
||||
i2c->state = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((i2c->msg->flags & I2C_M_RD) && (int_status &
|
||||
(HSI2C_INT_TRAILING | HSI2C_INT_RX_ALMOSTFULL))) {
|
||||
fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
|
||||
fifo_level = HSI2C_RX_FIFO_LVL(fifo_status);
|
||||
len = min(fifo_level, i2c->msg->len - i2c->msg_ptr);
|
||||
|
||||
while (len > 0) {
|
||||
byte = (unsigned char)
|
||||
readl(i2c->regs + HSI2C_RX_DATA);
|
||||
i2c->msg->buf[i2c->msg_ptr++] = byte;
|
||||
len--;
|
||||
}
|
||||
i2c->state = 0;
|
||||
} else if (int_status & HSI2C_INT_TX_ALMOSTEMPTY) {
|
||||
fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
|
||||
fifo_level = HSI2C_TX_FIFO_LVL(fifo_status);
|
||||
|
||||
len = HSI2C_FIFO_MAX - fifo_level;
|
||||
if (len > (i2c->msg->len - i2c->msg_ptr))
|
||||
len = i2c->msg->len - i2c->msg_ptr;
|
||||
|
||||
while (len > 0) {
|
||||
byte = i2c->msg->buf[i2c->msg_ptr++];
|
||||
writel(byte, i2c->regs + HSI2C_TX_DATA);
|
||||
len--;
|
||||
}
|
||||
i2c->state = 0;
|
||||
}
|
||||
|
||||
stop:
|
||||
if ((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) ||
|
||||
(i2c->state < 0)) {
|
||||
writel(0, i2c->regs + HSI2C_INT_ENABLE);
|
||||
exynos5_i2c_clr_pend_irq(i2c);
|
||||
complete(&i2c->msg_complete);
|
||||
}
|
||||
|
||||
spin_unlock(&i2c->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* exynos5_i2c_wait_bus_idle
|
||||
*
|
||||
* Wait for the bus to go idle, indicated by the MASTER_BUSY bit being
|
||||
* cleared.
|
||||
*
|
||||
* Returns -EBUSY if the bus cannot be bought to idle
|
||||
*/
|
||||
static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c)
|
||||
{
|
||||
unsigned long stop_time;
|
||||
u32 trans_status;
|
||||
|
||||
/* wait for 100 milli seconds for the bus to be idle */
|
||||
stop_time = jiffies + msecs_to_jiffies(100) + 1;
|
||||
do {
|
||||
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
|
||||
if (!(trans_status & HSI2C_MASTER_BUSY))
|
||||
return 0;
|
||||
|
||||
usleep_range(50, 200);
|
||||
} while (time_before(jiffies, stop_time));
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* exynos5_i2c_message_start: Configures the bus and starts the xfer
|
||||
* i2c: struct exynos5_i2c pointer for the current bus
|
||||
* stop: Enables stop after transfer if set. Set for last transfer of
|
||||
* in the list of messages.
|
||||
*
|
||||
* Configures the bus for read/write function
|
||||
* Sets chip address to talk to, message length to be sent.
|
||||
* Enables appropriate interrupts and sends start xfer command.
|
||||
*/
|
||||
static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
|
||||
{
|
||||
u32 i2c_ctl;
|
||||
u32 int_en = HSI2C_INT_I2C_EN;
|
||||
u32 i2c_auto_conf = 0;
|
||||
u32 fifo_ctl;
|
||||
unsigned long flags;
|
||||
|
||||
i2c_ctl = readl(i2c->regs + HSI2C_CTL);
|
||||
i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON);
|
||||
fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN;
|
||||
|
||||
if (i2c->msg->flags & I2C_M_RD) {
|
||||
i2c_ctl |= HSI2C_RXCHON;
|
||||
|
||||
i2c_auto_conf = HSI2C_READ_WRITE;
|
||||
|
||||
fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL);
|
||||
int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN |
|
||||
HSI2C_INT_TRAILING_EN);
|
||||
} else {
|
||||
i2c_ctl |= HSI2C_TXCHON;
|
||||
|
||||
fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL);
|
||||
int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN;
|
||||
}
|
||||
|
||||
writel(HSI2C_SLV_ADDR_MAS(i2c->msg->addr), i2c->regs + HSI2C_ADDR);
|
||||
|
||||
writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL);
|
||||
writel(i2c_ctl, i2c->regs + HSI2C_CTL);
|
||||
|
||||
|
||||
/*
|
||||
* Enable interrupts before starting the transfer so that we don't
|
||||
* miss any INT_I2C interrupts.
|
||||
*/
|
||||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
writel(int_en, i2c->regs + HSI2C_INT_ENABLE);
|
||||
|
||||
if (stop == 1)
|
||||
i2c_auto_conf |= HSI2C_STOP_AFTER_TRANS;
|
||||
i2c_auto_conf |= i2c->msg->len;
|
||||
i2c_auto_conf |= HSI2C_MASTER_RUN;
|
||||
writel(i2c_auto_conf, i2c->regs + HSI2C_AUTO_CONF);
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
}
|
||||
|
||||
static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
|
||||
struct i2c_msg *msgs, int stop)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
i2c->msg = msgs;
|
||||
i2c->msg_ptr = 0;
|
||||
i2c->trans_done = 0;
|
||||
|
||||
reinit_completion(&i2c->msg_complete);
|
||||
|
||||
exynos5_i2c_message_start(i2c, stop);
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c->msg_complete,
|
||||
EXYNOS5_I2C_TIMEOUT);
|
||||
if (timeout == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
ret = i2c->state;
|
||||
|
||||
/*
|
||||
* If this is the last message to be transfered (stop == 1)
|
||||
* Then check if the bus can be brought back to idle.
|
||||
*/
|
||||
if (ret == 0 && stop)
|
||||
ret = exynos5_i2c_wait_bus_idle(i2c);
|
||||
|
||||
if (ret < 0) {
|
||||
exynos5_i2c_reset(i2c);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_warn(i2c->dev, "%s timeout\n",
|
||||
(msgs->flags & I2C_M_RD) ? "rx" : "tx");
|
||||
}
|
||||
|
||||
/* Return the state as in interrupt routine */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos5_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data;
|
||||
int i = 0, ret = 0, stop = 0;
|
||||
|
||||
if (i2c->suspended) {
|
||||
dev_err(i2c->dev, "HS-I2C is not initialzed.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
clk_prepare_enable(i2c->clk);
|
||||
|
||||
for (i = 0; i < num; i++, msgs++) {
|
||||
stop = (i == num - 1);
|
||||
|
||||
ret = exynos5_i2c_xfer_msg(i2c, msgs, stop);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (i == num) {
|
||||
ret = num;
|
||||
} else {
|
||||
/* Only one message, cannot access the device */
|
||||
if (i == 1)
|
||||
ret = -EREMOTEIO;
|
||||
else
|
||||
ret = i;
|
||||
|
||||
dev_warn(i2c->dev, "xfer message failed\n");
|
||||
}
|
||||
|
||||
out:
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 exynos5_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm exynos5_i2c_algorithm = {
|
||||
.master_xfer = exynos5_i2c_xfer,
|
||||
.functionality = exynos5_i2c_func,
|
||||
};
|
||||
|
||||
static int exynos5_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct exynos5_i2c *i2c;
|
||||
struct resource *mem;
|
||||
unsigned int op_clock;
|
||||
int ret;
|
||||
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
|
||||
if (!i2c) {
|
||||
dev_err(&pdev->dev, "no memory for state\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &op_clock)) {
|
||||
i2c->speed_mode = HSI2C_FAST_SPD;
|
||||
i2c->fs_clock = HSI2C_FS_TX_CLOCK;
|
||||
} else {
|
||||
if (op_clock >= HSI2C_HS_TX_CLOCK) {
|
||||
i2c->speed_mode = HSI2C_HIGH_SPD;
|
||||
i2c->fs_clock = HSI2C_FS_TX_CLOCK;
|
||||
i2c->hs_clock = op_clock;
|
||||
} else {
|
||||
i2c->speed_mode = HSI2C_FAST_SPD;
|
||||
i2c->fs_clock = op_clock;
|
||||
}
|
||||
}
|
||||
|
||||
strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name));
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &exynos5_i2c_algorithm;
|
||||
i2c->adap.retries = 3;
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
i2c->clk = devm_clk_get(&pdev->dev, "hsi2c");
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
dev_err(&pdev->dev, "cannot get clock\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
clk_prepare_enable(i2c->clk);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(i2c->regs)) {
|
||||
ret = PTR_ERR(i2c->regs);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
i2c->adap.dev.of_node = np;
|
||||
i2c->adap.algo_data = i2c;
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
|
||||
/* Clear pending interrupts from u-boot or misc causes */
|
||||
exynos5_i2c_clr_pend_irq(i2c);
|
||||
|
||||
spin_lock_init(&i2c->lock);
|
||||
init_completion(&i2c->msg_complete);
|
||||
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
|
||||
ret = -EINVAL;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), i2c);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", i2c->irq);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = exynos5_hsi2c_clock_setup(i2c);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
exynos5_i2c_init(i2c);
|
||||
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos5_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5_i2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c->suspended = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
|
||||
int ret = 0;
|
||||
|
||||
clk_prepare_enable(i2c->clk);
|
||||
|
||||
ret = exynos5_hsi2c_clock_setup(i2c);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos5_i2c_init(i2c);
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
i2c->suspended = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq,
|
||||
exynos5_i2c_resume_noirq);
|
||||
|
||||
static struct platform_driver exynos5_i2c_driver = {
|
||||
.probe = exynos5_i2c_probe,
|
||||
.remove = exynos5_i2c_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "exynos5-hsi2c",
|
||||
.pm = &exynos5_i2c_dev_pm_ops,
|
||||
.of_match_table = exynos5_i2c_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(exynos5_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Exynos5 HS-I2C Bus driver");
|
||||
MODULE_AUTHOR("Naveen Krishna Chatradhi, <ch.naveen@samsung.com>");
|
||||
MODULE_AUTHOR("Taekgyun Ko, <taeggyun.ko@samsung.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
struct i2c_gpio_private_data {
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes
|
||||
Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
|
||||
Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
|
||||
Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
|
||||
|
||||
Features supported by this driver:
|
||||
Software PEC no
|
||||
|
@ -177,6 +178,7 @@
|
|||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
|
||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
|
||||
|
||||
struct i801_mux_config {
|
||||
char *gpio_chip;
|
||||
|
@ -819,6 +821,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
|
|
@ -911,7 +911,7 @@ static struct platform_driver mv64xxx_i2c_driver = {
|
|||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = MV64XXX_I2C_CTLR_NAME,
|
||||
.of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table),
|
||||
.of_match_table = mv64xxx_i2c_of_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Freescale MXS I2C bus driver
|
||||
*
|
||||
* Copyright (C) 2012-2013 Marek Vasut <marex@denx.de>
|
||||
* Copyright (C) 2011-2012 Wolfram Sang, Pengutronix e.K.
|
||||
*
|
||||
* based on a (non-working) driver which was:
|
||||
|
@ -34,10 +35,12 @@
|
|||
|
||||
#define MXS_I2C_CTRL0 (0x00)
|
||||
#define MXS_I2C_CTRL0_SET (0x04)
|
||||
#define MXS_I2C_CTRL0_CLR (0x08)
|
||||
|
||||
#define MXS_I2C_CTRL0_SFTRST 0x80000000
|
||||
#define MXS_I2C_CTRL0_RUN 0x20000000
|
||||
#define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000
|
||||
#define MXS_I2C_CTRL0_PIO_MODE 0x01000000
|
||||
#define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000
|
||||
#define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000
|
||||
#define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000
|
||||
|
@ -64,13 +67,13 @@
|
|||
#define MXS_I2C_CTRL1_SLAVE_IRQ 0x01
|
||||
|
||||
#define MXS_I2C_STAT (0x50)
|
||||
#define MXS_I2C_STAT_GOT_A_NAK 0x10000000
|
||||
#define MXS_I2C_STAT_BUS_BUSY 0x00000800
|
||||
#define MXS_I2C_STAT_CLK_GEN_BUSY 0x00000400
|
||||
|
||||
#define MXS_I2C_DATA (0xa0)
|
||||
#define MXS_I2C_DATA(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x60 : 0xa0)
|
||||
|
||||
#define MXS_I2C_DEBUG0 (0xb0)
|
||||
#define MXS_I2C_DEBUG0_CLR (0xb8)
|
||||
#define MXS_I2C_DEBUG0_CLR(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x78 : 0xb8)
|
||||
|
||||
#define MXS_I2C_DEBUG0_DMAREQ 0x80000000
|
||||
|
||||
|
@ -95,10 +98,17 @@
|
|||
#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
|
||||
MXS_I2C_CTRL0_MASTER_MODE)
|
||||
|
||||
enum mxs_i2c_devtype {
|
||||
MXS_I2C_UNKNOWN = 0,
|
||||
MXS_I2C_V1,
|
||||
MXS_I2C_V2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mxs_i2c_dev - per device, private MXS-I2C data
|
||||
*
|
||||
* @dev: driver model device node
|
||||
* @dev_type: distinguish i.MX23/i.MX28 features
|
||||
* @regs: IO registers pointer
|
||||
* @cmd_complete: completion object for transaction wait
|
||||
* @cmd_err: error code for last transaction
|
||||
|
@ -106,6 +116,7 @@
|
|||
*/
|
||||
struct mxs_i2c_dev {
|
||||
struct device *dev;
|
||||
enum mxs_i2c_devtype dev_type;
|
||||
void __iomem *regs;
|
||||
struct completion cmd_complete;
|
||||
int cmd_err;
|
||||
|
@ -291,48 +302,11 @@ write_init_pio_fail:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mxs_i2c_pio_wait_dmareq(struct mxs_i2c_dev *i2c)
|
||||
static int mxs_i2c_pio_wait_xfer_end(struct mxs_i2c_dev *i2c)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
|
||||
|
||||
while (!(readl(i2c->regs + MXS_I2C_DEBUG0) &
|
||||
MXS_I2C_DEBUG0_DMAREQ)) {
|
||||
if (time_after(jiffies, timeout))
|
||||
return -ETIMEDOUT;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c, int last)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
|
||||
|
||||
/*
|
||||
* We do not use interrupts in the PIO mode. Due to the
|
||||
* maximum transfer length being 8 bytes in PIO mode, the
|
||||
* overhead of interrupt would be too large and this would
|
||||
* neglect the gain from using the PIO mode.
|
||||
*/
|
||||
|
||||
while (!(readl(i2c->regs + MXS_I2C_CTRL1) &
|
||||
MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ)) {
|
||||
if (time_after(jiffies, timeout))
|
||||
return -ETIMEDOUT;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
writel(MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ,
|
||||
i2c->regs + MXS_I2C_CTRL1_CLR);
|
||||
|
||||
/*
|
||||
* When ending a transfer with a stop, we have to wait for the bus to
|
||||
* go idle before we report the transfer as completed. Otherwise the
|
||||
* start of the next transfer may race with the end of the current one.
|
||||
*/
|
||||
while (last && (readl(i2c->regs + MXS_I2C_STAT) &
|
||||
(MXS_I2C_STAT_BUS_BUSY | MXS_I2C_STAT_CLK_GEN_BUSY))) {
|
||||
while (readl(i2c->regs + MXS_I2C_CTRL0) & MXS_I2C_CTRL0_RUN) {
|
||||
if (time_after(jiffies, timeout))
|
||||
return -ETIMEDOUT;
|
||||
cond_resched();
|
||||
|
@ -370,106 +344,215 @@ static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd)
|
|||
writel(reg, i2c->regs + MXS_I2C_CTRL0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start WRITE transaction on the I2C bus. By studying i.MX23 datasheet,
|
||||
* CTRL0::PIO_MODE bit description clarifies the order in which the registers
|
||||
* must be written during PIO mode operation. First, the CTRL0 register has
|
||||
* to be programmed with all the necessary bits but the RUN bit. Then the
|
||||
* payload has to be written into the DATA register. Finally, the transmission
|
||||
* is executed by setting the RUN bit in CTRL0.
|
||||
*/
|
||||
static void mxs_i2c_pio_trigger_write_cmd(struct mxs_i2c_dev *i2c, u32 cmd,
|
||||
u32 data)
|
||||
{
|
||||
writel(cmd, i2c->regs + MXS_I2C_CTRL0);
|
||||
|
||||
if (i2c->dev_type == MXS_I2C_V1)
|
||||
writel(MXS_I2C_CTRL0_PIO_MODE, i2c->regs + MXS_I2C_CTRL0_SET);
|
||||
|
||||
writel(data, i2c->regs + MXS_I2C_DATA(i2c));
|
||||
writel(MXS_I2C_CTRL0_RUN, i2c->regs + MXS_I2C_CTRL0_SET);
|
||||
}
|
||||
|
||||
static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, uint32_t flags)
|
||||
{
|
||||
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
|
||||
uint32_t addr_data = msg->addr << 1;
|
||||
uint32_t data = 0;
|
||||
int i, shifts_left, ret;
|
||||
int i, ret, xlen = 0, xmit = 0;
|
||||
uint32_t start;
|
||||
|
||||
/* Mute IRQs coming from this block. */
|
||||
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_CLR);
|
||||
|
||||
/*
|
||||
* MX23 idea:
|
||||
* - Enable CTRL0::PIO_MODE (1 << 24)
|
||||
* - Enable CTRL1::ACK_MODE (1 << 27)
|
||||
*
|
||||
* WARNING! The MX23 is broken in some way, even if it claims
|
||||
* to support PIO, when we try to transfer any amount of data
|
||||
* that is not aligned to 4 bytes, the DMA engine will have
|
||||
* bits in DEBUG1::DMA_BYTES_ENABLES still set even after the
|
||||
* transfer. This in turn will mess up the next transfer as
|
||||
* the block it emit one byte write onto the bus terminated
|
||||
* with a NAK+STOP. A possible workaround is to reset the IP
|
||||
* block after every PIO transmission, which might just work.
|
||||
*
|
||||
* NOTE: The CTRL0::PIO_MODE description is important, since
|
||||
* it outlines how the PIO mode is really supposed to work.
|
||||
*/
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
/*
|
||||
* PIO READ transfer:
|
||||
*
|
||||
* This transfer MUST be limited to 4 bytes maximum. It is not
|
||||
* possible to transfer more than four bytes via PIO, since we
|
||||
* can not in any way make sure we can read the data from the
|
||||
* DATA register fast enough. Besides, the RX FIFO is only four
|
||||
* bytes deep, thus we can only really read up to four bytes at
|
||||
* time. Finally, there is no bit indicating us that new data
|
||||
* arrived at the FIFO and can thus be fetched from the DATA
|
||||
* register.
|
||||
*/
|
||||
BUG_ON(msg->len > 4);
|
||||
|
||||
addr_data |= I2C_SMBUS_READ;
|
||||
|
||||
/* SELECT command. */
|
||||
mxs_i2c_pio_trigger_cmd(i2c, MXS_CMD_I2C_SELECT);
|
||||
mxs_i2c_pio_trigger_write_cmd(i2c, MXS_CMD_I2C_SELECT,
|
||||
addr_data);
|
||||
|
||||
ret = mxs_i2c_pio_wait_dmareq(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(addr_data, i2c->regs + MXS_I2C_DATA);
|
||||
writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR);
|
||||
|
||||
ret = mxs_i2c_pio_wait_cplt(i2c, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (mxs_i2c_pio_check_error_state(i2c))
|
||||
ret = mxs_i2c_pio_wait_xfer_end(i2c);
|
||||
if (ret) {
|
||||
dev_err(i2c->dev,
|
||||
"PIO: Failed to send SELECT command!\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* READ command. */
|
||||
mxs_i2c_pio_trigger_cmd(i2c,
|
||||
MXS_CMD_I2C_READ | flags |
|
||||
MXS_I2C_CTRL0_XFER_COUNT(msg->len));
|
||||
|
||||
ret = mxs_i2c_pio_wait_xfer_end(i2c);
|
||||
if (ret) {
|
||||
dev_err(i2c->dev,
|
||||
"PIO: Failed to send SELECT command!\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
data = readl(i2c->regs + MXS_I2C_DATA(i2c));
|
||||
for (i = 0; i < msg->len; i++) {
|
||||
if ((i & 3) == 0) {
|
||||
ret = mxs_i2c_pio_wait_dmareq(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
data = readl(i2c->regs + MXS_I2C_DATA);
|
||||
writel(MXS_I2C_DEBUG0_DMAREQ,
|
||||
i2c->regs + MXS_I2C_DEBUG0_CLR);
|
||||
}
|
||||
msg->buf[i] = data & 0xff;
|
||||
data >>= 8;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* PIO WRITE transfer:
|
||||
*
|
||||
* The code below implements clock stretching to circumvent
|
||||
* the possibility of kernel not being able to supply data
|
||||
* fast enough. It is possible to transfer arbitrary amount
|
||||
* of data using PIO write.
|
||||
*/
|
||||
addr_data |= I2C_SMBUS_WRITE;
|
||||
|
||||
/* WRITE command. */
|
||||
mxs_i2c_pio_trigger_cmd(i2c,
|
||||
MXS_CMD_I2C_WRITE | flags |
|
||||
MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1));
|
||||
|
||||
/*
|
||||
* The LSB of data buffer is the first byte blasted across
|
||||
* the bus. Higher order bytes follow. Thus the following
|
||||
* filling schematic.
|
||||
*/
|
||||
|
||||
data = addr_data << 24;
|
||||
|
||||
/* Start the transfer with START condition. */
|
||||
start = MXS_I2C_CTRL0_PRE_SEND_START;
|
||||
|
||||
/* If the transfer is long, use clock stretching. */
|
||||
if (msg->len > 3)
|
||||
start |= MXS_I2C_CTRL0_RETAIN_CLOCK;
|
||||
|
||||
for (i = 0; i < msg->len; i++) {
|
||||
data >>= 8;
|
||||
data |= (msg->buf[i] << 24);
|
||||
if ((i & 3) == 2) {
|
||||
ret = mxs_i2c_pio_wait_dmareq(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
writel(data, i2c->regs + MXS_I2C_DATA);
|
||||
writel(MXS_I2C_DEBUG0_DMAREQ,
|
||||
i2c->regs + MXS_I2C_DEBUG0_CLR);
|
||||
}
|
||||
}
|
||||
|
||||
shifts_left = 24 - (i & 3) * 8;
|
||||
if (shifts_left) {
|
||||
data >>= shifts_left;
|
||||
ret = mxs_i2c_pio_wait_dmareq(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
writel(data, i2c->regs + MXS_I2C_DATA);
|
||||
xmit = 0;
|
||||
|
||||
/* This is the last transfer of the message. */
|
||||
if (i + 1 == msg->len) {
|
||||
/* Add optional STOP flag. */
|
||||
start |= flags;
|
||||
/* Remove RETAIN_CLOCK bit. */
|
||||
start &= ~MXS_I2C_CTRL0_RETAIN_CLOCK;
|
||||
xmit = 1;
|
||||
}
|
||||
|
||||
/* Four bytes are ready in the "data" variable. */
|
||||
if ((i & 3) == 2)
|
||||
xmit = 1;
|
||||
|
||||
/* Nothing interesting happened, continue stuffing. */
|
||||
if (!xmit)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Compute the size of the transfer and shift the
|
||||
* data accordingly.
|
||||
*
|
||||
* i = (4k + 0) .... xlen = 2
|
||||
* i = (4k + 1) .... xlen = 3
|
||||
* i = (4k + 2) .... xlen = 4
|
||||
* i = (4k + 3) .... xlen = 1
|
||||
*/
|
||||
|
||||
if ((i % 4) == 3)
|
||||
xlen = 1;
|
||||
else
|
||||
xlen = (i % 4) + 2;
|
||||
|
||||
data >>= (4 - xlen) * 8;
|
||||
|
||||
dev_dbg(i2c->dev,
|
||||
"PIO: len=%i pos=%i total=%i [W%s%s%s]\n",
|
||||
xlen, i, msg->len,
|
||||
start & MXS_I2C_CTRL0_PRE_SEND_START ? "S" : "",
|
||||
start & MXS_I2C_CTRL0_POST_SEND_STOP ? "E" : "",
|
||||
start & MXS_I2C_CTRL0_RETAIN_CLOCK ? "C" : "");
|
||||
|
||||
writel(MXS_I2C_DEBUG0_DMAREQ,
|
||||
i2c->regs + MXS_I2C_DEBUG0_CLR);
|
||||
i2c->regs + MXS_I2C_DEBUG0_CLR(i2c));
|
||||
|
||||
mxs_i2c_pio_trigger_write_cmd(i2c,
|
||||
start | MXS_I2C_CTRL0_MASTER_MODE |
|
||||
MXS_I2C_CTRL0_DIRECTION |
|
||||
MXS_I2C_CTRL0_XFER_COUNT(xlen), data);
|
||||
|
||||
/* The START condition is sent only once. */
|
||||
start &= ~MXS_I2C_CTRL0_PRE_SEND_START;
|
||||
|
||||
/* Wait for the end of the transfer. */
|
||||
ret = mxs_i2c_pio_wait_xfer_end(i2c);
|
||||
if (ret) {
|
||||
dev_err(i2c->dev,
|
||||
"PIO: Failed to finish WRITE cmd!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check NAK here. */
|
||||
ret = readl(i2c->regs + MXS_I2C_STAT) &
|
||||
MXS_I2C_STAT_GOT_A_NAK;
|
||||
if (ret) {
|
||||
ret = -ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = mxs_i2c_pio_wait_cplt(i2c, flags & MXS_I2C_CTRL0_POST_SEND_STOP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* make sure we capture any occurred error into cmd_err */
|
||||
mxs_i2c_pio_check_error_state(i2c);
|
||||
ret = mxs_i2c_pio_check_error_state(i2c);
|
||||
|
||||
cleanup:
|
||||
/* Clear any dangling IRQs and re-enable interrupts. */
|
||||
writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR);
|
||||
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
|
||||
|
||||
return 0;
|
||||
/* Clear the PIO_MODE on i.MX23 */
|
||||
if (i2c->dev_type == MXS_I2C_V1)
|
||||
writel(MXS_I2C_CTRL0_PIO_MODE, i2c->regs + MXS_I2C_CTRL0_CLR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -479,8 +562,9 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
|||
int stop)
|
||||
{
|
||||
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
|
||||
int ret, err;
|
||||
int ret;
|
||||
int flags;
|
||||
int use_pio = 0;
|
||||
|
||||
flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
|
||||
|
||||
|
@ -491,19 +575,21 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
|||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* The current boundary to select between PIO/DMA transfer method
|
||||
* is set to 8 bytes, transfers shorter than 8 bytes are transfered
|
||||
* using PIO mode while longer transfers use DMA. The 8 byte border is
|
||||
* based on this empirical measurement and a lot of previous frobbing.
|
||||
* The MX28 I2C IP block can only do PIO READ for transfer of to up
|
||||
* 4 bytes of length. The write transfer is not limited as it can use
|
||||
* clock stretching to avoid FIFO underruns.
|
||||
*/
|
||||
if ((msg->flags & I2C_M_RD) && (msg->len <= 4))
|
||||
use_pio = 1;
|
||||
if (!(msg->flags & I2C_M_RD) && (msg->len < 7))
|
||||
use_pio = 1;
|
||||
|
||||
i2c->cmd_err = 0;
|
||||
if (0) { /* disable PIO mode until a proper fix is made */
|
||||
if (use_pio) {
|
||||
ret = mxs_i2c_pio_setup_xfer(adap, msg, flags);
|
||||
if (ret) {
|
||||
err = mxs_i2c_reset(i2c);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
/* No need to reset the block if NAK was received. */
|
||||
if (ret && (ret != -ENXIO))
|
||||
mxs_i2c_reset(i2c);
|
||||
} else {
|
||||
reinit_completion(&i2c->cmd_complete);
|
||||
ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
|
||||
|
@ -514,9 +600,11 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
|||
msecs_to_jiffies(1000));
|
||||
if (ret == 0)
|
||||
goto timeout;
|
||||
|
||||
ret = i2c->cmd_err;
|
||||
}
|
||||
|
||||
if (i2c->cmd_err == -ENXIO) {
|
||||
if (ret == -ENXIO) {
|
||||
/*
|
||||
* If the transfer fails with a NAK from the slave the
|
||||
* controller halts until it gets told to return to idle state.
|
||||
|
@ -525,7 +613,19 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
|||
i2c->regs + MXS_I2C_CTRL1_SET);
|
||||
}
|
||||
|
||||
ret = i2c->cmd_err;
|
||||
/*
|
||||
* WARNING!
|
||||
* The i.MX23 is strange. After each and every operation, it's I2C IP
|
||||
* block must be reset, otherwise the IP block will misbehave. This can
|
||||
* be observed on the bus by the block sending out one single byte onto
|
||||
* the bus. In case such an error happens, bit 27 will be set in the
|
||||
* DEBUG0 register. This bit is not documented in the i.MX23 datasheet
|
||||
* and is marked as "TBD" instead. To reset this bit to a correct state,
|
||||
* reset the whole block. Since the block reset does not take long, do
|
||||
* reset the block after every transfer to play safe.
|
||||
*/
|
||||
if (i2c->dev_type == MXS_I2C_V1)
|
||||
mxs_i2c_reset(i2c);
|
||||
|
||||
dev_dbg(i2c->dev, "Done with err=%d\n", ret);
|
||||
|
||||
|
@ -680,8 +780,28 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id mxs_i2c_devtype[] = {
|
||||
{
|
||||
.name = "imx23-i2c",
|
||||
.driver_data = MXS_I2C_V1,
|
||||
}, {
|
||||
.name = "imx28-i2c",
|
||||
.driver_data = MXS_I2C_V2,
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype);
|
||||
|
||||
static const struct of_device_id mxs_i2c_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], },
|
||||
{ .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
|
||||
|
||||
static int mxs_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(mxs_i2c_dt_ids, &pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mxs_i2c_dev *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
|
@ -693,6 +813,11 @@ static int mxs_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_id) {
|
||||
const struct platform_device_id *device_id = of_id->data;
|
||||
i2c->dev_type = device_id->driver_data;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
||||
|
@ -768,12 +893,6 @@ static int mxs_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mxs_i2c_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx28-i2c", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
|
||||
|
||||
static struct platform_driver mxs_i2c_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
|
@ -796,6 +915,7 @@ static void __exit mxs_i2c_exit(void)
|
|||
}
|
||||
module_exit(mxs_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
|
||||
MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("MXS I2C Bus Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
|
||||
#define I2C_PNX_SPEED_KHZ_DEFAULT 100
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/i2c/i2c-rcar.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -102,8 +103,8 @@ enum {
|
|||
#define ID_NACK (1 << 4)
|
||||
|
||||
enum rcar_i2c_type {
|
||||
I2C_RCAR_H1,
|
||||
I2C_RCAR_H2,
|
||||
I2C_RCAR_GEN1,
|
||||
I2C_RCAR_GEN2,
|
||||
};
|
||||
|
||||
struct rcar_i2c_priv {
|
||||
|
@ -226,22 +227,23 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
|||
u32 bus_speed,
|
||||
struct device *dev)
|
||||
{
|
||||
struct clk *clkp = clk_get(NULL, "peripheral_clk");
|
||||
struct clk *clkp = clk_get(dev, NULL);
|
||||
u32 scgd, cdf;
|
||||
u32 round, ick;
|
||||
u32 scl;
|
||||
u32 cdf_width;
|
||||
unsigned long rate;
|
||||
|
||||
if (!clkp) {
|
||||
dev_err(dev, "there is no peripheral_clk\n");
|
||||
return -EIO;
|
||||
if (IS_ERR(clkp)) {
|
||||
dev_err(dev, "couldn't get clock\n");
|
||||
return PTR_ERR(clkp);
|
||||
}
|
||||
|
||||
switch (priv->devtype) {
|
||||
case I2C_RCAR_H1:
|
||||
case I2C_RCAR_GEN1:
|
||||
cdf_width = 2;
|
||||
break;
|
||||
case I2C_RCAR_H2:
|
||||
case I2C_RCAR_GEN2:
|
||||
cdf_width = 3;
|
||||
break;
|
||||
default:
|
||||
|
@ -264,15 +266,14 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
|||
* clkp : peripheral_clk
|
||||
* F[] : integer up-valuation
|
||||
*/
|
||||
for (cdf = 0; cdf < (1 << cdf_width); cdf++) {
|
||||
ick = clk_get_rate(clkp) / (1 + cdf);
|
||||
if (ick < 20000000)
|
||||
goto ick_find;
|
||||
rate = clk_get_rate(clkp);
|
||||
cdf = rate / 20000000;
|
||||
if (cdf >= 1 << cdf_width) {
|
||||
dev_err(dev, "Input clock %lu too high\n", rate);
|
||||
return -EIO;
|
||||
}
|
||||
dev_err(dev, "there is no best CDF\n");
|
||||
return -EIO;
|
||||
ick = rate / (cdf + 1);
|
||||
|
||||
ick_find:
|
||||
/*
|
||||
* it is impossible to calculate large scale
|
||||
* number on u32. separate it
|
||||
|
@ -290,6 +291,12 @@ ick_find:
|
|||
*
|
||||
* Calculation result (= SCL) should be less than
|
||||
* bus_speed for hardware safety
|
||||
*
|
||||
* We could use something along the lines of
|
||||
* div = ick / (bus_speed + 1) + 1;
|
||||
* scgd = (div - 20 - round + 7) / 8;
|
||||
* scl = ick / (20 + (scgd * 8) + round);
|
||||
* (not fully verified) but that would get pretty involved
|
||||
*/
|
||||
for (scgd = 0; scgd < 0x40; scgd++) {
|
||||
scl = ick / (20 + (scgd * 8) + round);
|
||||
|
@ -306,7 +313,7 @@ scgd_find:
|
|||
/*
|
||||
* keep icccr value
|
||||
*/
|
||||
priv->icccr = (scgd << (cdf_width) | cdf);
|
||||
priv->icccr = scgd << cdf_width | cdf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -632,6 +639,15 @@ static const struct i2c_algorithm rcar_i2c_algo = {
|
|||
.functionality = rcar_i2c_func,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_i2c_dt_ids[] = {
|
||||
{ .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 },
|
||||
{ .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 },
|
||||
{ .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 },
|
||||
{ .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
|
||||
|
||||
static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
@ -649,10 +665,15 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
bus_speed = 100000; /* default 100 kHz */
|
||||
if (pdata && pdata->bus_speed)
|
||||
ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
|
||||
if (ret < 0 && pdata && pdata->bus_speed)
|
||||
bus_speed = pdata->bus_speed;
|
||||
|
||||
priv->devtype = platform_get_device_id(pdev)->driver_data;
|
||||
if (pdev->dev.of_node)
|
||||
priv->devtype = (long)of_match_device(rcar_i2c_dt_ids,
|
||||
dev)->data;
|
||||
else
|
||||
priv->devtype = platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
|
||||
if (ret < 0)
|
||||
|
@ -673,6 +694,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->retries = 3;
|
||||
adap->dev.parent = dev;
|
||||
adap->dev.of_node = dev->of_node;
|
||||
i2c_set_adapdata(adap, priv);
|
||||
strlcpy(adap->name, pdev->name, sizeof(adap->name));
|
||||
|
||||
|
@ -709,9 +731,9 @@ static int rcar_i2c_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static struct platform_device_id rcar_i2c_id_table[] = {
|
||||
{ "i2c-rcar", I2C_RCAR_H1 },
|
||||
{ "i2c-rcar_h1", I2C_RCAR_H1 },
|
||||
{ "i2c-rcar_h2", I2C_RCAR_H2 },
|
||||
{ "i2c-rcar", I2C_RCAR_GEN1 },
|
||||
{ "i2c-rcar_gen1", I2C_RCAR_GEN1 },
|
||||
{ "i2c-rcar_gen2", I2C_RCAR_GEN2 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table);
|
||||
|
@ -720,6 +742,7 @@ static struct platform_driver rcar_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "i2c-rcar",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = rcar_i2c_dt_ids,
|
||||
},
|
||||
.probe = rcar_i2c_probe,
|
||||
.remove = rcar_i2c_remove,
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
|||
goto out;
|
||||
|
||||
obj = pkg->package.elements + 1;
|
||||
if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
|
||||
if (obj->type != ACPI_TYPE_INTEGER) {
|
||||
ACPI_ERROR((AE_INFO, "Invalid argument type"));
|
||||
result = -EIO;
|
||||
goto out;
|
||||
|
@ -235,7 +235,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
|||
case I2C_SMBUS_BYTE:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
|
||||
if (obj->type != ACPI_TYPE_INTEGER) {
|
||||
ACPI_ERROR((AE_INFO, "Invalid argument type"));
|
||||
result = -EIO;
|
||||
goto out;
|
||||
|
@ -246,7 +246,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
|||
data->byte = obj->integer.value;
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) {
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
ACPI_ERROR((AE_INFO, "Invalid argument type"));
|
||||
result = -EIO;
|
||||
goto out;
|
||||
|
|
|
@ -235,7 +235,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
|
|||
int offset;
|
||||
|
||||
/* Get clock rate after clock is enabled */
|
||||
clk_enable(pd->clk);
|
||||
clk_prepare_enable(pd->clk);
|
||||
i2c_clk_khz = clk_get_rate(pd->clk) / 1000;
|
||||
i2c_clk_khz /= pd->clks_per_count;
|
||||
|
||||
|
@ -270,14 +270,14 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
|
|||
pd->icic &= ~ICIC_ICCHB8;
|
||||
|
||||
out:
|
||||
clk_disable(pd->clk);
|
||||
clk_disable_unprepare(pd->clk);
|
||||
}
|
||||
|
||||
static void activate_ch(struct sh_mobile_i2c_data *pd)
|
||||
{
|
||||
/* Wake up device and enable clock */
|
||||
pm_runtime_get_sync(pd->dev);
|
||||
clk_enable(pd->clk);
|
||||
clk_prepare_enable(pd->clk);
|
||||
|
||||
/* Enable channel and configure rx ack */
|
||||
iic_set_clr(pd, ICCR, ICCR_ICE, 0);
|
||||
|
@ -300,7 +300,7 @@ static void deactivate_ch(struct sh_mobile_i2c_data *pd)
|
|||
iic_set_clr(pd, ICCR, 0, ICCR_ICE);
|
||||
|
||||
/* Disable clock and mark device as idle */
|
||||
clk_disable(pd->clk);
|
||||
clk_disable_unprepare(pd->clk);
|
||||
pm_runtime_put_sync(pd->dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,872 @@
|
|||
/*
|
||||
* Copyright (C) 2013 STMicroelectronics
|
||||
*
|
||||
* I2C master mode controller driver, used in STMicroelectronics devices.
|
||||
*
|
||||
* Author: Maxime Coquelin <maxime.coquelin@st.com>
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
/* SSC registers */
|
||||
#define SSC_BRG 0x000
|
||||
#define SSC_TBUF 0x004
|
||||
#define SSC_RBUF 0x008
|
||||
#define SSC_CTL 0x00C
|
||||
#define SSC_IEN 0x010
|
||||
#define SSC_STA 0x014
|
||||
#define SSC_I2C 0x018
|
||||
#define SSC_SLAD 0x01C
|
||||
#define SSC_REP_START_HOLD 0x020
|
||||
#define SSC_START_HOLD 0x024
|
||||
#define SSC_REP_START_SETUP 0x028
|
||||
#define SSC_DATA_SETUP 0x02C
|
||||
#define SSC_STOP_SETUP 0x030
|
||||
#define SSC_BUS_FREE 0x034
|
||||
#define SSC_TX_FSTAT 0x038
|
||||
#define SSC_RX_FSTAT 0x03C
|
||||
#define SSC_PRE_SCALER_BRG 0x040
|
||||
#define SSC_CLR 0x080
|
||||
#define SSC_NOISE_SUPP_WIDTH 0x100
|
||||
#define SSC_PRSCALER 0x104
|
||||
#define SSC_NOISE_SUPP_WIDTH_DATAOUT 0x108
|
||||
#define SSC_PRSCALER_DATAOUT 0x10c
|
||||
|
||||
/* SSC Control */
|
||||
#define SSC_CTL_DATA_WIDTH_9 0x8
|
||||
#define SSC_CTL_DATA_WIDTH_MSK 0xf
|
||||
#define SSC_CTL_BM 0xf
|
||||
#define SSC_CTL_HB BIT(4)
|
||||
#define SSC_CTL_PH BIT(5)
|
||||
#define SSC_CTL_PO BIT(6)
|
||||
#define SSC_CTL_SR BIT(7)
|
||||
#define SSC_CTL_MS BIT(8)
|
||||
#define SSC_CTL_EN BIT(9)
|
||||
#define SSC_CTL_LPB BIT(10)
|
||||
#define SSC_CTL_EN_TX_FIFO BIT(11)
|
||||
#define SSC_CTL_EN_RX_FIFO BIT(12)
|
||||
#define SSC_CTL_EN_CLST_RX BIT(13)
|
||||
|
||||
/* SSC Interrupt Enable */
|
||||
#define SSC_IEN_RIEN BIT(0)
|
||||
#define SSC_IEN_TIEN BIT(1)
|
||||
#define SSC_IEN_TEEN BIT(2)
|
||||
#define SSC_IEN_REEN BIT(3)
|
||||
#define SSC_IEN_PEEN BIT(4)
|
||||
#define SSC_IEN_AASEN BIT(6)
|
||||
#define SSC_IEN_STOPEN BIT(7)
|
||||
#define SSC_IEN_ARBLEN BIT(8)
|
||||
#define SSC_IEN_NACKEN BIT(10)
|
||||
#define SSC_IEN_REPSTRTEN BIT(11)
|
||||
#define SSC_IEN_TX_FIFO_HALF BIT(12)
|
||||
#define SSC_IEN_RX_FIFO_HALF_FULL BIT(14)
|
||||
|
||||
/* SSC Status */
|
||||
#define SSC_STA_RIR BIT(0)
|
||||
#define SSC_STA_TIR BIT(1)
|
||||
#define SSC_STA_TE BIT(2)
|
||||
#define SSC_STA_RE BIT(3)
|
||||
#define SSC_STA_PE BIT(4)
|
||||
#define SSC_STA_CLST BIT(5)
|
||||
#define SSC_STA_AAS BIT(6)
|
||||
#define SSC_STA_STOP BIT(7)
|
||||
#define SSC_STA_ARBL BIT(8)
|
||||
#define SSC_STA_BUSY BIT(9)
|
||||
#define SSC_STA_NACK BIT(10)
|
||||
#define SSC_STA_REPSTRT BIT(11)
|
||||
#define SSC_STA_TX_FIFO_HALF BIT(12)
|
||||
#define SSC_STA_TX_FIFO_FULL BIT(13)
|
||||
#define SSC_STA_RX_FIFO_HALF BIT(14)
|
||||
|
||||
/* SSC I2C Control */
|
||||
#define SSC_I2C_I2CM BIT(0)
|
||||
#define SSC_I2C_STRTG BIT(1)
|
||||
#define SSC_I2C_STOPG BIT(2)
|
||||
#define SSC_I2C_ACKG BIT(3)
|
||||
#define SSC_I2C_AD10 BIT(4)
|
||||
#define SSC_I2C_TXENB BIT(5)
|
||||
#define SSC_I2C_REPSTRTG BIT(11)
|
||||
#define SSC_I2C_SLAVE_DISABLE BIT(12)
|
||||
|
||||
/* SSC Tx FIFO Status */
|
||||
#define SSC_TX_FSTAT_STATUS 0x07
|
||||
|
||||
/* SSC Rx FIFO Status */
|
||||
#define SSC_RX_FSTAT_STATUS 0x07
|
||||
|
||||
/* SSC Clear bit operation */
|
||||
#define SSC_CLR_SSCAAS BIT(6)
|
||||
#define SSC_CLR_SSCSTOP BIT(7)
|
||||
#define SSC_CLR_SSCARBL BIT(8)
|
||||
#define SSC_CLR_NACK BIT(10)
|
||||
#define SSC_CLR_REPSTRT BIT(11)
|
||||
|
||||
/* SSC Clock Prescaler */
|
||||
#define SSC_PRSC_VALUE 0x0f
|
||||
|
||||
|
||||
#define SSC_TXFIFO_SIZE 0x8
|
||||
#define SSC_RXFIFO_SIZE 0x8
|
||||
|
||||
enum st_i2c_mode {
|
||||
I2C_MODE_STANDARD,
|
||||
I2C_MODE_FAST,
|
||||
I2C_MODE_END,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct st_i2c_timings - per-Mode tuning parameters
|
||||
* @rate: I2C bus rate
|
||||
* @rep_start_hold: I2C repeated start hold time requirement
|
||||
* @rep_start_setup: I2C repeated start set up time requirement
|
||||
* @start_hold: I2C start hold time requirement
|
||||
* @data_setup_time: I2C data set up time requirement
|
||||
* @stop_setup_time: I2C stop set up time requirement
|
||||
* @bus_free_time: I2C bus free time requirement
|
||||
* @sda_pulse_min_limit: I2C SDA pulse mini width limit
|
||||
*/
|
||||
struct st_i2c_timings {
|
||||
u32 rate;
|
||||
u32 rep_start_hold;
|
||||
u32 rep_start_setup;
|
||||
u32 start_hold;
|
||||
u32 data_setup_time;
|
||||
u32 stop_setup_time;
|
||||
u32 bus_free_time;
|
||||
u32 sda_pulse_min_limit;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct st_i2c_client - client specific data
|
||||
* @addr: 8-bit slave addr, including r/w bit
|
||||
* @count: number of bytes to be transfered
|
||||
* @xfered: number of bytes already transferred
|
||||
* @buf: data buffer
|
||||
* @result: result of the transfer
|
||||
* @stop: last I2C msg to be sent, i.e. STOP to be generated
|
||||
*/
|
||||
struct st_i2c_client {
|
||||
u8 addr;
|
||||
u32 count;
|
||||
u32 xfered;
|
||||
u8 *buf;
|
||||
int result;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct st_i2c_dev - private data of the controller
|
||||
* @adap: I2C adapter for this controller
|
||||
* @dev: device for this controller
|
||||
* @base: virtual memory area
|
||||
* @complete: completion of I2C message
|
||||
* @irq: interrupt line for th controller
|
||||
* @clk: hw ssc block clock
|
||||
* @mode: I2C mode of the controller. Standard or Fast only supported
|
||||
* @scl_min_width_us: SCL line minimum pulse width in us
|
||||
* @sda_min_width_us: SDA line minimum pulse width in us
|
||||
* @client: I2C transfert information
|
||||
* @busy: I2C transfer on-going
|
||||
*/
|
||||
struct st_i2c_dev {
|
||||
struct i2c_adapter adap;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct completion complete;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
int mode;
|
||||
u32 scl_min_width_us;
|
||||
u32 sda_min_width_us;
|
||||
struct st_i2c_client client;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
static inline void st_i2c_set_bits(void __iomem *reg, u32 mask)
|
||||
{
|
||||
writel_relaxed(readl_relaxed(reg) | mask, reg);
|
||||
}
|
||||
|
||||
static inline void st_i2c_clr_bits(void __iomem *reg, u32 mask)
|
||||
{
|
||||
writel_relaxed(readl_relaxed(reg) & ~mask, reg);
|
||||
}
|
||||
|
||||
/* From I2C Specifications v0.5 */
|
||||
static struct st_i2c_timings i2c_timings[] = {
|
||||
[I2C_MODE_STANDARD] = {
|
||||
.rate = 100000,
|
||||
.rep_start_hold = 4000,
|
||||
.rep_start_setup = 4700,
|
||||
.start_hold = 4000,
|
||||
.data_setup_time = 250,
|
||||
.stop_setup_time = 4000,
|
||||
.bus_free_time = 4700,
|
||||
},
|
||||
[I2C_MODE_FAST] = {
|
||||
.rate = 400000,
|
||||
.rep_start_hold = 600,
|
||||
.rep_start_setup = 600,
|
||||
.start_hold = 600,
|
||||
.data_setup_time = 100,
|
||||
.stop_setup_time = 600,
|
||||
.bus_free_time = 1300,
|
||||
},
|
||||
};
|
||||
|
||||
static void st_i2c_flush_rx_fifo(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
int count, i;
|
||||
|
||||
/*
|
||||
* Counter only counts up to 7 but fifo size is 8...
|
||||
* When fifo is full, counter is 0 and RIR bit of status register is
|
||||
* set
|
||||
*/
|
||||
if (readl_relaxed(i2c_dev->base + SSC_STA) & SSC_STA_RIR)
|
||||
count = SSC_RXFIFO_SIZE;
|
||||
else
|
||||
count = readl_relaxed(i2c_dev->base + SSC_RX_FSTAT) &
|
||||
SSC_RX_FSTAT_STATUS;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
readl_relaxed(i2c_dev->base + SSC_RBUF);
|
||||
}
|
||||
|
||||
static void st_i2c_soft_reset(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
/*
|
||||
* FIFO needs to be emptied before reseting the IP,
|
||||
* else the controller raises a BUSY error.
|
||||
*/
|
||||
st_i2c_flush_rx_fifo(i2c_dev);
|
||||
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_CTL, SSC_CTL_SR);
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_CTL, SSC_CTL_SR);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_hw_config() - Prepare SSC block, calculate and apply tuning timings
|
||||
* @i2c_dev: Controller's private data
|
||||
*/
|
||||
static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned long rate;
|
||||
u32 val, ns_per_clk;
|
||||
struct st_i2c_timings *t = &i2c_timings[i2c_dev->mode];
|
||||
|
||||
st_i2c_soft_reset(i2c_dev);
|
||||
|
||||
val = SSC_CLR_REPSTRT | SSC_CLR_NACK | SSC_CLR_SSCARBL |
|
||||
SSC_CLR_SSCAAS | SSC_CLR_SSCSTOP;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_CLR);
|
||||
|
||||
/* SSC Control register setup */
|
||||
val = SSC_CTL_PO | SSC_CTL_PH | SSC_CTL_HB | SSC_CTL_DATA_WIDTH_9;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_CTL);
|
||||
|
||||
rate = clk_get_rate(i2c_dev->clk);
|
||||
ns_per_clk = 1000000000 / rate;
|
||||
|
||||
/* Baudrate */
|
||||
val = rate / (2 * t->rate);
|
||||
writel_relaxed(val, i2c_dev->base + SSC_BRG);
|
||||
|
||||
/* Pre-scaler baudrate */
|
||||
writel_relaxed(1, i2c_dev->base + SSC_PRE_SCALER_BRG);
|
||||
|
||||
/* Enable I2C mode */
|
||||
writel_relaxed(SSC_I2C_I2CM, i2c_dev->base + SSC_I2C);
|
||||
|
||||
/* Repeated start hold time */
|
||||
val = t->rep_start_hold / ns_per_clk;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_REP_START_HOLD);
|
||||
|
||||
/* Repeated start set up time */
|
||||
val = t->rep_start_setup / ns_per_clk;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_REP_START_SETUP);
|
||||
|
||||
/* Start hold time */
|
||||
val = t->start_hold / ns_per_clk;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_START_HOLD);
|
||||
|
||||
/* Data set up time */
|
||||
val = t->data_setup_time / ns_per_clk;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_DATA_SETUP);
|
||||
|
||||
/* Stop set up time */
|
||||
val = t->stop_setup_time / ns_per_clk;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_STOP_SETUP);
|
||||
|
||||
/* Bus free time */
|
||||
val = t->bus_free_time / ns_per_clk;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_BUS_FREE);
|
||||
|
||||
/* Prescalers set up */
|
||||
val = rate / 10000000;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_PRSCALER);
|
||||
writel_relaxed(val, i2c_dev->base + SSC_PRSCALER_DATAOUT);
|
||||
|
||||
/* Noise suppression witdh */
|
||||
val = i2c_dev->scl_min_width_us * rate / 100000000;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH);
|
||||
|
||||
/* Noise suppression max output data delay width */
|
||||
val = i2c_dev->sda_min_width_us * rate / 100000000;
|
||||
writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH_DATAOUT);
|
||||
}
|
||||
|
||||
static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 sta;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
sta = readl_relaxed(i2c_dev->base + SSC_STA);
|
||||
if (!(sta & SSC_STA_BUSY))
|
||||
return 0;
|
||||
|
||||
usleep_range(2000, 4000);
|
||||
}
|
||||
|
||||
dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_write_tx_fifo() - Write a byte in the Tx FIFO
|
||||
* @i2c_dev: Controller's private data
|
||||
* @byte: Data to write in the Tx FIFO
|
||||
*/
|
||||
static inline void st_i2c_write_tx_fifo(struct st_i2c_dev *i2c_dev, u8 byte)
|
||||
{
|
||||
u16 tbuf = byte << 1;
|
||||
|
||||
writel_relaxed(tbuf | 1, i2c_dev->base + SSC_TBUF);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_wr_fill_tx_fifo() - Fill the Tx FIFO in write mode
|
||||
* @i2c_dev: Controller's private data
|
||||
*
|
||||
* This functions fills the Tx FIFO with I2C transfert buffer when
|
||||
* in write mode.
|
||||
*/
|
||||
static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 tx_fstat, sta;
|
||||
int i;
|
||||
|
||||
sta = readl_relaxed(i2c_dev->base + SSC_STA);
|
||||
if (sta & SSC_STA_TX_FIFO_FULL)
|
||||
return;
|
||||
|
||||
tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT);
|
||||
tx_fstat &= SSC_TX_FSTAT_STATUS;
|
||||
|
||||
if (c->count < (SSC_TXFIFO_SIZE - tx_fstat))
|
||||
i = c->count;
|
||||
else
|
||||
i = SSC_TXFIFO_SIZE - tx_fstat;
|
||||
|
||||
for (; i > 0; i--, c->count--, c->buf++)
|
||||
st_i2c_write_tx_fifo(i2c_dev, *c->buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_rd_fill_tx_fifo() - Fill the Tx FIFO in read mode
|
||||
* @i2c_dev: Controller's private data
|
||||
*
|
||||
* This functions fills the Tx FIFO with fixed pattern when
|
||||
* in read mode to trigger clock.
|
||||
*/
|
||||
static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, int max)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 tx_fstat, sta;
|
||||
int i;
|
||||
|
||||
sta = readl_relaxed(i2c_dev->base + SSC_STA);
|
||||
if (sta & SSC_STA_TX_FIFO_FULL)
|
||||
return;
|
||||
|
||||
tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT);
|
||||
tx_fstat &= SSC_TX_FSTAT_STATUS;
|
||||
|
||||
if (max < (SSC_TXFIFO_SIZE - tx_fstat))
|
||||
i = max;
|
||||
else
|
||||
i = SSC_TXFIFO_SIZE - tx_fstat;
|
||||
|
||||
for (; i > 0; i--, c->xfered++)
|
||||
st_i2c_write_tx_fifo(i2c_dev, 0xff);
|
||||
}
|
||||
|
||||
static void st_i2c_read_rx_fifo(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 i, sta;
|
||||
u16 rbuf;
|
||||
|
||||
sta = readl_relaxed(i2c_dev->base + SSC_STA);
|
||||
if (sta & SSC_STA_RIR) {
|
||||
i = SSC_RXFIFO_SIZE;
|
||||
} else {
|
||||
i = readl_relaxed(i2c_dev->base + SSC_RX_FSTAT);
|
||||
i &= SSC_RX_FSTAT_STATUS;
|
||||
}
|
||||
|
||||
for (; (i > 0) && (c->count > 0); i--, c->count--) {
|
||||
rbuf = readl_relaxed(i2c_dev->base + SSC_RBUF) >> 1;
|
||||
*c->buf++ = (u8)rbuf & 0xff;
|
||||
}
|
||||
|
||||
if (i) {
|
||||
dev_err(i2c_dev->dev, "Unexpected %d bytes in rx fifo\n", i);
|
||||
st_i2c_flush_rx_fifo(i2c_dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_terminate_xfer() - Send either STOP or REPSTART condition
|
||||
* @i2c_dev: Controller's private data
|
||||
*/
|
||||
static void st_i2c_terminate_xfer(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_IEN, SSC_IEN_TEEN);
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG);
|
||||
|
||||
if (c->stop) {
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_IEN, SSC_IEN_STOPEN);
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG);
|
||||
} else {
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_IEN, SSC_IEN_REPSTRTEN);
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_REPSTRTG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_handle_write() - Handle FIFO empty interrupt in case of write
|
||||
* @i2c_dev: Controller's private data
|
||||
*/
|
||||
static void st_i2c_handle_write(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
|
||||
st_i2c_flush_rx_fifo(i2c_dev);
|
||||
|
||||
if (!c->count)
|
||||
/* End of xfer, send stop or repstart */
|
||||
st_i2c_terminate_xfer(i2c_dev);
|
||||
else
|
||||
st_i2c_wr_fill_tx_fifo(i2c_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_handle_write() - Handle FIFO enmpty interrupt in case of read
|
||||
* @i2c_dev: Controller's private data
|
||||
*/
|
||||
static void st_i2c_handle_read(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 ien;
|
||||
|
||||
/* Trash the address read back */
|
||||
if (!c->xfered) {
|
||||
readl_relaxed(i2c_dev->base + SSC_RBUF);
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_TXENB);
|
||||
} else {
|
||||
st_i2c_read_rx_fifo(i2c_dev);
|
||||
}
|
||||
|
||||
if (!c->count) {
|
||||
/* End of xfer, send stop or repstart */
|
||||
st_i2c_terminate_xfer(i2c_dev);
|
||||
} else if (c->count == 1) {
|
||||
/* Penultimate byte to xfer, disable ACK gen. */
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_ACKG);
|
||||
|
||||
/* Last received byte is to be handled by NACK interrupt */
|
||||
ien = SSC_IEN_NACKEN | SSC_IEN_ARBLEN;
|
||||
writel_relaxed(ien, i2c_dev->base + SSC_IEN);
|
||||
|
||||
st_i2c_rd_fill_tx_fifo(i2c_dev, c->count);
|
||||
} else {
|
||||
st_i2c_rd_fill_tx_fifo(i2c_dev, c->count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_isr() - Interrupt routine
|
||||
* @irq: interrupt number
|
||||
* @data: Controller's private data
|
||||
*/
|
||||
static irqreturn_t st_i2c_isr_thread(int irq, void *data)
|
||||
{
|
||||
struct st_i2c_dev *i2c_dev = data;
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 sta, ien;
|
||||
int it;
|
||||
|
||||
ien = readl_relaxed(i2c_dev->base + SSC_IEN);
|
||||
sta = readl_relaxed(i2c_dev->base + SSC_STA);
|
||||
|
||||
/* Use __fls() to check error bits first */
|
||||
it = __fls(sta & ien);
|
||||
if (it < 0) {
|
||||
dev_dbg(i2c_dev->dev, "spurious it (sta=0x%04x, ien=0x%04x)\n",
|
||||
sta, ien);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
switch (1 << it) {
|
||||
case SSC_STA_TE:
|
||||
if (c->addr & I2C_M_RD)
|
||||
st_i2c_handle_read(i2c_dev);
|
||||
else
|
||||
st_i2c_handle_write(i2c_dev);
|
||||
break;
|
||||
|
||||
case SSC_STA_STOP:
|
||||
case SSC_STA_REPSTRT:
|
||||
writel_relaxed(0, i2c_dev->base + SSC_IEN);
|
||||
complete(&i2c_dev->complete);
|
||||
break;
|
||||
|
||||
case SSC_STA_NACK:
|
||||
writel_relaxed(SSC_CLR_NACK, i2c_dev->base + SSC_CLR);
|
||||
|
||||
/* Last received byte handled by NACK interrupt */
|
||||
if ((c->addr & I2C_M_RD) && (c->count == 1) && (c->xfered)) {
|
||||
st_i2c_handle_read(i2c_dev);
|
||||
break;
|
||||
}
|
||||
|
||||
it = SSC_IEN_STOPEN | SSC_IEN_ARBLEN;
|
||||
writel_relaxed(it, i2c_dev->base + SSC_IEN);
|
||||
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG);
|
||||
c->result = -EIO;
|
||||
break;
|
||||
|
||||
case SSC_STA_ARBL:
|
||||
writel_relaxed(SSC_CLR_SSCARBL, i2c_dev->base + SSC_CLR);
|
||||
|
||||
it = SSC_IEN_STOPEN | SSC_IEN_ARBLEN;
|
||||
writel_relaxed(it, i2c_dev->base + SSC_IEN);
|
||||
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG);
|
||||
c->result = -EIO;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(i2c_dev->dev,
|
||||
"it %d unhandled (sta=0x%04x)\n", it, sta);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read IEN register to ensure interrupt mask write is effective
|
||||
* before re-enabling interrupt at GIC level, and thus avoid spurious
|
||||
* interrupts.
|
||||
*/
|
||||
readl(i2c_dev->base + SSC_IEN);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_xfer_msg() - Transfer a single I2C message
|
||||
* @i2c_dev: Controller's private data
|
||||
* @msg: I2C message to transfer
|
||||
* @is_first: first message of the sequence
|
||||
* @is_last: last message of the sequence
|
||||
*/
|
||||
static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
|
||||
bool is_first, bool is_last)
|
||||
{
|
||||
struct st_i2c_client *c = &i2c_dev->client;
|
||||
u32 ctl, i2c, it;
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
c->addr = (u8)(msg->addr << 1);
|
||||
c->addr |= (msg->flags & I2C_M_RD);
|
||||
c->buf = msg->buf;
|
||||
c->count = msg->len;
|
||||
c->xfered = 0;
|
||||
c->result = 0;
|
||||
c->stop = is_last;
|
||||
|
||||
reinit_completion(&i2c_dev->complete);
|
||||
|
||||
ctl = SSC_CTL_EN | SSC_CTL_MS | SSC_CTL_EN_RX_FIFO | SSC_CTL_EN_TX_FIFO;
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_CTL, ctl);
|
||||
|
||||
i2c = SSC_I2C_TXENB;
|
||||
if (c->addr & I2C_M_RD)
|
||||
i2c |= SSC_I2C_ACKG;
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, i2c);
|
||||
|
||||
/* Write slave address */
|
||||
st_i2c_write_tx_fifo(i2c_dev, c->addr);
|
||||
|
||||
/* Pre-fill Tx fifo with data in case of write */
|
||||
if (!(c->addr & I2C_M_RD))
|
||||
st_i2c_wr_fill_tx_fifo(i2c_dev);
|
||||
|
||||
it = SSC_IEN_NACKEN | SSC_IEN_TEEN | SSC_IEN_ARBLEN;
|
||||
writel_relaxed(it, i2c_dev->base + SSC_IEN);
|
||||
|
||||
if (is_first) {
|
||||
ret = st_i2c_wait_free_bus(i2c_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG);
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
ret = c->result;
|
||||
|
||||
if (!timeout) {
|
||||
dev_err(i2c_dev->dev, "Write to slave 0x%x timed out\n",
|
||||
c->addr);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
i2c = SSC_I2C_STOPG | SSC_I2C_REPSTRTG;
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, i2c);
|
||||
|
||||
writel_relaxed(SSC_CLR_SSCSTOP | SSC_CLR_REPSTRT,
|
||||
i2c_dev->base + SSC_CLR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_i2c_xfer() - Transfer a single I2C message
|
||||
* @i2c_adap: Adapter pointer to the controller
|
||||
* @msgs: Pointer to data to be written.
|
||||
* @num: Number of messages to be executed
|
||||
*/
|
||||
static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
|
||||
int ret, i;
|
||||
|
||||
i2c_dev->busy = true;
|
||||
|
||||
ret = clk_prepare_enable(i2c_dev->clk);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev, "Failed to prepare_enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_default_state(i2c_dev->dev);
|
||||
|
||||
st_i2c_hw_config(i2c_dev);
|
||||
|
||||
for (i = 0; (i < num) && !ret; i++)
|
||||
ret = st_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0, i == num - 1);
|
||||
|
||||
pinctrl_pm_select_idle_state(i2c_dev->dev);
|
||||
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
i2c_dev->busy = false;
|
||||
|
||||
return (ret < 0) ? ret : i;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int st_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
container_of(dev, struct platform_device, dev);
|
||||
struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (i2c_dev->busy)
|
||||
return -EBUSY;
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_i2c_resume(struct device *dev)
|
||||
{
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
/* Go in idle state if available */
|
||||
pinctrl_pm_select_idle_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
|
||||
#define ST_I2C_PM (&st_i2c_pm)
|
||||
#else
|
||||
#define ST_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static u32 st_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm st_i2c_algo = {
|
||||
.master_xfer = st_i2c_xfer,
|
||||
.functionality = st_i2c_func,
|
||||
};
|
||||
|
||||
static int st_i2c_of_get_deglitch(struct device_node *np,
|
||||
struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "st,i2c-min-scl-pulse-width-us",
|
||||
&i2c_dev->scl_min_width_us);
|
||||
if ((ret == -ENODATA) || (ret == -EOVERFLOW)) {
|
||||
dev_err(i2c_dev->dev, "st,i2c-min-scl-pulse-width-us invalid\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "st,i2c-min-sda-pulse-width-us",
|
||||
&i2c_dev->sda_min_width_us);
|
||||
if ((ret == -ENODATA) || (ret == -EOVERFLOW)) {
|
||||
dev_err(i2c_dev->dev, "st,i2c-min-sda-pulse-width-us invalid\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct st_i2c_dev *i2c_dev;
|
||||
struct resource *res;
|
||||
u32 clk_rate;
|
||||
struct i2c_adapter *adap;
|
||||
int ret;
|
||||
|
||||
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
|
||||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(i2c_dev->base))
|
||||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
i2c_dev->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!i2c_dev->irq) {
|
||||
dev_err(&pdev->dev, "IRQ missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2c_dev->clk = of_clk_get_by_name(np, "ssc");
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_err(&pdev->dev, "Unable to request clock\n");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
|
||||
i2c_dev->mode = I2C_MODE_STANDARD;
|
||||
ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
|
||||
if ((!ret) && (clk_rate == 400000))
|
||||
i2c_dev->mode = I2C_MODE_FAST;
|
||||
|
||||
i2c_dev->dev = &pdev->dev;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq,
|
||||
NULL, st_i2c_isr_thread,
|
||||
IRQF_ONESHOT, pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_default_state(i2c_dev->dev);
|
||||
/* In case idle state available, select it */
|
||||
pinctrl_pm_select_idle_state(i2c_dev->dev);
|
||||
|
||||
ret = st_i2c_of_get_deglitch(np, i2c_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adap = &i2c_dev->adap;
|
||||
i2c_set_adapdata(adap, i2c_dev);
|
||||
snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%x)", res->start);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->timeout = 2 * HZ;
|
||||
adap->retries = 0;
|
||||
adap->algo = &st_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
init_completion(&i2c_dev->complete);
|
||||
|
||||
ret = i2c_add_adapter(adap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2c_dev);
|
||||
|
||||
dev_info(i2c_dev->dev, "%s initialized\n", adap->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&i2c_dev->adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id st_i2c_match[] = {
|
||||
{ .compatible = "st,comms-ssc-i2c", },
|
||||
{ .compatible = "st,comms-ssc4-i2c", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_i2c_match);
|
||||
|
||||
static struct platform_driver st_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "st-i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = st_i2c_match,
|
||||
.pm = ST_I2C_PM,
|
||||
},
|
||||
.probe = st_i2c_probe,
|
||||
.remove = st_i2c_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(st_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@st.com>");
|
||||
MODULE_DESCRIPTION("STMicroelectronics I2C driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -349,6 +349,7 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
|
|||
err = clk_set_rate(i2c_dev->clk, 20000000);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/i2c-xiic.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define DRIVER_NAME "xiic-i2c"
|
||||
|
||||
|
@ -702,7 +703,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
if (irq < 0)
|
||||
goto resource_missing;
|
||||
|
||||
pdata = (struct xiic_i2c_platform_data *)dev_get_platdata(&pdev->dev);
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
|
|
|
@ -248,7 +248,7 @@ static int i2c_device_probe(struct device *dev)
|
|||
driver = to_i2c_driver(dev->driver);
|
||||
if (!driver->probe || !driver->id_table)
|
||||
return -ENODEV;
|
||||
client->driver = driver;
|
||||
|
||||
if (!device_can_wakeup(&client->dev))
|
||||
device_init_wakeup(&client->dev,
|
||||
client->flags & I2C_CLIENT_WAKE);
|
||||
|
@ -257,7 +257,6 @@ static int i2c_device_probe(struct device *dev)
|
|||
acpi_dev_pm_attach(&client->dev, true);
|
||||
status = driver->probe(client, i2c_match_id(driver->id_table, client));
|
||||
if (status) {
|
||||
client->driver = NULL;
|
||||
i2c_set_clientdata(client, NULL);
|
||||
acpi_dev_pm_detach(&client->dev, true);
|
||||
}
|
||||
|
@ -281,10 +280,8 @@ static int i2c_device_remove(struct device *dev)
|
|||
dev->driver = NULL;
|
||||
status = 0;
|
||||
}
|
||||
if (status == 0) {
|
||||
client->driver = NULL;
|
||||
if (status == 0)
|
||||
i2c_set_clientdata(client, NULL);
|
||||
}
|
||||
acpi_dev_pm_detach(&client->dev, true);
|
||||
return status;
|
||||
}
|
||||
|
@ -1614,9 +1611,14 @@ static int i2c_cmd(struct device *dev, void *_arg)
|
|||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_cmd_arg *arg = _arg;
|
||||
struct i2c_driver *driver;
|
||||
|
||||
if (client && client->driver && client->driver->command)
|
||||
client->driver->command(client, arg->cmd, arg->arg);
|
||||
if (!client || !client->dev.driver)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(client->dev.driver);
|
||||
if (driver->command)
|
||||
driver->command(client, arg->cmd, arg->arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,8 +102,8 @@ static void return_i2c_dev(struct i2c_dev *i2c_dev)
|
|||
kfree(i2c_dev);
|
||||
}
|
||||
|
||||
static ssize_t show_adapter_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt));
|
||||
|
||||
|
@ -111,7 +111,13 @@ static ssize_t show_adapter_name(struct device *dev,
|
|||
return -ENODEV;
|
||||
return sprintf(buf, "%s\n", i2c_dev->adap->name);
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static struct attribute *i2c_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(i2c);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
@ -562,15 +568,10 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
|
|||
res = PTR_ERR(i2c_dev->dev);
|
||||
goto error;
|
||||
}
|
||||
res = device_create_file(i2c_dev->dev, &dev_attr_name);
|
||||
if (res)
|
||||
goto error_destroy;
|
||||
|
||||
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
|
||||
adap->name, adap->nr);
|
||||
return 0;
|
||||
error_destroy:
|
||||
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
|
||||
error:
|
||||
return_i2c_dev(i2c_dev);
|
||||
return res;
|
||||
|
@ -589,7 +590,6 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
|
|||
if (!i2c_dev) /* attach_adapter must have failed */
|
||||
return 0;
|
||||
|
||||
device_remove_file(i2c_dev->dev, &dev_attr_name);
|
||||
return_i2c_dev(i2c_dev);
|
||||
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
|
||||
|
||||
|
@ -637,6 +637,7 @@ static int __init i2c_dev_init(void)
|
|||
res = PTR_ERR(i2c_dev_class);
|
||||
goto out_unreg_chrdev;
|
||||
}
|
||||
i2c_dev_class->dev_groups = i2c_groups;
|
||||
|
||||
/* Keep track of adapters which will be added or removed later */
|
||||
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
|
||||
|
|
|
@ -46,6 +46,7 @@ static int smbus_do_alert(struct device *dev, void *addrp)
|
|||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct alert_data *data = addrp;
|
||||
struct i2c_driver *driver;
|
||||
|
||||
if (!client || client->addr != data->addr)
|
||||
return 0;
|
||||
|
@ -54,12 +55,13 @@ static int smbus_do_alert(struct device *dev, void *addrp)
|
|||
|
||||
/*
|
||||
* Drivers should either disable alerts, or provide at least
|
||||
* a minimal handler. Lock so client->driver won't change.
|
||||
* a minimal handler. Lock so the driver won't change.
|
||||
*/
|
||||
device_lock(dev);
|
||||
if (client->driver) {
|
||||
if (client->driver->alert)
|
||||
client->driver->alert(client, data->flag);
|
||||
if (client->dev.driver) {
|
||||
driver = to_i2c_driver(client->dev.driver);
|
||||
if (driver->alert)
|
||||
driver->alert(client, data->flag);
|
||||
else
|
||||
dev_warn(&client->dev, "no driver alert()!\n");
|
||||
} else
|
||||
|
|
|
@ -238,7 +238,7 @@ static struct platform_driver i2c_arbitrator_driver = {
|
|||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-arb-gpio-challenge",
|
||||
.of_match_table = of_match_ptr(i2c_arbitrator_of_match),
|
||||
.of_match_table = i2c_arbitrator_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -30,15 +30,15 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < mux->data.n_gpios; i++)
|
||||
gpio_set_value(mux->gpio_base + mux->data.gpios[i],
|
||||
val & (1 << i));
|
||||
gpio_set_value_cansleep(mux->gpio_base + mux->data.gpios[i],
|
||||
val & (1 << i));
|
||||
}
|
||||
|
||||
static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
|
||||
{
|
||||
struct gpiomux *mux = data;
|
||||
|
||||
i2c_mux_gpio_set(mux, mux->data.values[chan]);
|
||||
i2c_mux_gpio_set(mux, chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
|||
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
|
||||
|
||||
mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
|
||||
i, class,
|
||||
mux->data.values[i], class,
|
||||
i2c_mux_gpio_select, deselect);
|
||||
if (!mux->adap[i]) {
|
||||
ret = -ENODEV;
|
||||
|
@ -283,7 +283,7 @@ static struct platform_driver i2c_mux_gpio_driver = {
|
|||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-mux-gpio",
|
||||
.of_match_table = of_match_ptr(i2c_mux_gpio_of_match),
|
||||
.of_match_table = i2c_mux_gpio_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/i2c-mux-pinctrl.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct i2c_mux_pinctrl {
|
||||
struct device *dev;
|
||||
|
|
|
@ -1581,7 +1581,7 @@ static int s5c73m3_probe(struct i2c_client *client,
|
|||
oif_sd = &state->oif_sd;
|
||||
|
||||
v4l2_subdev_init(sd, &s5c73m3_subdev_ops);
|
||||
sd->owner = client->driver->driver.owner;
|
||||
sd->owner = client->dev.driver->owner;
|
||||
v4l2_set_subdevdata(sd, state);
|
||||
strlcpy(sd->name, "S5C73M3", sizeof(sd->name));
|
||||
|
||||
|
|
|
@ -411,8 +411,8 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd,
|
|||
|
||||
device_lock(&client->dev);
|
||||
|
||||
if (!client->driver ||
|
||||
!try_module_get(client->driver->driver.owner)) {
|
||||
if (!client->dev.driver ||
|
||||
!try_module_get(client->dev.driver->owner)) {
|
||||
ret = -EPROBE_DEFER;
|
||||
v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n",
|
||||
node->full_name);
|
||||
|
@ -442,7 +442,7 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd,
|
|||
fmd->num_sensors++;
|
||||
|
||||
mod_put:
|
||||
module_put(client->driver->driver.owner);
|
||||
module_put(client->dev.driver->owner);
|
||||
dev_put:
|
||||
device_unlock(&client->dev);
|
||||
put_device(&client->dev);
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#define UNSET (-1U)
|
||||
|
||||
#define PREFIX (t->i2c->driver->driver.name)
|
||||
#define PREFIX (t->i2c->dev.driver->name)
|
||||
|
||||
/*
|
||||
* Driver modprobe parameters
|
||||
|
@ -452,7 +452,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
|
|||
}
|
||||
|
||||
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
|
||||
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
|
||||
c->adapter->name, c->dev.driver->name, c->addr << 1, type,
|
||||
t->mode_mask);
|
||||
return;
|
||||
|
||||
|
@ -556,7 +556,7 @@ static void tuner_lookup(struct i2c_adapter *adap,
|
|||
int mode_mask;
|
||||
|
||||
if (pos->i2c->adapter != adap ||
|
||||
strcmp(pos->i2c->driver->driver.name, "tuner"))
|
||||
strcmp(pos->i2c->dev.driver->name, "tuner"))
|
||||
continue;
|
||||
|
||||
mode_mask = pos->mode_mask;
|
||||
|
|
|
@ -236,14 +236,14 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
|
|||
v4l2_subdev_init(sd, ops);
|
||||
sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
|
||||
/* the owner is the same as the i2c_client's driver owner */
|
||||
sd->owner = client->driver->driver.owner;
|
||||
sd->owner = client->dev.driver->owner;
|
||||
sd->dev = &client->dev;
|
||||
/* i2c_client and v4l2_subdev point to one another */
|
||||
v4l2_set_subdevdata(sd, client);
|
||||
i2c_set_clientdata(client, sd);
|
||||
/* initialize name */
|
||||
snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
|
||||
client->driver->driver.name, i2c_adapter_id(client->adapter),
|
||||
client->dev.driver->name, i2c_adapter_id(client->adapter),
|
||||
client->addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
|
||||
|
@ -274,11 +274,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
|
|||
loaded. This delay-load mechanism doesn't work if other drivers
|
||||
want to use the i2c device, so explicitly loading the module
|
||||
is the best alternative. */
|
||||
if (client == NULL || client->driver == NULL)
|
||||
if (client == NULL || client->dev.driver == NULL)
|
||||
goto error;
|
||||
|
||||
/* Lock the module so we can safely get the v4l2_subdev pointer */
|
||||
if (!try_module_get(client->driver->driver.owner))
|
||||
if (!try_module_get(client->dev.driver->owner))
|
||||
goto error;
|
||||
sd = i2c_get_clientdata(client);
|
||||
|
||||
|
@ -287,7 +287,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
|
|||
if (v4l2_device_register_subdev(v4l2_dev, sd))
|
||||
sd = NULL;
|
||||
/* Decrease the module use count to match the first try_module_get. */
|
||||
module_put(client->driver->driver.owner);
|
||||
module_put(client->dev.driver->owner);
|
||||
|
||||
error:
|
||||
/* If we have a client but no subdev, then something went wrong and
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
|
||||
/*
|
||||
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
|
||||
|
|
|
@ -205,7 +205,6 @@ struct i2c_driver {
|
|||
* @name: Indicates the type of the device, usually a chip name that's
|
||||
* generic enough to hide second-sourcing and compatible revisions.
|
||||
* @adapter: manages the bus segment hosting this I2C device
|
||||
* @driver: device's driver, hence pointer to access routines
|
||||
* @dev: Driver model device node for the slave.
|
||||
* @irq: indicates the IRQ generated by this device (if any)
|
||||
* @detected: member of an i2c_driver.clients list or i2c-core's
|
||||
|
@ -222,7 +221,6 @@ struct i2c_client {
|
|||
/* _LOWER_ 7 bits */
|
||||
char name[I2C_NAME_SIZE];
|
||||
struct i2c_adapter *adapter; /* the adapter we sit on */
|
||||
struct i2c_driver *driver; /* and our access routines */
|
||||
struct device dev; /* the device structure */
|
||||
int irq; /* irq issued by device */
|
||||
struct list_head detected;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
*
|
||||
* void get_mac_addr(struct memory_accessor *mem_acc, void *context)
|
||||
* {
|
||||
* u8 *mac_addr = ethernet_pdata->mac_addr;
|
||||
* u8 *mac_addr = ethernet_pdata->mac_addr;
|
||||
* off_t offset = context;
|
||||
*
|
||||
* // Read MAC addr from EEPROM
|
|
@ -35,7 +35,7 @@
|
|||
printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg)
|
||||
|
||||
#define v4l_client_printk(level, client, fmt, arg...) \
|
||||
v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \
|
||||
v4l_printk(level, (client)->dev.driver->name, (client)->adapter, \
|
||||
(client)->addr, fmt , ## arg)
|
||||
|
||||
#define v4l_err(client, fmt, arg...) \
|
||||
|
|
|
@ -65,7 +65,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
|
|||
* already bound. If not it means binding failed, and then there
|
||||
* is no point in keeping the device instantiated.
|
||||
*/
|
||||
if (!keywest_ctx->client->driver) {
|
||||
if (!keywest_ctx->client->dev.driver) {
|
||||
i2c_unregister_device(keywest_ctx->client);
|
||||
keywest_ctx->client = NULL;
|
||||
return -ENODEV;
|
||||
|
@ -76,7 +76,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
|
|||
* This is safe because i2c-core holds the core_lock mutex for us.
|
||||
*/
|
||||
list_add_tail(&keywest_ctx->client->detected,
|
||||
&keywest_ctx->client->driver->clients);
|
||||
&to_i2c_driver(keywest_ctx->client->dev.driver)->clients);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ static int imx_wm8962_probe(struct platform_device *pdev)
|
|||
goto fail;
|
||||
}
|
||||
codec_dev = of_find_i2c_device_by_node(codec_np);
|
||||
if (!codec_dev || !codec_dev->driver) {
|
||||
if (!codec_dev || !codec_dev->dev.driver) {
|
||||
dev_err(&pdev->dev, "failed to find codec platform device\n");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
|
|
Загрузка…
Ссылка в новой задаче