summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/Kconfig1364
-rw-r--r--drivers/i2c/busses/Makefile144
-rw-r--r--drivers/i2c/busses/i2c-acorn.c99
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c536
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c443
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c517
-rw-r--r--drivers/i2c/busses/i2c-altera.c518
-rw-r--r--drivers/i2c/busses/i2c-amd756-s4882.c254
-rw-r--r--drivers/i2c/busses/i2c-amd756.c410
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c493
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c979
-rw-r--r--drivers/i2c/busses/i2c-at91.c1263
-rw-r--r--drivers/i2c/busses/i2c-au1550.c401
-rw-r--r--drivers/i2c/busses/i2c-axxia.c626
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c580
-rw-r--r--drivers/i2c/busses/i2c-bcm-kona.c902
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c450
-rw-r--r--drivers/i2c/busses/i2c-brcmstb.c735
-rw-r--r--drivers/i2c/busses/i2c-cadence.c1033
-rw-r--r--drivers/i2c/busses/i2c-cbus-gpio.c303
-rw-r--r--drivers/i2c/busses/i2c-cht-wc.c447
-rw-r--r--drivers/i2c/busses/i2c-cpm.c724
-rw-r--r--drivers/i2c/busses/i2c-cros-ec-tunnel.c321
-rw-r--r--drivers/i2c/busses/i2c-davinci.c991
-rw-r--r--drivers/i2c/busses/i2c-designware-baytrail.c179
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c360
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h324
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c748
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c347
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c498
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c292
-rw-r--r--drivers/i2c/busses/i2c-digicolor.c385
-rw-r--r--drivers/i2c/busses/i2c-diolan-u2c.c523
-rw-r--r--drivers/i2c/busses/i2c-dln2.c263
-rw-r--r--drivers/i2c/busses/i2c-efm32.c482
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c939
-rw-r--r--drivers/i2c/busses/i2c-elektor.c331
-rw-r--r--drivers/i2c/busses/i2c-emev2.c452
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c900
-rw-r--r--drivers/i2c/busses/i2c-fsi.c752
-rw-r--r--drivers/i2c/busses/i2c-gpio.c429
-rw-r--r--drivers/i2c/busses/i2c-highlander.c478
-rw-r--r--drivers/i2c/busses/i2c-hix5hd2.c538
-rw-r--r--drivers/i2c/busses/i2c-hydra.c158
-rw-r--r--drivers/i2c/busses/i2c-i801.c1785
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c809
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.h123
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c1522
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c693
-rw-r--r--drivers/i2c/busses/i2c-imx.c1301
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c523
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h103
-rw-r--r--drivers/i2c/busses/i2c-isch.c320
-rw-r--r--drivers/i2c/busses/i2c-ismt.c973
-rw-r--r--drivers/i2c/busses/i2c-jz4780.c805
-rw-r--r--drivers/i2c/busses/i2c-kempld.c408
-rw-r--r--drivers/i2c/busses/i2c-lpc2k.c507
-rw-r--r--drivers/i2c/busses/i2c-meson.c505
-rw-r--r--drivers/i2c/busses/i2c-mlxcpld.c554
-rw-r--r--drivers/i2c/busses/i2c-mpc.c955
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c943
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c1018
-rw-r--r--drivers/i2c/busses/i2c-mxs.c912
-rw-r--r--drivers/i2c/busses/i2c-nforce2-s4985.c249
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c450
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c1131
-rw-r--r--drivers/i2c/busses/i2c-ocores.c582
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.c792
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.h219
-rw-r--r--drivers/i2c/busses/i2c-octeon-platdrv.c286
-rw-r--r--drivers/i2c/busses/i2c-omap.c1577
-rw-r--r--drivers/i2c/busses/i2c-opal.c290
-rw-r--r--drivers/i2c/busses/i2c-owl.c501
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c275
-rw-r--r--drivers/i2c/busses/i2c-parport.c330
-rw-r--r--drivers/i2c/busses/i2c-parport.h114
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c423
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c212
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c262
-rw-r--r--drivers/i2c/busses/i2c-piix4.c1019
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c600
-rw-r--r--drivers/i2c/busses/i2c-pnx.c792
-rw-r--r--drivers/i2c/busses/i2c-powermac.c464
-rw-r--r--drivers/i2c/busses/i2c-puv3.c278
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c154
-rw-r--r--drivers/i2c/busses/i2c-pxa.c1398
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c688
-rw-r--r--drivers/i2c/busses/i2c-qup.c2004
-rw-r--r--drivers/i2c/busses/i2c-rcar.c1043
-rw-r--r--drivers/i2c/busses/i2c-riic.c488
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c1369
-rw-r--r--drivers/i2c/busses/i2c-robotfuzz-osif.c199
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1315
-rw-r--r--drivers/i2c/busses/i2c-scmi.c444
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c565
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c994
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c194
-rw-r--r--drivers/i2c/busses/i2c-simtec.c165
-rw-r--r--drivers/i2c/busses/i2c-sirf.c479
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c430
-rw-r--r--drivers/i2c/busses/i2c-sis630.c557
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c326
-rw-r--r--drivers/i2c/busses/i2c-sprd.c667
-rw-r--r--drivers/i2c/busses/i2c-st.c917
-rw-r--r--drivers/i2c/busses/i2c-stm32.c153
-rw-r--r--drivers/i2c/busses/i2c-stm32.h58
-rw-r--r--drivers/i2c/busses/i2c-stm32f4.c894
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c1996
-rw-r--r--drivers/i2c/busses/i2c-stu300.c1015
-rw-r--r--drivers/i2c/busses/i2c-sun6i-p2wi.c343
-rw-r--r--drivers/i2c/busses/i2c-synquacer.c669
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c319
-rw-r--r--drivers/i2c/busses/i2c-tegra-bpmp.c346
-rw-r--r--drivers/i2c/busses/i2c-tegra.c1169
-rw-r--r--drivers/i2c/busses/i2c-thunderx-pcidrv.c260
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c307
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c675
-rw-r--r--drivers/i2c/busses/i2c-uniphier.c467
-rw-r--r--drivers/i2c/busses/i2c-versatile.c140
-rw-r--r--drivers/i2c/busses/i2c-via.c163
-rw-r--r--drivers/i2c/busses/i2c-viapro.c507
-rw-r--r--drivers/i2c/busses/i2c-viperboard.c473
-rw-r--r--drivers/i2c/busses/i2c-wmt.c474
-rw-r--r--drivers/i2c/busses/i2c-xgene-slimpro.c627
-rw-r--r--drivers/i2c/busses/i2c-xiic.c899
-rw-r--r--drivers/i2c/busses/i2c-xlp9xx.c606
-rw-r--r--drivers/i2c/busses/i2c-xlr.c472
-rw-r--r--drivers/i2c/busses/i2c-zx2967.c611
-rw-r--r--drivers/i2c/busses/scx200_acb.c608
129 files changed, 78163 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
new file mode 100644
index 000000000..165c112bc
--- /dev/null
+++ b/drivers/i2c/busses/Kconfig
@@ -0,0 +1,1364 @@
+#
+# Sensor device configuration
+#
+
+menu "I2C Hardware Bus support"
+ depends on HAS_IOMEM
+
+comment "PC SMBus host controller drivers"
+ depends on PCI
+
+config I2C_ALI1535
+ tristate "ALI 1535"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SMB
+ Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
+ controller is part of the 7101 device, which is an ACPI-compliant
+ Power Management Unit (PMU).
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ali1535.
+
+config I2C_ALI1563
+ tristate "ALI 1563"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SMB
+ Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
+ controller is part of the 7101 device, which is an ACPI-compliant
+ Power Management Unit (PMU).
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ali1563.
+
+config I2C_ALI15X3
+ tristate "ALI 15x3"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ali15x3.
+
+config I2C_AMD756
+ tristate "AMD 756/766/768/8111 and nVidia nForce"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the AMD
+ 756/766/768 mainboard I2C interfaces. The driver also includes
+ support for the first (SMBus 1.0) I2C interface of the AMD 8111 and
+ the nVidia nForce I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-amd756.
+
+config I2C_AMD756_S4882
+ tristate "SMBus multiplexing on the Tyan S4882"
+ depends on I2C_AMD756 && X86
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
+ over 8 different channels, where the various memory module EEPROMs
+ and temperature sensors live. Saying yes here will give you access
+ to these in addition to the trunk.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-amd756-s4882.
+
+config I2C_AMD8111
+ tristate "AMD 8111"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ second (SMBus 2.0) AMD 8111 mainboard I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-amd8111.
+
+config I2C_HIX5HD2
+ tristate "Hix5hd2 high-speed I2C driver"
+ depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
+ help
+ Say Y here to include support for the high-speed I2C controller
+ used in HiSilicon hix5hd2 SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-hix5hd2.
+
+config I2C_I801
+ tristate "Intel 82801 (ICH/PCH)"
+ depends on PCI
+ select CHECK_SIGNATURE if X86 && DMI
+ select I2C_SMBUS
+ help
+ If you say yes to this option, support will be included for the Intel
+ 801 family of mainboard I2C interfaces. Specifically, the following
+ versions of the chipset are supported:
+ 82801AA
+ 82801AB
+ 82801BA
+ 82801CA/CAM
+ 82801DB
+ 82801EB/ER (ICH5/ICH5R)
+ 6300ESB
+ ICH6
+ ICH7
+ ESB2
+ ICH8
+ ICH9
+ EP80579 (Tolapai)
+ ICH10
+ 5/3400 Series (PCH)
+ 6 Series (PCH)
+ Patsburg (PCH)
+ DH89xxCC (PCH)
+ Panther Point (PCH)
+ Lynx Point (PCH)
+ Avoton (SOC)
+ Wellsburg (PCH)
+ Coleto Creek (PCH)
+ Wildcat Point (PCH)
+ BayTrail (SOC)
+ Braswell (SOC)
+ Sunrise Point (PCH)
+ Kaby Lake (PCH)
+ DNV (SOC)
+ Broxton (SOC)
+ Lewisburg (PCH)
+ Gemini Lake (SOC)
+ Cannon Lake (PCH)
+ Cedar Fork (PCH)
+ Ice Lake (PCH)
+ Comet Lake (PCH)
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-i801.
+
+config I2C_ISCH
+ tristate "Intel SCH SMBus 1.0"
+ depends on PCI
+ select LPC_SCH
+ help
+ Say Y here if you want to use SMBus controller on the Intel SCH
+ based systems.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-isch.
+
+config I2C_ISMT
+ tristate "Intel iSMT SMBus Controller"
+ depends on PCI && X86
+ help
+ If you say yes to this option, support will be included for the Intel
+ iSMT SMBus host controller interface.
+
+ This driver can also be built as a module. If so, the module will be
+ called i2c-ismt.
+
+config I2C_PIIX4
+ tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the Intel
+ PIIX4 family of mainboard I2C interfaces. Specifically, the following
+ versions of the chipset are supported (note that Serverworks is part
+ of Broadcom):
+ Intel PIIX4
+ Intel 440MX
+ ATI IXP200
+ ATI IXP300
+ ATI IXP400
+ ATI SB600
+ ATI SB700/SP5100
+ ATI SB800
+ AMD Hudson-2
+ AMD ML
+ AMD CZ
+ Serverworks OSB4
+ Serverworks CSB5
+ Serverworks CSB6
+ Serverworks HT-1000
+ Serverworks HT-1100
+ SMSC Victory66
+
+ Some AMD chipsets contain two PIIX4-compatible SMBus
+ controllers. This driver will attempt to use both controllers
+ on the SB700/SP5100, if they have been initialized by the BIOS.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-piix4.
+
+config I2C_CHT_WC
+ tristate "Intel Cherry Trail Whiskey Cove PMIC smbus controller"
+ depends on INTEL_SOC_PMIC_CHTWC
+ help
+ If you say yes to this option, support will be included for the
+ SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC
+ found on some Intel Cherry Trail systems.
+
+ Note this controller is hooked up to a TI bq24292i charger-IC,
+ combined with a FUSB302 Type-C port-controller as such it is advised
+ to also select CONFIG_TYPEC_FUSB302=m.
+
+config I2C_NFORCE2
+ tristate "Nvidia nForce2, nForce3 and nForce4"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the Nvidia
+ nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-nforce2.
+
+config I2C_NFORCE2_S4985
+ tristate "SMBus multiplexing on the Tyan S4985"
+ depends on I2C_NFORCE2 && X86
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
+ over 4 different channels, where the various memory module EEPROMs
+ live. Saying yes here will give you access to these in addition
+ to the trunk.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-nforce2-s4985.
+
+config I2C_SIS5595
+ tristate "SiS 5595"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS5595 SMBus (a subset of I2C) interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis5595.
+
+config I2C_SIS630
+ tristate "SiS 630/730/964"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis630.
+
+config I2C_SIS96X
+ tristate "SiS 96x"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SiS
+ 96x SMBus (a subset of I2C) interfaces. Specifically, the following
+ chipsets are supported:
+ 645/961
+ 645DX/961
+ 645DX/962
+ 648/961
+ 650/961
+ 735
+ 745
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sis96x.
+
+config I2C_VIA
+ tristate "VIA VT82C586B"
+ depends on PCI
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be included for the VIA
+ 82C586B I2C interface
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-via.
+
+config I2C_VIAPRO
+ tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx/VX900"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the VIA
+ VT82C596 and later SMBus interface. Specifically, the following
+ chipsets are supported:
+ VT82C596A/B
+ VT82C686A/B
+ VT8231
+ VT8233/A
+ VT8235
+ VT8237R/A/S
+ VT8251
+ CX700
+ VX800/VX820
+ VX855/VX875
+ VX900
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-viapro.
+
+if ACPI
+
+comment "ACPI drivers"
+
+config I2C_SCMI
+ tristate "SMBus Control Method Interface"
+ help
+ This driver supports the SMBus Control Method Interface. It needs the
+ BIOS to declare ACPI control methods as described in the SMBus Control
+ Method Interface specification.
+
+ To compile this driver as a module, choose M here:
+ the module will be called i2c-scmi.
+
+endif # ACPI
+
+comment "Mac SMBus host controller drivers"
+ depends on PPC_CHRP || PPC_PMAC
+
+config I2C_HYDRA
+ tristate "CHRP Apple Hydra Mac I/O I2C interface"
+ depends on PCI && PPC_CHRP
+ select I2C_ALGOBIT
+ help
+ This supports the use of the I2C interface in the Apple Hydra Mac
+ I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you
+ have such a machine.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-hydra.
+
+config I2C_POWERMAC
+ tristate "Powermac I2C interface"
+ depends on PPC_PMAC
+ default y
+ help
+ This exposes the various PowerMac i2c interfaces to the linux i2c
+ layer and to userland. It is used by various drivers on the PowerMac
+ platform, and should generally be enabled.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-powermac.
+
+comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
+config I2C_ALTERA
+ tristate "Altera Soft IP I2C"
+ depends on (ARCH_SOCFPGA || NIOS2) && OF
+ help
+ If you say yes to this option, support will be included for the
+ Altera Soft IP I2C interfaces on SoCFPGA and Nios2 architectures.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-altera.
+
+config I2C_ASPEED
+ tristate "Aspeed I2C Controller"
+ depends on ARCH_ASPEED || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ Aspeed I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-aspeed.
+
+config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on ARCH_AT91
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
+ A serious problem is that there is no documented way to issue
+ repeated START conditions for more than two messages, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+ unless your system can cope with this limitation.
+
+ Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices
+ don't have clock stretching in transmission mode. For that reason,
+ you can encounter underrun issues causing premature stop sendings if
+ the latency to fill the transmission register is too long. If you
+ are facing this situation, use the i2c-gpio driver.
+
+config I2C_AU1550
+ tristate "Au1550/Au1200/Au1300 SMBus interface"
+ depends on MIPS_ALCHEMY
+ help
+ If you say yes to this option, support will be included for the
+ Au1550/Au1200/Au1300 SMBus interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-au1550.
+
+config I2C_AXXIA
+ tristate "Axxia I2C controller"
+ depends on ARCH_AXXIA || COMPILE_TEST
+ default ARCH_AXXIA
+ help
+ Say yes if you want to support the I2C bus on Axxia platforms.
+
+ Please note that this controller is limited to transfers of maximum
+ 255 bytes in length. Any attempt to to a larger transfer will return
+ an error.
+
+config I2C_BCM2835
+ tristate "Broadcom BCM2835 I2C controller"
+ depends on ARCH_BCM2835
+ help
+ If you say yes to this option, support will be included for the
+ BCM2835 I2C controller.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-bcm2835.
+
+config I2C_BCM_IPROC
+ tristate "Broadcom iProc I2C controller"
+ depends on ARCH_BCM_IPROC || COMPILE_TEST
+ default ARCH_BCM_IPROC
+ help
+ If you say yes to this option, support will be included for the
+ Broadcom iProc I2C controller.
+
+ If you don't know what to do here, say N.
+
+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 interface, say N.
+
+config I2C_BRCMSTB
+ tristate "BRCM Settop/DSL I2C controller"
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_63XX || \
+ COMPILE_TEST
+ default y
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Broadcom Settop/DSL SoCs.
+
+ If you do not need I2C interface, say N.
+
+config I2C_CADENCE
+ tristate "Cadence I2C Controller"
+ depends on ARCH_ZYNQ || ARM64 || XTENSA || COMPILE_TEST
+ help
+ Say yes here to select Cadence I2C Host Controller. This controller is
+ e.g. used by Xilinx Zynq.
+
+config I2C_CBUS_GPIO
+ tristate "CBUS I2C driver"
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Support for CBUS access using I2C API. Mostly relevant for Nokia
+ Internet Tablets (770, N800 and N810).
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-cbus-gpio.
+
+config I2C_CPM
+ tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
+ depends on CPM1 || CPM2
+ help
+ This supports the use of the I2C interface on Freescale
+ processors with CPM1 or CPM2.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-cpm.
+
+config I2C_DAVINCI
+ tristate "DaVinci I2C driver"
+ depends on ARCH_DAVINCI || ARCH_KEYSTONE
+ help
+ Support for TI DaVinci I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-davinci.
+
+ Please note that this driver might be needed to bring up other
+ devices such as DaVinci NIC.
+ For details please see http://www.ti.com/davinci
+
+config I2C_DESIGNWARE_CORE
+ tristate
+
+config I2C_DESIGNWARE_PLATFORM
+ tristate "Synopsys DesignWare Platform"
+ select I2C_DESIGNWARE_CORE
+ depends on (ACPI && COMMON_CLK) || !ACPI
+ help
+ If you say yes to this option, support will be included for the
+ Synopsys DesignWare I2C adapter.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-designware-platform.
+
+config I2C_DESIGNWARE_SLAVE
+ bool "Synopsys DesignWare Slave"
+ select I2C_SLAVE
+ depends on I2C_DESIGNWARE_PLATFORM
+ help
+ If you say yes to this option, support will be included for the
+ Synopsys DesignWare I2C slave adapter.
+
+ This is not a standalone module, this module compiles together with
+ i2c-designware-core.
+
+config I2C_DESIGNWARE_PCI
+ tristate "Synopsys DesignWare PCI"
+ depends on PCI
+ select I2C_DESIGNWARE_CORE
+ help
+ If you say yes to this option, support will be included for the
+ Synopsys DesignWare I2C adapter. Only master mode is supported.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-designware-pci.
+
+config I2C_DESIGNWARE_BAYTRAIL
+ bool "Intel Baytrail I2C semaphore support"
+ depends on ACPI
+ depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \
+ (I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y)
+ help
+ This driver enables managed host access to the PMIC I2C bus on select
+ Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
+ the host to request uninterrupted access to the PMIC's I2C bus from
+ the platform firmware controlling it. You should say Y if running on
+ a BayTrail system using the AXP288.
+
+config I2C_DIGICOLOR
+ tristate "Conexant Digicolor I2C driver"
+ depends on ARCH_DIGICOLOR
+ help
+ Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-digicolor.
+
+config I2C_EFM32
+ tristate "EFM32 I2C controller"
+ depends on ARCH_EFM32 || COMPILE_TEST
+ help
+ This driver supports the i2c block found in Energy Micro's EFM32
+ SoCs.
+
+config I2C_EG20T
+ tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
+ help
+ This driver is for PCH(Platform controller Hub) I2C of EG20T which
+ is an IOH(Input/Output Hub) for x86 embedded processor.
+ This driver can access PCH I2C bus device.
+
+ This driver also can be used for LAPIS Semiconductor IOH(Input/
+ Output Hub), ML7213, ML7223 and ML7831.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+ for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+ ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+
+config I2C_EMEV2
+ tristate "EMMA Mobile series I2C adapter"
+ depends on HAVE_CLK
+ select I2C_SLAVE
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Renesas Electronics EM/EV family of processors.
+
+config I2C_EXYNOS5
+ tristate "Exynos5 high-speed I2C driver"
+ depends on ARCH_EXYNOS && OF
+ default y
+ help
+ High-speed I2C controller on Exynos5 based Samsung SoCs.
+
+config I2C_GPIO
+ tristate "GPIO-based bitbanging I2C"
+ depends on GPIOLIB || COMPILE_TEST
+ select I2C_ALGOBIT
+ help
+ This is a very simple bitbanging I2C driver utilizing the
+ arch-neutral GPIO API to control the SCL and SDA lines.
+
+config I2C_GPIO_FAULT_INJECTOR
+ bool "GPIO-based fault injector"
+ depends on I2C_GPIO
+ help
+ This adds some functionality to the i2c-gpio driver which can inject
+ faults to an I2C bus, so another bus master can be stress-tested.
+ This is for debugging. If unsure, say 'no'.
+
+config I2C_HIGHLANDER
+ tristate "Highlander FPGA SMBus interface"
+ depends on SH_HIGHLANDER
+ help
+ If you say yes to this option, support will be included for
+ the SMBus interface located in the FPGA on various Highlander
+ boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+ FPGAs. This is wholly unrelated to the SoC I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-highlander.
+
+config I2C_IBM_IIC
+ tristate "IBM PPC 4xx on-chip I2C interface"
+ depends on 4xx
+ help
+ Say Y here if you want to use IIC peripheral found on
+ embedded IBM PPC 4xx based systems.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ibm_iic.
+
+config I2C_IMG
+ tristate "Imagination Technologies I2C SCB Controller"
+ depends on MIPS || COMPILE_TEST
+ help
+ Say Y here if you want to use the IMG I2C SCB controller,
+ available on the TZ1090 and other IMG SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-img-scb.
+
+config I2C_IMX
+ tristate "IMX I2C interface"
+ depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Freescale i.MX/MXC, Layerscape or ColdFire processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-imx.
+
+config I2C_IMX_LPI2C
+ tristate "IMX Low Power I2C interface"
+ depends on ARCH_MXC || COMPILE_TEST
+ help
+ Say Y here if you want to use the Low Power IIC bus controller
+ on the Freescale i.MX processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-imx-lpi2c.
+
+config I2C_IOP3XX
+ tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-iop3xx.
+
+config I2C_JZ4780
+ tristate "JZ4780 I2C controller interface support"
+ depends on MACH_JZ4780 || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ Ingenic JZ4780 I2C controller.
+
+ If you don't know what to do here, say N.
+
+config I2C_KEMPLD
+ tristate "Kontron COM I2C Controller"
+ depends on MFD_KEMPLD
+ help
+ This enables support for the I2C bus interface on some Kontron ETX
+ and COMexpress (ETXexpress) modules.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-kempld.
+
+config I2C_LPC2K
+ tristate "I2C bus support for NXP LPC2K/LPC178x/18xx/43xx"
+ depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
+ help
+ This driver supports the I2C interface found several NXP
+ devices including LPC2xxx, LPC178x/7x and LPC18xx/43xx.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-lpc2k.
+
+config I2C_MESON
+ tristate "Amlogic Meson I2C controller"
+ depends on ARCH_MESON || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Amlogic Meson family of SoCs.
+
+config I2C_MPC
+ tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
+ depends on PPC
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
+ MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mpc.
+
+config I2C_MT65XX
+ tristate "MediaTek I2C adapter"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ help
+ This selects the MediaTek(R) Integrated Inter Circuit bus driver
+ for MT65xx and MT81xx.
+ If you want to use MediaTek(R) I2C interface, say Y or M here.
+ If unsure, say N.
+
+config I2C_MV64XXX
+ tristate "Marvell mv64xxx I2C Controller"
+ depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Marvell 64xxx line of host bridges.
+ This driver is also used for Allwinner SoCs I2C controllers.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mv64xxx.
+
+config I2C_MXS
+ tristate "Freescale i.MX28 I2C interface"
+ depends on SOC_IMX28
+ select STMP_DEVICE
+ help
+ Say Y here if you want to use the I2C bus controller on
+ the Freescale i.MX28 processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mxs.
+
+config I2C_NOMADIK
+ tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
+ depends on ARM_AMBA
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
+ as well as the STA2X11 PCIe I/O HUB.
+
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+ http://www.opencores.org/projects.cgi/web/i2c/overview
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ocores.
+
+config I2C_OMAP
+ tristate "OMAP I2C adapter"
+ depends on ARCH_OMAP || ARCH_K3
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Texas Instruments OMAP1/2 family of processors.
+ Like OMAP1510/1610/1710/5912 and OMAP242x.
+ For details see http://www.ti.com/omap.
+
+config I2C_OWL
+ tristate "Actions Semiconductor Owl I2C Controller"
+ depends on ARCH_ACTIONS || COMPILE_TEST
+ help
+ Say Y here if you want to use the I2C bus controller on
+ the Actions Semiconductor Owl SoC's.
+
+config I2C_PASEMI
+ tristate "PA Semi SMBus interface"
+ depends on PPC_PASEMI && PCI
+ help
+ Supports the PA Semi PWRficient on-chip SMBus interfaces.
+
+config I2C_PCA_PLATFORM
+ tristate "PCA9564/PCA9665 as platform device"
+ select I2C_ALGOPCA
+ default n
+ help
+ This driver supports a memory mapped Philips PCA9564/PCA9665
+ parallel bus to I2C bus controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pca-platform.
+
+config I2C_PMCMSP
+ tristate "PMC MSP I2C TWI Controller"
+ depends on PMC_MSP
+ help
+ This driver supports the PMC TWI controller on MSP devices.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-pmcmsp.
+
+config I2C_PNX
+ tristate "I2C bus support for Philips PNX and NXP LPC targets"
+ depends on ARCH_LPC32XX
+ help
+ This driver supports the Philips IP3204 I2C IP block master and/or
+ slave controller
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pnx.
+
+config I2C_PUV3
+ tristate "PKUnity v3 I2C bus support"
+ depends on UNICORE32 && ARCH_PUV3
+ select I2C_ALGOBIT
+ help
+ This driver supports the I2C IP inside the PKUnity-v3 SoC.
+ This I2C bus controller is under AMBA/AXI bus.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-puv3.
+
+config I2C_PXA
+ tristate "Intel PXA2XX I2C adapter"
+ depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF)
+ help
+ If you have devices in the PXA I2C bus, say yes to this option.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pxa.
+
+config I2C_PXA_PCI
+ def_bool I2C_PXA && X86_32 && PCI && OF
+
+config I2C_PXA_SLAVE
+ bool "Intel PXA2XX I2C Slave comms support"
+ depends on I2C_PXA && !X86_32
+ help
+ Support I2C slave mode communications on the PXA I2C bus. This
+ is necessary for systems where the PXA may be a target on the
+ I2C bus.
+
+config I2C_QCOM_GENI
+ tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on QCOM_GENI_SE
+ help
+ This driver supports GENI serial engine based I2C controller in
+ master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
+ yes to this option, support will be included for the built-in I2C
+ interface on the Qualcomm Technologies Inc.'s SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-qcom-geni.
+
+config I2C_QUP
+ tristate "Qualcomm QUP based I2C controller"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ built-in I2C interface on the Qualcomm SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-qup.
+
+config I2C_RIIC
+ tristate "Renesas RIIC adapter"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ Renesas RIIC I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-riic.
+
+config I2C_RK3X
+ tristate "Rockchip RK3xxx I2C adapter"
+ depends on OF && COMMON_CLK
+ help
+ Say Y here to include support for the I2C adapter in Rockchip RK3xxx
+ SoCs.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-rk3x.
+
+config HAVE_S3C2410_I2C
+ bool
+ help
+ This will include I2C support for Samsung SoCs. If you want to
+ include I2C support for any machine, kindly select this in the
+ respective Kconfig file.
+
+config I2C_S3C2410
+ tristate "S3C2410 I2C Driver"
+ depends on HAVE_S3C2410_I2C
+ help
+ Say Y here to include support for I2C controller in the
+ Samsung SoCs.
+
+config I2C_SH7760
+ tristate "Renesas SH7760 I2C Controller"
+ depends on CPU_SUBTYPE_SH7760
+ help
+ This driver supports the 2 I2C interfaces on the Renesas SH7760.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sh7760.
+
+config I2C_SH_MOBILE
+ tristate "SuperH Mobile I2C Controller"
+ depends on ARCH_SHMOBILE || ARCH_RENESAS || 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.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sh_mobile.
+
+config I2C_SIMTEC
+ tristate "Simtec Generic I2C interface"
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be included for
+ the Simtec Generic I2C interface. This driver is for the
+ simple I2C bus used on newer Simtec products for general
+ I2C, such as DDC on the Simtec BBD2016A.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-simtec.
+
+config I2C_SIRF
+ tristate "CSR SiRFprimaII I2C interface"
+ depends on ARCH_SIRF
+ help
+ If you say yes to this option, support will be included for the
+ CSR SiRFprimaII I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-sirf.
+
+config I2C_SPRD
+ bool "Spreadtrum I2C interface"
+ depends on I2C=y && ARCH_SPRD
+ help
+ If you say yes to this option, support will be included for the
+ Spreadtrum I2C interface.
+
+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_STM32F4
+ tristate "STMicroelectronics STM32F4 I2C support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ Enable this option to add support for STM32 I2C controller embedded
+ in STM32F4 SoCs.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-stm32f4.
+
+config I2C_STM32F7
+ tristate "STMicroelectronics STM32F7 I2C support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ select I2C_SLAVE
+ help
+ Enable this option to add support for STM32 I2C controller embedded
+ in STM32F7 SoCs.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-stm32f7.
+
+config I2C_STU300
+ tristate "ST Microelectronics DDC I2C interface"
+ depends on MACH_U300
+ default y if MACH_U300
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface from ST Microelectronics simply called "DDC I2C"
+ supporting both I2C and DDC, used in e.g. the U300 series
+ mobile platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-stu300.
+
+config I2C_SUN6I_P2WI
+ tristate "Allwinner sun6i internal P2WI controller"
+ depends on RESET_CONTROLLER
+ depends on MACH_SUN6I || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ P2WI (Push/Pull 2 Wire Interface) controller embedded in some sunxi
+ SOCs.
+ The P2WI looks like an SMBus controller (which supports only byte
+ accesses), except that it only supports one slave device.
+ This interface is used to connect to specific PMIC devices (like the
+ AXP221).
+
+config I2C_SYNQUACER
+ tristate "Socionext SynQuacer I2C controller"
+ depends on ARCH_SYNQUACER || COMPILE_TEST
+ help
+ Say Y here to include support for the I2C controller used in some
+ Fujitsu and Socionext SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-synquacer.
+
+config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+
+config I2C_TEGRA_BPMP
+ tristate "NVIDIA Tegra BPMP I2C controller"
+ depends on TEGRA_BPMP
+ default y
+ help
+ If you say yes to this option, support will be included for the I2C
+ controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
+
+ This I2C driver is a 'virtual' I2C driver. The real driver is part
+ of the BPMP firmware, and this driver merely communicates with that
+ real driver.
+
+config I2C_UNIPHIER
+ tristate "UniPhier FIFO-less I2C controller"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for
+ the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8,
+ or older UniPhier SoCs.
+
+config I2C_UNIPHIER_F
+ tristate "UniPhier FIFO-builtin I2C controller"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for
+ the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4,
+ PH1-Pro5, or newer UniPhier SoCs.
+
+config I2C_VERSATILE
+ tristate "ARM Versatile/Realview I2C bus support"
+ depends on ARCH_MPS2 || ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || COMPILE_TEST
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C serial bus on ARMs Versatile
+ range of platforms.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-versatile.
+
+config I2C_WMT
+ tristate "Wondermedia WM8xxx SoC I2C bus support"
+ depends on ARCH_VT8500
+ help
+ Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
+ SoCs.
+
+ This driver can also be built as a module. If so, the module will be
+ called i2c-wmt.
+
+config I2C_OCTEON
+ tristate "Cavium OCTEON I2C bus support"
+ depends on CAVIUM_OCTEON_SOC
+ help
+ Say yes if you want to support the I2C serial bus on Cavium
+ OCTEON SOC.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-octeon.
+
+config I2C_THUNDERX
+ tristate "Cavium ThunderX I2C bus support"
+ depends on 64BIT && PCI && (ARM64 || COMPILE_TEST)
+ select I2C_SMBUS
+ help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-thunderx.
+
+config I2C_XILINX
+ tristate "Xilinx I2C Controller"
+ depends on HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ Xilinx I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called xilinx_i2c.
+
+config I2C_XLR
+ tristate "Netlogic XLR and Sigma Designs I2C support"
+ depends on CPU_XLR || ARCH_TANGO
+ help
+ This driver enables support for the on-chip I2C interface of
+ the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-xlr.
+
+config I2C_XLP9XX
+ tristate "XLP9XX I2C support"
+ depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
+ help
+ This driver enables support for the on-chip I2C interface of
+ the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-xlp9xx.
+
+config I2C_RCAR
+ tristate "Renesas R-Car I2C Controller"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ select I2C_SLAVE
+ select RESET_CONTROLLER if ARCH_RCAR_GEN3
+ help
+ If you say yes to this option, support will be included for the
+ R-Car I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-rcar.
+
+comment "External I2C/SMBus adapter drivers"
+
+config I2C_DIOLAN_U2C
+ tristate "Diolan U2C-12 USB adapter"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for Diolan
+ U2C-12, a USB to I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-diolan-u2c.
+
+config I2C_DLN2
+ tristate "Diolan DLN-2 USB I2C adapter"
+ depends on MFD_DLN2
+ help
+ If you say yes to this option, support will be included for Diolan
+ DLN2, a USB to I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-dln2.
+
+config I2C_PARPORT
+ tristate "Parallel port adapter"
+ depends on PARPORT
+ select I2C_ALGOBIT
+ select I2C_SMBUS
+ help
+ This supports parallel port I2C adapters such as the ones made by
+ Philips or Velleman, Analog Devices evaluation boards, and more.
+ Basically any adapter using the parallel port as an I2C bus with
+ no extra chipset is supported by this driver, or could be.
+
+ This driver is a replacement for (and was inspired by) an older
+ driver named i2c-philips-par. The new driver supports more devices,
+ and makes it easier to add support for new devices.
+
+ An adapter type parameter is now mandatory. Please read the file
+ Documentation/i2c/busses/i2c-parport for details.
+
+ Another driver exists, named i2c-parport-light, which doesn't depend
+ on the parport driver. This is meant for embedded systems. Don't say
+ Y here if you intend to say Y or M there.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-parport.
+
+config I2C_PARPORT_LIGHT
+ tristate "Parallel port adapter (light)"
+ select I2C_ALGOBIT
+ select I2C_SMBUS
+ help
+ This supports parallel port I2C adapters such as the ones made by
+ Philips or Velleman, Analog Devices evaluation boards, and more.
+ Basically any adapter using the parallel port as an I2C bus with
+ no extra chipset is supported by this driver, or could be.
+
+ This driver is a light version of i2c-parport. It doesn't depend
+ on the parport driver, and uses direct I/O access instead. This
+ might be preferred on embedded systems where wasting memory for
+ the clean but heavy parport handling is not an option. The
+ drawback is a reduced portability and the impossibility to
+ daisy-chain other parallel port devices.
+
+ Don't say Y here if you said Y or M to i2c-parport. Saying M to
+ both is possible but both modules should not be loaded at the same
+ time.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-parport-light.
+
+config I2C_ROBOTFUZZ_OSIF
+ tristate "RobotFuzz Open Source InterFace USB adapter"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for the
+ RobotFuzz Open Source InterFace USB to I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-osif.
+
+config I2C_TAOS_EVM
+ tristate "TAOS evaluation module"
+ depends on TTY
+ select SERIO
+ select SERIO_SERPORT
+ default n
+ help
+ This supports TAOS evaluation modules on serial port. In order to
+ use this driver, you will need the inputattach tool, which is part
+ of the input-utils package.
+
+ If unsure, say N.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-taos-evm.
+
+config I2C_TINY_USB
+ tristate "Tiny-USB adapter"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for the
+ i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
+ http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-tiny-usb.
+
+config I2C_VIPERBOARD
+ tristate "Viperboard I2C master support"
+ depends on MFD_VIPERBOARD && USB
+ help
+ Say yes here to access the I2C part of the Nano River
+ Technologies Viperboard as I2C master.
+ See viperboard API specification and Nano
+ River Tech's viperboard.h for detailed meaning
+ of the module parameters.
+
+comment "Other I2C/SMBus bus drivers"
+
+config I2C_ACORN
+ tristate "Acorn IOC/IOMD I2C bus support"
+ depends on ARCH_ACORN
+ default y
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C bus on Acorn platforms.
+
+ If you don't know, say Y.
+
+config I2C_ELEKTOR
+ tristate "Elektor ISA card"
+ depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP
+ select I2C_ALGOPCF
+ help
+ This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
+ such an adapter.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-elektor.
+
+config I2C_MLXCPLD
+ tristate "Mellanox I2C driver"
+ depends on X86_64
+ help
+ This exposes the Mellanox platform I2C busses to the linux I2C layer
+ for X86 based systems.
+ Controller is implemented as CPLD logic.
+
+ This driver can also be built as a module. If so, the module will be
+ called as i2c-mlxcpld.
+
+config I2C_PCA_ISA
+ tristate "PCA9564/PCA9665 on an ISA bus"
+ depends on ISA
+ select I2C_ALGOPCA
+ default n
+ help
+ This driver supports ISA boards using the Philips PCA9564/PCA9665
+ parallel bus to I2C bus controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pca-isa.
+
+ This device is almost undetectable and using this driver on a
+ system which doesn't have this device will result in long
+ delays when I2C/SMBus chip drivers are loaded (e.g. at boot
+ time). If unsure, say N.
+
+config I2C_SIBYTE
+ tristate "SiByte SMBus interface"
+ depends on SIBYTE_SB1xxx_SOC
+ help
+ Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+
+config I2C_CROS_EC_TUNNEL
+ tristate "ChromeOS EC tunnel I2C bus"
+ depends on MFD_CROS_EC
+ help
+ If you say yes here you get an I2C bus that will tunnel i2c commands
+ through to the other side of the ChromeOS EC to the i2c bus
+ connected there. This will work whatever the interface used to
+ talk to the EC (SPI, I2C or LPC).
+
+config I2C_XGENE_SLIMPRO
+ tristate "APM X-Gene SoC I2C SLIMpro devices support"
+ depends on ARCH_XGENE && MAILBOX
+ help
+ Enable I2C bus access using the APM X-Gene SoC SLIMpro
+ co-processor. The I2C device access the I2C bus via the X-Gene
+ to SLIMpro (On chip coprocessor) mailbox mechanism.
+ If unsure, say N.
+
+config SCx200_ACB
+ tristate "Geode ACCESS.bus support"
+ depends on X86_32 && PCI
+ help
+ Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
+ SC1100 processors and the CS5535 and CS5536 Geode companion devices.
+
+ If you don't know what to do here, say N.
+
+ This support is also available as a module. If so, the module
+ will be called scx200_acb.
+
+config I2C_OPAL
+ tristate "IBM OPAL I2C driver"
+ depends on PPC_POWERNV
+ default y
+ help
+ This exposes the PowerNV platform i2c busses to the linux i2c layer,
+ the driver is based on the OPAL interfaces.
+
+ This driver can also be built as a module. If so, the module will be
+ called as i2c-opal.
+
+config I2C_ZX2967
+ tristate "ZTE ZX2967 I2C support"
+ depends on ARCH_ZX
+ default y
+ help
+ Selecting this option will add ZX2967 I2C driver.
+ This driver can also be built as a module. If so, the module will be
+ called i2c-zx2967.
+
+config I2C_FSI
+ tristate "FSI I2C driver"
+ depends on FSI
+ help
+ Driver for FSI bus attached I2C masters. These are I2C masters that
+ are connected to the system over an FSI bus, instead of the more
+ common PCI or MMIO interface.
+
+ This driver can also be built as a module. If so, the module will be
+ called as i2c-fsi.
+
+endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
new file mode 100644
index 000000000..18b26af82
--- /dev/null
+++ b/drivers/i2c/busses/Makefile
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the i2c bus drivers.
+#
+
+# ACPI drivers
+obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
+
+# PC SMBus host controller drivers
+obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
+obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
+obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
+obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
+obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
+obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
+obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o
+obj-$(CONFIG_I2C_I801) += i2c-i801.o
+obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
+obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o
+obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
+obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
+obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
+obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
+obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
+obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
+obj-$(CONFIG_I2C_VIA) += i2c-via.o
+obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
+
+# Mac SMBus host controller drivers
+obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+# Embedded system I2C/SMBus host controller drivers
+obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o
+obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
+obj-$(CONFIG_I2C_AT91) += i2c-at91.o
+obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
+obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
+obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o
+obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
+obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
+obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
+obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
+i2c-designware-core-objs := i2c-designware-common.o i2c-designware-master.o
+ifeq ($(CONFIG_I2C_DESIGNWARE_SLAVE),y)
+i2c-designware-core-objs += i2c-designware-slave.o
+endif
+obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
+i2c-designware-platform-objs := i2c-designware-platdrv.o
+i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
+obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
+i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o
+obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
+obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
+obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.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_HIX5HD2) += i2c-hix5hd2.o
+obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
+obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
+obj-$(CONFIG_I2C_IMX) += i2c-imx.o
+obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o
+obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
+obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
+obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
+obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
+obj-$(CONFIG_I2C_MESON) += i2c-meson.o
+obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
+obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o
+obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
+obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
+obj-$(CONFIG_I2C_OWL) += i2c-owl.o
+obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
+obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
+obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
+obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
+obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
+obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
+obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
+obj-$(CONFIG_I2C_QUP) += i2c-qup.o
+obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
+obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
+obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
+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_SPRD) += i2c-sprd.o
+obj-$(CONFIG_I2C_ST) += i2c-st.o
+obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
+i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o
+obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o
+obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
+obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
+obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o
+obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
+obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o
+obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
+obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
+obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
+i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
+obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
+i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
+obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
+obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
+obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
+obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
+obj-$(CONFIG_I2C_ZX2967) += i2c-zx2967.o
+
+# External I2C/SMBus adapter drivers
+obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
+obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
+obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
+obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
+obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
+obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
+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_BRCMSTB) += i2c-brcmstb.o
+obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
+obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o
+obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
+obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
+obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
+obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+obj-$(CONFIG_I2C_FSI) += i2c-fsi.o
+
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
new file mode 100644
index 000000000..fa3763e4b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -0,0 +1,99 @@
+/*
+ * ARM IOC/IOMD i2c driver.
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ * On Acorn machines, the following i2c devices are on the bus:
+ * - PCF8583 real time clock & static RAM
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/ioc.h>
+
+#define FORCE_ONES 0xdc
+#define SCL 0x02
+#define SDA 0x01
+
+/*
+ * We must preserve all non-i2c output bits in IOC_CONTROL.
+ * Note also that we need to preserve the value of SCL and
+ * SDA outputs as well (which may be different from the
+ * values read back from IOC_CONTROL).
+ */
+static u_int force_ones;
+
+static void ioc_setscl(void *data, int state)
+{
+ u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+ u_int ones = force_ones;
+
+ if (state)
+ ones |= SCL;
+ else
+ ones &= ~SCL;
+
+ force_ones = ones;
+
+ ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static void ioc_setsda(void *data, int state)
+{
+ u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+ u_int ones = force_ones;
+
+ if (state)
+ ones |= SDA;
+ else
+ ones &= ~SDA;
+
+ force_ones = ones;
+
+ ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static int ioc_getscl(void *data)
+{
+ return (ioc_readb(IOC_CONTROL) & SCL) != 0;
+}
+
+static int ioc_getsda(void *data)
+{
+ return (ioc_readb(IOC_CONTROL) & SDA) != 0;
+}
+
+static struct i2c_algo_bit_data ioc_data = {
+ .setsda = ioc_setsda,
+ .setscl = ioc_setscl,
+ .getsda = ioc_getsda,
+ .getscl = ioc_getscl,
+ .udelay = 80,
+ .timeout = HZ,
+};
+
+static struct i2c_adapter ioc_ops = {
+ .nr = 0,
+ .name = "ioc",
+ .algo_data = &ioc_data,
+};
+
+static int __init i2c_ioc_init(void)
+{
+ force_ones = FORCE_ONES | SCL | SDA;
+
+ return i2c_bit_add_numbered_bus(&ioc_ops);
+}
+
+module_init(i2c_ioc_init);
+
+MODULE_AUTHOR("Russell King <linux@armlinux.org.uk>");
+MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
new file mode 100644
index 000000000..4f2d78868
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
+ * Philip Edelbrock <phil@netroedge.com>,
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ * Dan Eaton <dan.eaton@rocketlogix.com> and
+ * Stephen Rousset <stephen.rousset@rocketlogix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+/*
+ This is the driver for the SMB Host controller on
+ Acer Labs Inc. (ALI) M1535 South Bridge.
+
+ The M1535 is a South bridge for portable systems.
+ It is very similar to the M15x3 South bridges also produced
+ by Acer Labs Inc. Some of the registers within the part
+ have moved and some have been redefined slightly. Additionally,
+ the sequencing of the SMBus transactions has been modified
+ to be more consistent with the sequencing recommended by
+ the manufacturer and observed through testing. These
+ changes are reflected in this driver and can be identified
+ by comparing this driver to the i2c-ali15x3 driver.
+ For an overview of these chips see http://www.acerlabs.com
+
+ The SMB controller is part of the 7101 device, which is an
+ ACPI-compliant Power Management Unit (PMU).
+
+ The whole 7101 device has to be enabled for the SMB to work.
+ You can't just enable the SMB alone.
+ The SMB and the ACPI have separate I/O spaces.
+ We make sure that the SMB is enabled. We leave the ACPI alone.
+
+ This driver controls the SMB Host only.
+
+ This driver does not use interrupts.
+*/
+
+
+/* Note: we assume there can only be one ALI1535, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/* ALI1535 SMBus address offsets */
+#define SMBHSTSTS (0 + ali1535_smba)
+#define SMBHSTTYP (1 + ali1535_smba)
+#define SMBHSTPORT (2 + ali1535_smba)
+#define SMBHSTCMD (7 + ali1535_smba)
+#define SMBHSTADD (3 + ali1535_smba)
+#define SMBHSTDAT0 (4 + ali1535_smba)
+#define SMBHSTDAT1 (5 + ali1535_smba)
+#define SMBBLKDAT (6 + ali1535_smba)
+
+/* PCI Address Constants */
+#define SMBCOM 0x004
+#define SMBREV 0x008
+#define SMBCFG 0x0D1
+#define SMBBA 0x0E2
+#define SMBHSTCFG 0x0F0
+#define SMBCLK 0x0F2
+
+/* Other settings */
+#define MAX_TIMEOUT 500 /* times 1/100 sec */
+#define ALI1535_SMB_IOSIZE 32
+
+#define ALI1535_SMB_DEFAULTBASE 0x8040
+
+/* ALI1535 address lock bits */
+#define ALI1535_LOCK 0x06 /* dwe */
+
+/* ALI1535 command constants */
+#define ALI1535_QUICK 0x00
+#define ALI1535_BYTE 0x10
+#define ALI1535_BYTE_DATA 0x20
+#define ALI1535_WORD_DATA 0x30
+#define ALI1535_BLOCK_DATA 0x40
+#define ALI1535_I2C_READ 0x60
+
+#define ALI1535_DEV10B_EN 0x80 /* Enable 10-bit addressing in */
+ /* I2C read */
+#define ALI1535_T_OUT 0x08 /* Time-out Command (write) */
+#define ALI1535_A_HIGH_BIT9 0x08 /* Bit 9 of 10-bit address in */
+ /* Alert-Response-Address */
+ /* (read) */
+#define ALI1535_KILL 0x04 /* Kill Command (write) */
+#define ALI1535_A_HIGH_BIT8 0x04 /* Bit 8 of 10-bit address in */
+ /* Alert-Response-Address */
+ /* (read) */
+
+#define ALI1535_D_HI_MASK 0x03 /* Mask for isolating bits 9-8 */
+ /* of 10-bit address in I2C */
+ /* Read Command */
+
+/* ALI1535 status register bits */
+#define ALI1535_STS_IDLE 0x04
+#define ALI1535_STS_BUSY 0x08 /* host busy */
+#define ALI1535_STS_DONE 0x10 /* transaction complete */
+#define ALI1535_STS_DEV 0x20 /* device error */
+#define ALI1535_STS_BUSERR 0x40 /* bus error */
+#define ALI1535_STS_FAIL 0x80 /* failed bus transaction */
+#define ALI1535_STS_ERR 0xE0 /* all the bad error bits */
+
+#define ALI1535_BLOCK_CLR 0x04 /* reset block data index */
+
+/* ALI1535 device address register bits */
+#define ALI1535_RD_ADDR 0x01 /* Read/Write Bit in Device */
+ /* Address field */
+ /* -> Write = 0 */
+ /* -> Read = 1 */
+#define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */
+
+static struct pci_driver ali1535_driver;
+static unsigned long ali1535_smba;
+static unsigned short ali1535_offset;
+
+/* Detect whether a ALI1535 can be found, and initialize it, where necessary.
+ Note the differences between kernels with the old PCI BIOS interface and
+ newer kernels with the real PCI interface. In compat.h some things are
+ defined to make the transition easier. */
+static int ali1535_setup(struct pci_dev *dev)
+{
+ int retval;
+ unsigned char temp;
+
+ /* Check the following things:
+ - SMB I/O address is initialized
+ - Device is enabled
+ - We can use the addresses
+ */
+
+ retval = pci_enable_device(dev);
+ if (retval) {
+ dev_err(&dev->dev, "ALI1535_smb can't enable device\n");
+ goto exit;
+ }
+
+ /* Determine the address of the SMBus area */
+ pci_read_config_word(dev, SMBBA, &ali1535_offset);
+ dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset);
+ ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
+ if (ali1535_offset == 0) {
+ dev_warn(&dev->dev,
+ "ALI1535_smb region uninitialized - upgrade BIOS?\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (pci_resource_flags(dev, 0) & IORESOURCE_IO)
+ ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset;
+ else
+ ali1535_smba = ali1535_offset;
+
+ retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
+ ali1535_driver.name);
+ if (retval)
+ goto exit;
+
+ if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
+ ali1535_driver.name)) {
+ dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n",
+ ali1535_smba);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ /* check if whole device is enabled */
+ pci_read_config_byte(dev, SMBCFG, &temp);
+ if ((temp & ALI1535_SMBIO_EN) == 0) {
+ dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
+ retval = -ENODEV;
+ goto exit_free;
+ }
+
+ /* Is SMB Host controller enabled? */
+ pci_read_config_byte(dev, SMBHSTCFG, &temp);
+ if ((temp & 1) == 0) {
+ dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
+ retval = -ENODEV;
+ goto exit_free;
+ }
+
+ /* set SMB clock to 74KHz as recommended in data sheet */
+ pci_write_config_byte(dev, SMBCLK, 0x20);
+
+ /*
+ The interrupt routing for SMB is set up in register 0x77 in the
+ 1533 ISA Bridge device, NOT in the 7101 device.
+ Don't bother with finding the 1533 device and reading the register.
+ if ((....... & 0x0F) == 1)
+ dev_dbg(&dev->dev, "ALI1535 using Interrupt 9 for SMBus.\n");
+ */
+ pci_read_config_byte(dev, SMBREV, &temp);
+ dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba);
+
+ return 0;
+
+exit_free:
+ release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+exit:
+ return retval;
+}
+
+static int ali1535_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, TYP=%02x, "
+ "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
+ inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+ /* get status */
+ temp = inb_p(SMBHSTSTS);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ /* Check the busy bit first */
+ if (temp & ALI1535_STS_BUSY) {
+ /* If the host controller is still busy, it may have timed out
+ * in the previous transaction, resulting in a "SMBus Timeout"
+ * printk. I've tried the following to reset a stuck busy bit.
+ * 1. Reset the controller with an KILL command. (this
+ * doesn't seem to clear the controller if an external
+ * device is hung)
+ * 2. Reset the controller and the other SMBus devices with a
+ * T_OUT command. (this clears the host busy bit if an
+ * external device is hung, but it comes back upon a new
+ * access to a device)
+ * 3. Disable and reenable the controller in SMBHSTCFG. Worst
+ * case, nothing seems to work except power reset.
+ */
+
+ /* Try resetting entire SMB bus, including other devices - This
+ * may not work either - it clears the BUSY bit but then the
+ * BUSY bit may come back on when you try and use the chip
+ * again. If that's the case you are stuck.
+ */
+ dev_info(&adap->dev,
+ "Resetting entire SMB Bus to clear busy condition (%02x)\n",
+ temp);
+ outb_p(ALI1535_T_OUT, SMBHSTTYP);
+ temp = inb_p(SMBHSTSTS);
+ }
+
+ /* now check the error bits and the busy bit */
+ if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+ /* do a clear-on-write */
+ outb_p(0xFF, SMBHSTSTS);
+ temp = inb_p(SMBHSTSTS);
+ if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+ /* This is probably going to be correctable only by a
+ * power reset as one of the bits now appears to be
+ * stuck */
+ /* This may be a bus or device with electrical problems. */
+ dev_err(&adap->dev,
+ "SMBus reset failed! (0x%02x) - controller or "
+ "device on bus is probably hung\n", temp);
+ return -EBUSY;
+ }
+ } else {
+ /* check and clear done bit */
+ if (temp & ALI1535_STS_DONE)
+ outb_p(temp, SMBHSTSTS);
+ }
+
+ /* start the transaction by writing anything to the start register */
+ outb_p(0xFF, SMBHSTPORT);
+
+ /* We will always wait for a fraction of a second! */
+ timeout = 0;
+ do {
+ usleep_range(1000, 2000);
+ temp = inb_p(SMBHSTSTS);
+ } while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
+ && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ result = -ETIMEDOUT;
+ dev_err(&adap->dev, "SMBus Timeout!\n");
+ }
+
+ if (temp & ALI1535_STS_FAIL) {
+ result = -EIO;
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ }
+
+ /* Unfortunately the ALI SMB controller maps "no response" and "bus
+ * collision" into a single bit. No response is the usual case so don't
+ * do a printk. This means that bus collisions go unreported.
+ */
+ if (temp & ALI1535_STS_BUSERR) {
+ result = -ENXIO;
+ dev_dbg(&adap->dev,
+ "Error: no response or bus collision ADD=%02x\n",
+ inb_p(SMBHSTADD));
+ }
+
+ /* haven't ever seen this */
+ if (temp & ALI1535_STS_DEV) {
+ result = -EIO;
+ dev_err(&adap->dev, "Error: device error\n");
+ }
+
+ /* check to see if the "command complete" indication is set */
+ if (!(temp & ALI1535_STS_DONE)) {
+ result = -ETIMEDOUT;
+ dev_err(&adap->dev, "Error: command never completed\n");
+ }
+
+ dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, "
+ "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
+ inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+ /* take consequent actions for error conditions */
+ if (!(temp & ALI1535_STS_DONE)) {
+ /* issue "kill" to reset host controller */
+ outb_p(ALI1535_KILL, SMBHSTTYP);
+ outb_p(0xFF, SMBHSTSTS);
+ } else if (temp & ALI1535_STS_ERR) {
+ /* issue "timeout" to reset all devices on bus */
+ outb_p(ALI1535_T_OUT, SMBHSTTYP);
+ outb_p(0xFF, SMBHSTSTS);
+ }
+
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int i, len;
+ int temp;
+ int timeout;
+ s32 result = 0;
+
+ /* make sure SMBus is idle */
+ temp = inb_p(SMBHSTSTS);
+ for (timeout = 0;
+ (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
+ timeout++) {
+ usleep_range(1000, 2000);
+ temp = inb_p(SMBHSTSTS);
+ }
+ if (timeout >= MAX_TIMEOUT)
+ dev_warn(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+
+ /* clear status register (clear-on-write) */
+ outb_p(0xFF, SMBHSTSTS);
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_QUICK;
+ outb_p(size, SMBHSTTYP); /* output command */
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_BYTE;
+ outb_p(size, SMBHSTTYP); /* output command */
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_BYTE_DATA;
+ outb_p(size, SMBHSTTYP); /* output command */
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_WORD_DATA;
+ outb_p(size, SMBHSTTYP); /* output command */
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI1535_BLOCK_DATA;
+ outb_p(size, SMBHSTTYP); /* output command */
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0) {
+ len = 0;
+ data->block[0] = len;
+ }
+ if (len > 32) {
+ len = 32;
+ data->block[0] = len;
+ }
+ outb_p(len, SMBHSTDAT0);
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ result = -EOPNOTSUPP;
+ goto EXIT;
+ }
+
+ result = ali1535_transaction(adap);
+ if (result)
+ goto EXIT;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK)) {
+ result = 0;
+ goto EXIT;
+ }
+
+ switch (size) {
+ case ALI1535_BYTE: /* Result put in SMBHSTDAT0 */
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI1535_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI1535_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case ALI1535_BLOCK_DATA:
+ len = inb_p(SMBHSTDAT0);
+ if (len > 32)
+ len = 32;
+ data->block[0] = len;
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
+ for (i = 1; i <= data->block[0]; i++) {
+ data->block[i] = inb_p(SMBBLKDAT);
+ dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+ len, i, data->block[i]);
+ }
+ break;
+ }
+EXIT:
+ return result;
+}
+
+
+static u32 ali1535_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ali1535_access,
+ .functionality = ali1535_func,
+};
+
+static struct i2c_adapter ali1535_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id ali1535_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, ali1535_ids);
+
+static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if (ali1535_setup(dev)) {
+ dev_warn(&dev->dev,
+ "ALI1535 not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ ali1535_adapter.dev.parent = &dev->dev;
+
+ snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
+ "SMBus ALI1535 adapter at %04x", ali1535_offset);
+ return i2c_add_adapter(&ali1535_adapter);
+}
+
+static void ali1535_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&ali1535_adapter);
+ release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+}
+
+static struct pci_driver ali1535_driver = {
+ .name = "ali1535_smbus",
+ .id_table = ali1535_ids,
+ .probe = ali1535_probe,
+ .remove = ali1535_remove,
+};
+
+module_pci_driver(ali1535_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "Mark D. Studebaker <mdsxyz123@yahoo.com> "
+ "and Dan Eaton <dan.eaton@rocketlogix.com>");
+MODULE_DESCRIPTION("ALI1535 SMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
new file mode 100644
index 000000000..15517d78d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -0,0 +1,443 @@
+/**
+ * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
+ *
+ * Copyright (C) 2004 Patrick Mochel
+ * 2005 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * The 1563 southbridge is deceptively similar to the 1533, with a
+ * few notable exceptions. One of those happens to be the fact they
+ * upgraded the i2c core to be 2.0 compliant, and happens to be almost
+ * identical to the i2c controller found in the Intel 801 south
+ * bridges.
+ *
+ * This driver is based on a mix of the 15x3, 1535, and i801 drivers,
+ * with a little help from the ALi 1563 spec.
+ *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+
+#define ALI1563_MAX_TIMEOUT 500
+#define ALI1563_SMBBA 0x80
+#define ALI1563_SMB_IOEN 1
+#define ALI1563_SMB_HOSTEN 2
+#define ALI1563_SMB_IOSIZE 16
+
+#define SMB_HST_STS (ali1563_smba + 0)
+#define SMB_HST_CNTL1 (ali1563_smba + 1)
+#define SMB_HST_CNTL2 (ali1563_smba + 2)
+#define SMB_HST_CMD (ali1563_smba + 3)
+#define SMB_HST_ADD (ali1563_smba + 4)
+#define SMB_HST_DAT0 (ali1563_smba + 5)
+#define SMB_HST_DAT1 (ali1563_smba + 6)
+#define SMB_BLK_DAT (ali1563_smba + 7)
+
+#define HST_STS_BUSY 0x01
+#define HST_STS_INTR 0x02
+#define HST_STS_DEVERR 0x04
+#define HST_STS_BUSERR 0x08
+#define HST_STS_FAIL 0x10
+#define HST_STS_DONE 0x80
+#define HST_STS_BAD 0x1c
+
+
+#define HST_CNTL1_TIMEOUT 0x80
+#define HST_CNTL1_LAST 0x40
+
+#define HST_CNTL2_KILL 0x04
+#define HST_CNTL2_START 0x40
+#define HST_CNTL2_QUICK 0x00
+#define HST_CNTL2_BYTE 0x01
+#define HST_CNTL2_BYTE_DATA 0x02
+#define HST_CNTL2_WORD_DATA 0x03
+#define HST_CNTL2_BLOCK 0x05
+
+
+#define HST_CNTL2_SIZEMASK 0x38
+
+static struct pci_driver ali1563_pci_driver;
+static unsigned short ali1563_smba;
+
+static int ali1563_transaction(struct i2c_adapter *a, int size)
+{
+ u32 data;
+ int timeout;
+ int status = -EIO;
+
+ dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, "
+ "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD) {
+ dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
+ outb_p(data | HST_STS_BAD, SMB_HST_STS);
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD)
+ return -EBUSY;
+ }
+ outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
+
+ timeout = ALI1563_MAX_TIMEOUT;
+ do {
+ msleep(1);
+ } while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
+
+ dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, "
+ "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ if (timeout && !(data & HST_STS_BAD))
+ return 0;
+
+ if (!timeout) {
+ dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
+ /* Issue 'kill' to host controller */
+ outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2);
+ data = inb_p(SMB_HST_STS);
+ status = -ETIMEDOUT;
+ }
+
+ /* device error - no response, ignore the autodetection case */
+ if (data & HST_STS_DEVERR) {
+ if (size != HST_CNTL2_QUICK)
+ dev_err(&a->dev, "Device error!\n");
+ status = -ENXIO;
+ }
+ /* bus collision */
+ if (data & HST_STS_BUSERR) {
+ dev_err(&a->dev, "Bus collision!\n");
+ /* Issue timeout, hoping it helps */
+ outb_p(HST_CNTL1_TIMEOUT, SMB_HST_CNTL1);
+ }
+
+ if (data & HST_STS_FAIL) {
+ dev_err(&a->dev, "Cleaning fail after KILL!\n");
+ outb_p(0x0, SMB_HST_CNTL2);
+ }
+
+ return status;
+}
+
+static int ali1563_block_start(struct i2c_adapter *a)
+{
+ u32 data;
+ int timeout;
+ int status = -EIO;
+
+ dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, "
+ "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD) {
+ dev_warn(&a->dev, "ali1563: Trying to reset busy device\n");
+ outb_p(data | HST_STS_BAD, SMB_HST_STS);
+ data = inb_p(SMB_HST_STS);
+ if (data & HST_STS_BAD)
+ return -EBUSY;
+ }
+
+ /* Clear byte-ready bit */
+ outb_p(data | HST_STS_DONE, SMB_HST_STS);
+
+ /* Start transaction and wait for byte-ready bit to be set */
+ outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
+
+ timeout = ALI1563_MAX_TIMEOUT;
+ do {
+ msleep(1);
+ } while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
+
+ dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, "
+ "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+ inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+ inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+ inb_p(SMB_HST_DAT1));
+
+ if (timeout && !(data & HST_STS_BAD))
+ return 0;
+
+ if (timeout == 0)
+ status = -ETIMEDOUT;
+
+ if (data & HST_STS_DEVERR)
+ status = -ENXIO;
+
+ dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
+ timeout ? "" : "Timeout ",
+ data & HST_STS_FAIL ? "Transaction Failed " : "",
+ data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
+ data & HST_STS_DEVERR ? "Device Error " : "",
+ !(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
+ return status;
+}
+
+static int ali1563_block(struct i2c_adapter *a,
+ union i2c_smbus_data *data, u8 rw)
+{
+ int i, len;
+ int error = 0;
+
+ /* Do we need this? */
+ outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1);
+
+ if (rw == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 1)
+ len = 1;
+ else if (len > 32)
+ len = 32;
+ outb_p(len, SMB_HST_DAT0);
+ outb_p(data->block[1], SMB_BLK_DAT);
+ } else
+ len = 32;
+
+ outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2);
+
+ for (i = 0; i < len; i++) {
+ if (rw == I2C_SMBUS_WRITE) {
+ outb_p(data->block[i + 1], SMB_BLK_DAT);
+ error = ali1563_block_start(a);
+ if (error)
+ break;
+ } else {
+ error = ali1563_block_start(a);
+ if (error)
+ break;
+ if (i == 0) {
+ len = inb_p(SMB_HST_DAT0);
+ if (len < 1)
+ len = 1;
+ else if (len > 32)
+ len = 32;
+ }
+ data->block[i+1] = inb_p(SMB_BLK_DAT);
+ }
+ }
+ /* Do we need this? */
+ outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1);
+ return error;
+}
+
+static s32 ali1563_access(struct i2c_adapter *a, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data)
+{
+ int error = 0;
+ int timeout;
+ u32 reg;
+
+ for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) {
+ reg = inb_p(SMB_HST_STS);
+ if (!(reg & HST_STS_BUSY))
+ break;
+ }
+ if (!timeout)
+ dev_warn(&a->dev, "SMBus not idle. HST_STS = %02x\n", reg);
+ outb_p(0xff, SMB_HST_STS);
+
+ /* Map the size to what the chip understands */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ size = HST_CNTL2_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ size = HST_CNTL2_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ size = HST_CNTL2_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ size = HST_CNTL2_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ size = HST_CNTL2_BLOCK;
+ break;
+ default:
+ dev_warn(&a->dev, "Unsupported transaction %d\n", size);
+ error = -EOPNOTSUPP;
+ goto Done;
+ }
+
+ outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
+ outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) |
+ (size << 3), SMB_HST_CNTL2);
+
+ /* Write the command register */
+
+ switch (size) {
+ case HST_CNTL2_BYTE:
+ if (rw == I2C_SMBUS_WRITE)
+ /* Beware it uses DAT0 register and not CMD! */
+ outb_p(cmd, SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_BYTE_DATA:
+ outb_p(cmd, SMB_HST_CMD);
+ if (rw == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_WORD_DATA:
+ outb_p(cmd, SMB_HST_CMD);
+ if (rw == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMB_HST_DAT0);
+ outb_p((data->word & 0xff00) >> 8, SMB_HST_DAT1);
+ }
+ break;
+ case HST_CNTL2_BLOCK:
+ outb_p(cmd, SMB_HST_CMD);
+ error = ali1563_block(a, data, rw);
+ goto Done;
+ }
+
+ error = ali1563_transaction(a, size);
+ if (error)
+ goto Done;
+
+ if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
+ goto Done;
+
+ switch (size) {
+ case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */
+ data->byte = inb_p(SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_BYTE_DATA:
+ data->byte = inb_p(SMB_HST_DAT0);
+ break;
+ case HST_CNTL2_WORD_DATA:
+ data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8);
+ break;
+ }
+Done:
+ return error;
+}
+
+static u32 ali1563_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+
+static int ali1563_setup(struct pci_dev *dev)
+{
+ u16 ctrl;
+
+ pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
+
+ /* SMB I/O Base in high 12 bits and must be aligned with the
+ * size of the I/O space. */
+ ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1);
+ if (!ali1563_smba) {
+ dev_warn(&dev->dev, "ali1563_smba Uninitialized\n");
+ goto Err;
+ }
+
+ /* Check if device is enabled */
+ if (!(ctrl & ALI1563_SMB_HOSTEN)) {
+ dev_warn(&dev->dev, "Host Controller not enabled\n");
+ goto Err;
+ }
+ if (!(ctrl & ALI1563_SMB_IOEN)) {
+ dev_warn(&dev->dev, "I/O space not enabled, trying manually\n");
+ pci_write_config_word(dev, ALI1563_SMBBA,
+ ctrl | ALI1563_SMB_IOEN);
+ pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
+ if (!(ctrl & ALI1563_SMB_IOEN)) {
+ dev_err(&dev->dev,
+ "I/O space still not enabled, giving up\n");
+ goto Err;
+ }
+ }
+
+ if (acpi_check_region(ali1563_smba, ALI1563_SMB_IOSIZE,
+ ali1563_pci_driver.name))
+ goto Err;
+
+ if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE,
+ ali1563_pci_driver.name)) {
+ dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n",
+ ali1563_smba);
+ goto Err;
+ }
+ dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n", ali1563_smba);
+
+ return 0;
+Err:
+ return -ENODEV;
+}
+
+static void ali1563_shutdown(struct pci_dev *dev)
+{
+ release_region(ali1563_smba, ALI1563_SMB_IOSIZE);
+}
+
+static const struct i2c_algorithm ali1563_algorithm = {
+ .smbus_xfer = ali1563_access,
+ .functionality = ali1563_func,
+};
+
+static struct i2c_adapter ali1563_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &ali1563_algorithm,
+};
+
+static int ali1563_probe(struct pci_dev *dev,
+ const struct pci_device_id *id_table)
+{
+ int error;
+
+ error = ali1563_setup(dev);
+ if (error)
+ goto exit;
+ ali1563_adapter.dev.parent = &dev->dev;
+ snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
+ "SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
+ error = i2c_add_adapter(&ali1563_adapter);
+ if (error)
+ goto exit_shutdown;
+ return 0;
+
+exit_shutdown:
+ ali1563_shutdown(dev);
+exit:
+ dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n", error);
+ return error;
+}
+
+static void ali1563_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&ali1563_adapter);
+ ali1563_shutdown(dev);
+}
+
+static const struct pci_device_id ali1563_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, ali1563_id_table);
+
+static struct pci_driver ali1563_pci_driver = {
+ .name = "ali1563_smbus",
+ .id_table = ali1563_id_table,
+ .probe = ali1563_probe,
+ .remove = ali1563_remove,
+};
+
+module_pci_driver(ali1563_pci_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
new file mode 100644
index 000000000..6e6bf46bc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -0,0 +1,517 @@
+/*
+ Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com> and
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ This is the driver for the SMB Host controller on
+ Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
+
+ The M1543C is a South bridge for desktop systems.
+ The M1533 is a South bridge for portable systems.
+ They are part of the following ALI chipsets:
+ "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
+ with AGP and 100MHz CPU Front Side bus
+ "Aladdin V": Includes the M1541 Socket 7 North bridge
+ with AGP and 100MHz CPU Front Side bus
+ "Aladdin IV": Includes the M1541 Socket 7 North bridge
+ with host bus up to 83.3 MHz.
+ For an overview of these chips see http://www.acerlabs.com
+
+ The M1533/M1543C devices appear as FOUR separate devices
+ on the PCI bus. An output of lspci will show something similar
+ to the following:
+
+ 00:02.0 USB Controller: Acer Laboratories Inc. M5237
+ 00:03.0 Bridge: Acer Laboratories Inc. M7101
+ 00:07.0 ISA bridge: Acer Laboratories Inc. M1533
+ 00:0f.0 IDE interface: Acer Laboratories Inc. M5229
+
+ The SMB controller is part of the 7101 device, which is an
+ ACPI-compliant Power Management Unit (PMU).
+
+ The whole 7101 device has to be enabled for the SMB to work.
+ You can't just enable the SMB alone.
+ The SMB and the ACPI have separate I/O spaces.
+ We make sure that the SMB is enabled. We leave the ACPI alone.
+
+ This driver controls the SMB Host only.
+ The SMB Slave controller on the M15X3 is not enabled.
+
+ This driver does not use interrupts.
+*/
+
+/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* ALI15X3 SMBus address offsets */
+#define SMBHSTSTS (0 + ali15x3_smba)
+#define SMBHSTCNT (1 + ali15x3_smba)
+#define SMBHSTSTART (2 + ali15x3_smba)
+#define SMBHSTCMD (7 + ali15x3_smba)
+#define SMBHSTADD (3 + ali15x3_smba)
+#define SMBHSTDAT0 (4 + ali15x3_smba)
+#define SMBHSTDAT1 (5 + ali15x3_smba)
+#define SMBBLKDAT (6 + ali15x3_smba)
+
+/* PCI Address Constants */
+#define SMBCOM 0x004
+#define SMBBA 0x014
+#define SMBATPC 0x05B /* used to unlock xxxBA registers */
+#define SMBHSTCFG 0x0E0
+#define SMBSLVC 0x0E1
+#define SMBCLK 0x0E2
+#define SMBREV 0x008
+
+/* Other settings */
+#define MAX_TIMEOUT 200 /* times 1/100 sec */
+#define ALI15X3_SMB_IOSIZE 32
+
+/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
+ We don't use these here. If the bases aren't set to some value we
+ tell user to upgrade BIOS and we fail.
+*/
+#define ALI15X3_SMB_DEFAULTBASE 0xE800
+
+/* ALI15X3 address lock bits */
+#define ALI15X3_LOCK 0x06
+
+/* ALI15X3 command constants */
+#define ALI15X3_ABORT 0x02
+#define ALI15X3_T_OUT 0x04
+#define ALI15X3_QUICK 0x00
+#define ALI15X3_BYTE 0x10
+#define ALI15X3_BYTE_DATA 0x20
+#define ALI15X3_WORD_DATA 0x30
+#define ALI15X3_BLOCK_DATA 0x40
+#define ALI15X3_BLOCK_CLR 0x80
+
+/* ALI15X3 status register bits */
+#define ALI15X3_STS_IDLE 0x04
+#define ALI15X3_STS_BUSY 0x08
+#define ALI15X3_STS_DONE 0x10
+#define ALI15X3_STS_DEV 0x20 /* device error */
+#define ALI15X3_STS_COLL 0x40 /* collision or no response */
+#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
+#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
+
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the device at the given address. */
+static u16 force_addr;
+module_param_hw(force_addr, ushort, ioport, 0);
+MODULE_PARM_DESC(force_addr,
+ "Initialize the base address of the i2c controller");
+
+static struct pci_driver ali15x3_driver;
+static unsigned short ali15x3_smba;
+
+static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+{
+ u16 a;
+ unsigned char temp;
+
+ /* Check the following things:
+ - SMB I/O address is initialized
+ - Device is enabled
+ - We can use the addresses
+ */
+
+ /* Unlock the register.
+ The data sheet says that the address registers are read-only
+ if the lock bits are 1, but in fact the address registers
+ are zero unless you clear the lock bits.
+ */
+ pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
+ if (temp & ALI15X3_LOCK) {
+ temp &= ~ALI15X3_LOCK;
+ pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
+ }
+
+ /* Determine the address of the SMBus area */
+ pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
+ ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
+ if (ali15x3_smba == 0 && force_addr == 0) {
+ dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
+ "- upgrade BIOS or use force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+
+ if(force_addr)
+ ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
+
+ if (acpi_check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
+ ali15x3_driver.name))
+ return -EBUSY;
+
+ if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
+ ali15x3_driver.name)) {
+ dev_err(&ALI15X3_dev->dev,
+ "ALI15X3_smb region 0x%x already in use!\n",
+ ali15x3_smba);
+ return -ENODEV;
+ }
+
+ if(force_addr) {
+ dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
+ ali15x3_smba);
+ if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev,
+ SMBBA,
+ ali15x3_smba))
+ goto error;
+ if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev,
+ SMBBA, &a))
+ goto error;
+ if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
+ /* make sure it works */
+ dev_err(&ALI15X3_dev->dev,
+ "force address failed - not supported?\n");
+ goto error;
+ }
+ }
+ /* check if whole device is enabled */
+ pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
+ if ((temp & 1) == 0) {
+ dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
+ pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
+ }
+
+ /* Is SMB Host controller enabled? */
+ pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
+ if ((temp & 1) == 0) {
+ dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
+ pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
+ }
+
+ /* set SMB clock to 74KHz as recommended in data sheet */
+ pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
+
+ /*
+ The interrupt routing for SMB is set up in register 0x77 in the
+ 1533 ISA Bridge device, NOT in the 7101 device.
+ Don't bother with finding the 1533 device and reading the register.
+ if ((....... & 0x0F) == 1)
+ dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
+ */
+ pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
+ dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
+
+ return 0;
+error:
+ release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+ return -ENODEV;
+}
+
+/* Another internally used function */
+static int ali15x3_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+ /* get status */
+ temp = inb_p(SMBHSTSTS);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ /* Check the busy bit first */
+ if (temp & ALI15X3_STS_BUSY) {
+ /*
+ If the host controller is still busy, it may have timed out in the
+ previous transaction, resulting in a "SMBus Timeout" Dev.
+ I've tried the following to reset a stuck busy bit.
+ 1. Reset the controller with an ABORT command.
+ (this doesn't seem to clear the controller if an external
+ device is hung)
+ 2. Reset the controller and the other SMBus devices with a
+ T_OUT command. (this clears the host busy bit if an
+ external device is hung, but it comes back upon a new access
+ to a device)
+ 3. Disable and reenable the controller in SMBHSTCFG
+ Worst case, nothing seems to work except power reset.
+ */
+ /* Abort - reset the host controller */
+ /*
+ Try resetting entire SMB bus, including other devices -
+ This may not work either - it clears the BUSY bit but
+ then the BUSY bit may come back on when you try and use the chip again.
+ If that's the case you are stuck.
+ */
+ dev_info(&adap->dev, "Resetting entire SMB Bus to "
+ "clear busy condition (%02x)\n", temp);
+ outb_p(ALI15X3_T_OUT, SMBHSTCNT);
+ temp = inb_p(SMBHSTSTS);
+ }
+
+ /* now check the error bits and the busy bit */
+ if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+ /* do a clear-on-write */
+ outb_p(0xFF, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) &
+ (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+ /* this is probably going to be correctable only by a power reset
+ as one of the bits now appears to be stuck */
+ /* This may be a bus or device with electrical problems. */
+ dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
+ "controller or device on bus is probably hung\n",
+ temp);
+ return -EBUSY;
+ }
+ } else {
+ /* check and clear done bit */
+ if (temp & ALI15X3_STS_DONE) {
+ outb_p(temp, SMBHSTSTS);
+ }
+ }
+
+ /* start the transaction by writing anything to the start register */
+ outb_p(0xFF, SMBHSTSTART);
+
+ /* We will always wait for a fraction of a second! */
+ timeout = 0;
+ do {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ } while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
+ && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ result = -ETIMEDOUT;
+ dev_err(&adap->dev, "SMBus Timeout!\n");
+ }
+
+ if (temp & ALI15X3_STS_TERM) {
+ result = -EIO;
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ }
+
+ /*
+ Unfortunately the ALI SMB controller maps "no response" and "bus
+ collision" into a single bit. No response is the usual case so don't
+ do a printk.
+ This means that bus collisions go unreported.
+ */
+ if (temp & ALI15X3_STS_COLL) {
+ result = -ENXIO;
+ dev_dbg(&adap->dev,
+ "Error: no response or bus collision ADD=%02x\n",
+ inb_p(SMBHSTADD));
+ }
+
+ /* haven't ever seen this */
+ if (temp & ALI15X3_STS_DEV) {
+ result = -EIO;
+ dev_err(&adap->dev, "Error: device error\n");
+ }
+ dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data * data)
+{
+ int i, len;
+ int temp;
+ int timeout;
+
+ /* clear all the bits (clear-on-write) */
+ outb_p(0xFF, SMBHSTSTS);
+ /* make sure SMBus is idle */
+ temp = inb_p(SMBHSTSTS);
+ for (timeout = 0;
+ (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
+ timeout++) {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ }
+ if (timeout >= MAX_TIMEOUT) {
+ dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+ }
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ size = ALI15X3_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ size = ALI15X3_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ size = ALI15X3_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = ALI15X3_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0) {
+ len = 0;
+ data->block[0] = len;
+ }
+ if (len > 32) {
+ len = 32;
+ data->block[0] = len;
+ }
+ outb_p(len, SMBHSTDAT0);
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ size = ALI15X3_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ outb_p(size, SMBHSTCNT); /* output command */
+
+ temp = ali15x3_transaction(adap);
+ if (temp)
+ return temp;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
+ return 0;
+
+
+ switch (size) {
+ case ALI15X3_BYTE: /* Result put in SMBHSTDAT0 */
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI15X3_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case ALI15X3_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case ALI15X3_BLOCK_DATA:
+ len = inb_p(SMBHSTDAT0);
+ if (len > 32)
+ len = 32;
+ data->block[0] = len;
+ /* Reset SMBBLKDAT */
+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+ for (i = 1; i <= data->block[0]; i++) {
+ data->block[i] = inb_p(SMBBLKDAT);
+ dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+ len, i, data->block[i]);
+ }
+ break;
+ }
+ return 0;
+}
+
+static u32 ali15x3_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ali15x3_access,
+ .functionality = ali15x3_func,
+};
+
+static struct i2c_adapter ali15x3_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id ali15x3_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, ali15x3_ids);
+
+static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if (ali15x3_setup(dev)) {
+ dev_err(&dev->dev,
+ "ALI15X3 not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ ali15x3_adapter.dev.parent = &dev->dev;
+
+ snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
+ "SMBus ALI15X3 adapter at %04x", ali15x3_smba);
+ return i2c_add_adapter(&ali15x3_adapter);
+}
+
+static void ali15x3_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&ali15x3_adapter);
+ release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+}
+
+static struct pci_driver ali15x3_driver = {
+ .name = "ali15x3_smbus",
+ .id_table = ali15x3_ids,
+ .probe = ali15x3_probe,
+ .remove = ali15x3_remove,
+};
+
+module_pci_driver(ali15x3_driver);
+
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+ "Philip Edelbrock <phil@netroedge.com>, "
+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("ALI15X3 SMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c
new file mode 100644
index 000000000..1d59eede5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-altera.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright Intel Corporation (C) 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on the i2c-axxia.c driver.
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#define ALTR_I2C_TFR_CMD 0x00 /* Transfer Command register */
+#define ALTR_I2C_TFR_CMD_STA BIT(9) /* send START before byte */
+#define ALTR_I2C_TFR_CMD_STO BIT(8) /* send STOP after byte */
+#define ALTR_I2C_TFR_CMD_RW_D BIT(0) /* Direction of transfer */
+#define ALTR_I2C_RX_DATA 0x04 /* RX data FIFO register */
+#define ALTR_I2C_CTRL 0x08 /* Control register */
+#define ALTR_I2C_CTRL_RXT_SHFT 4 /* RX FIFO Threshold */
+#define ALTR_I2C_CTRL_TCT_SHFT 2 /* TFER CMD FIFO Threshold */
+#define ALTR_I2C_CTRL_BSPEED BIT(1) /* Bus Speed (1=Fast) */
+#define ALTR_I2C_CTRL_EN BIT(0) /* Enable Core (1=Enable) */
+#define ALTR_I2C_ISER 0x0C /* Interrupt Status Enable register */
+#define ALTR_I2C_ISER_RXOF_EN BIT(4) /* Enable RX OVERFLOW IRQ */
+#define ALTR_I2C_ISER_ARB_EN BIT(3) /* Enable ARB LOST IRQ */
+#define ALTR_I2C_ISER_NACK_EN BIT(2) /* Enable NACK DET IRQ */
+#define ALTR_I2C_ISER_RXRDY_EN BIT(1) /* Enable RX Ready IRQ */
+#define ALTR_I2C_ISER_TXRDY_EN BIT(0) /* Enable TX Ready IRQ */
+#define ALTR_I2C_ISR 0x10 /* Interrupt Status register */
+#define ALTR_I2C_ISR_RXOF BIT(4) /* RX OVERFLOW IRQ */
+#define ALTR_I2C_ISR_ARB BIT(3) /* ARB LOST IRQ */
+#define ALTR_I2C_ISR_NACK BIT(2) /* NACK DET IRQ */
+#define ALTR_I2C_ISR_RXRDY BIT(1) /* RX Ready IRQ */
+#define ALTR_I2C_ISR_TXRDY BIT(0) /* TX Ready IRQ */
+#define ALTR_I2C_STATUS 0x14 /* Status register */
+#define ALTR_I2C_STAT_CORE BIT(0) /* Core Status (0=idle) */
+#define ALTR_I2C_TC_FIFO_LVL 0x18 /* Transfer FIFO LVL register */
+#define ALTR_I2C_RX_FIFO_LVL 0x1C /* Receive FIFO LVL register */
+#define ALTR_I2C_SCL_LOW 0x20 /* SCL low count register */
+#define ALTR_I2C_SCL_HIGH 0x24 /* SCL high count register */
+#define ALTR_I2C_SDA_HOLD 0x28 /* SDA hold count register */
+
+#define ALTR_I2C_ALL_IRQ (ALTR_I2C_ISR_RXOF | ALTR_I2C_ISR_ARB | \
+ ALTR_I2C_ISR_NACK | ALTR_I2C_ISR_RXRDY | \
+ ALTR_I2C_ISR_TXRDY)
+
+#define ALTR_I2C_THRESHOLD 0 /* IRQ Threshold at 1 element */
+#define ALTR_I2C_DFLT_FIFO_SZ 4
+#define ALTR_I2C_TIMEOUT 100000 /* 100ms */
+#define ALTR_I2C_XFER_TIMEOUT (msecs_to_jiffies(250))
+
+/**
+ * altr_i2c_dev - I2C device context
+ * @base: pointer to register struct
+ * @msg: pointer to current message
+ * @msg_len: number of bytes transferred in msg
+ * @msg_err: error code for completed message
+ * @msg_complete: xfer completion object
+ * @dev: device reference
+ * @adapter: core i2c abstraction
+ * @i2c_clk: clock reference for i2c input clock
+ * @bus_clk_rate: current i2c bus clock rate
+ * @buf: ptr to msg buffer for easier use.
+ * @fifo_size: size of the FIFO passed in.
+ * @isr_mask: cached copy of local ISR enables.
+ * @isr_status: cached copy of local ISR status.
+ * @lock: spinlock for IRQ synchronization.
+ * @isr_mutex: mutex for IRQ thread.
+ */
+struct altr_i2c_dev {
+ void __iomem *base;
+ struct i2c_msg *msg;
+ size_t msg_len;
+ int msg_err;
+ struct completion msg_complete;
+ struct device *dev;
+ struct i2c_adapter adapter;
+ struct clk *i2c_clk;
+ u32 bus_clk_rate;
+ u8 *buf;
+ u32 fifo_size;
+ u32 isr_mask;
+ u32 isr_status;
+ spinlock_t lock; /* IRQ synchronization */
+ struct mutex isr_mutex;
+};
+
+static void
+altr_i2c_int_enable(struct altr_i2c_dev *idev, u32 mask, bool enable)
+{
+ unsigned long flags;
+ u32 int_en;
+
+ spin_lock_irqsave(&idev->lock, flags);
+
+ int_en = readl(idev->base + ALTR_I2C_ISER);
+ if (enable)
+ idev->isr_mask = int_en | mask;
+ else
+ idev->isr_mask = int_en & ~mask;
+
+ writel(idev->isr_mask, idev->base + ALTR_I2C_ISER);
+
+ spin_unlock_irqrestore(&idev->lock, flags);
+}
+
+static void altr_i2c_int_clear(struct altr_i2c_dev *idev, u32 mask)
+{
+ u32 int_en = readl(idev->base + ALTR_I2C_ISR);
+
+ writel(int_en | mask, idev->base + ALTR_I2C_ISR);
+}
+
+static void altr_i2c_core_disable(struct altr_i2c_dev *idev)
+{
+ u32 tmp = readl(idev->base + ALTR_I2C_CTRL);
+
+ writel(tmp & ~ALTR_I2C_CTRL_EN, idev->base + ALTR_I2C_CTRL);
+}
+
+static void altr_i2c_core_enable(struct altr_i2c_dev *idev)
+{
+ u32 tmp = readl(idev->base + ALTR_I2C_CTRL);
+
+ writel(tmp | ALTR_I2C_CTRL_EN, idev->base + ALTR_I2C_CTRL);
+}
+
+static void altr_i2c_reset(struct altr_i2c_dev *idev)
+{
+ altr_i2c_core_disable(idev);
+ altr_i2c_core_enable(idev);
+}
+
+static inline void altr_i2c_stop(struct altr_i2c_dev *idev)
+{
+ writel(ALTR_I2C_TFR_CMD_STO, idev->base + ALTR_I2C_TFR_CMD);
+}
+
+static void altr_i2c_init(struct altr_i2c_dev *idev)
+{
+ u32 divisor = clk_get_rate(idev->i2c_clk) / idev->bus_clk_rate;
+ u32 clk_mhz = clk_get_rate(idev->i2c_clk) / 1000000;
+ u32 tmp = (ALTR_I2C_THRESHOLD << ALTR_I2C_CTRL_RXT_SHFT) |
+ (ALTR_I2C_THRESHOLD << ALTR_I2C_CTRL_TCT_SHFT);
+ u32 t_high, t_low;
+
+ if (idev->bus_clk_rate <= 100000) {
+ tmp &= ~ALTR_I2C_CTRL_BSPEED;
+ /* Standard mode SCL 50/50 */
+ t_high = divisor * 1 / 2;
+ t_low = divisor * 1 / 2;
+ } else {
+ tmp |= ALTR_I2C_CTRL_BSPEED;
+ /* Fast mode SCL 33/66 */
+ t_high = divisor * 1 / 3;
+ t_low = divisor * 2 / 3;
+ }
+ writel(tmp, idev->base + ALTR_I2C_CTRL);
+
+ dev_dbg(idev->dev, "rate=%uHz per_clk=%uMHz -> ratio=1:%u\n",
+ idev->bus_clk_rate, clk_mhz, divisor);
+
+ /* Reset controller */
+ altr_i2c_reset(idev);
+
+ /* SCL High Time */
+ writel(t_high, idev->base + ALTR_I2C_SCL_HIGH);
+ /* SCL Low Time */
+ writel(t_low, idev->base + ALTR_I2C_SCL_LOW);
+ /* SDA Hold Time, 300ns */
+ writel(3 * clk_mhz / 10, idev->base + ALTR_I2C_SDA_HOLD);
+
+ /* Mask all master interrupt bits */
+ altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false);
+}
+
+/**
+ * altr_i2c_transfer - On the last byte to be transmitted, send
+ * a Stop bit on the last byte.
+ */
+static void altr_i2c_transfer(struct altr_i2c_dev *idev, u32 data)
+{
+ /* On the last byte to be transmitted, send STOP */
+ if (idev->msg_len == 1)
+ data |= ALTR_I2C_TFR_CMD_STO;
+ if (idev->msg_len > 0)
+ writel(data, idev->base + ALTR_I2C_TFR_CMD);
+}
+
+/**
+ * altr_i2c_empty_rx_fifo - Fetch data from RX FIFO until end of
+ * transfer. Send a Stop bit on the last byte.
+ */
+static void altr_i2c_empty_rx_fifo(struct altr_i2c_dev *idev)
+{
+ size_t rx_fifo_avail = readl(idev->base + ALTR_I2C_RX_FIFO_LVL);
+ int bytes_to_transfer = min(rx_fifo_avail, idev->msg_len);
+
+ while (bytes_to_transfer-- > 0) {
+ *idev->buf++ = readl(idev->base + ALTR_I2C_RX_DATA);
+ idev->msg_len--;
+ altr_i2c_transfer(idev, 0);
+ }
+}
+
+/**
+ * altr_i2c_fill_tx_fifo - Fill TX FIFO from current message buffer.
+ * @return: Number of bytes left to transfer.
+ */
+static int altr_i2c_fill_tx_fifo(struct altr_i2c_dev *idev)
+{
+ size_t tx_fifo_avail = idev->fifo_size - readl(idev->base +
+ ALTR_I2C_TC_FIFO_LVL);
+ int bytes_to_transfer = min(tx_fifo_avail, idev->msg_len);
+ int ret = idev->msg_len - bytes_to_transfer;
+
+ while (bytes_to_transfer-- > 0) {
+ altr_i2c_transfer(idev, *idev->buf++);
+ idev->msg_len--;
+ }
+
+ return ret;
+}
+
+static irqreturn_t altr_i2c_isr_quick(int irq, void *_dev)
+{
+ struct altr_i2c_dev *idev = _dev;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ /* Read IRQ status but only interested in Enabled IRQs. */
+ idev->isr_status = readl(idev->base + ALTR_I2C_ISR) & idev->isr_mask;
+ if (idev->isr_status)
+ ret = IRQ_WAKE_THREAD;
+
+ return ret;
+}
+
+static irqreturn_t altr_i2c_isr(int irq, void *_dev)
+{
+ int ret;
+ bool read, finish = false;
+ struct altr_i2c_dev *idev = _dev;
+ u32 status = idev->isr_status;
+
+ mutex_lock(&idev->isr_mutex);
+ if (!idev->msg) {
+ dev_warn(idev->dev, "unexpected interrupt\n");
+ altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ);
+ goto out;
+ }
+ read = (idev->msg->flags & I2C_M_RD) != 0;
+
+ /* handle Lost Arbitration */
+ if (unlikely(status & ALTR_I2C_ISR_ARB)) {
+ altr_i2c_int_clear(idev, ALTR_I2C_ISR_ARB);
+ idev->msg_err = -EAGAIN;
+ finish = true;
+ } else if (unlikely(status & ALTR_I2C_ISR_NACK)) {
+ dev_dbg(idev->dev, "Could not get ACK\n");
+ idev->msg_err = -ENXIO;
+ altr_i2c_int_clear(idev, ALTR_I2C_ISR_NACK);
+ altr_i2c_stop(idev);
+ finish = true;
+ } else if (read && unlikely(status & ALTR_I2C_ISR_RXOF)) {
+ /* handle RX FIFO Overflow */
+ altr_i2c_empty_rx_fifo(idev);
+ altr_i2c_int_clear(idev, ALTR_I2C_ISR_RXRDY);
+ altr_i2c_stop(idev);
+ dev_err(idev->dev, "RX FIFO Overflow\n");
+ finish = true;
+ } else if (read && (status & ALTR_I2C_ISR_RXRDY)) {
+ /* RX FIFO needs service? */
+ altr_i2c_empty_rx_fifo(idev);
+ altr_i2c_int_clear(idev, ALTR_I2C_ISR_RXRDY);
+ if (!idev->msg_len)
+ finish = true;
+ } else if (!read && (status & ALTR_I2C_ISR_TXRDY)) {
+ /* TX FIFO needs service? */
+ altr_i2c_int_clear(idev, ALTR_I2C_ISR_TXRDY);
+ if (idev->msg_len > 0)
+ altr_i2c_fill_tx_fifo(idev);
+ else
+ finish = true;
+ } else {
+ dev_warn(idev->dev, "Unexpected interrupt: 0x%x\n", status);
+ altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ);
+ }
+
+ if (finish) {
+ /* Wait for the Core to finish */
+ ret = readl_poll_timeout_atomic(idev->base + ALTR_I2C_STATUS,
+ status,
+ !(status & ALTR_I2C_STAT_CORE),
+ 1, ALTR_I2C_TIMEOUT);
+ if (ret)
+ dev_err(idev->dev, "message timeout\n");
+ altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false);
+ altr_i2c_int_clear(idev, ALTR_I2C_ALL_IRQ);
+ complete(&idev->msg_complete);
+ dev_dbg(idev->dev, "Message Complete\n");
+ }
+out:
+ mutex_unlock(&idev->isr_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int altr_i2c_xfer_msg(struct altr_i2c_dev *idev, struct i2c_msg *msg)
+{
+ u32 imask = ALTR_I2C_ISR_RXOF | ALTR_I2C_ISR_ARB | ALTR_I2C_ISR_NACK;
+ unsigned long time_left;
+ u32 value;
+ u8 addr = i2c_8bit_addr_from_msg(msg);
+
+ mutex_lock(&idev->isr_mutex);
+ idev->msg = msg;
+ idev->msg_len = msg->len;
+ idev->buf = msg->buf;
+ idev->msg_err = 0;
+ reinit_completion(&idev->msg_complete);
+ altr_i2c_core_enable(idev);
+
+ /* Make sure RX FIFO is empty */
+ do {
+ readl(idev->base + ALTR_I2C_RX_DATA);
+ } while (readl(idev->base + ALTR_I2C_RX_FIFO_LVL));
+
+ writel(ALTR_I2C_TFR_CMD_STA | addr, idev->base + ALTR_I2C_TFR_CMD);
+
+ if ((msg->flags & I2C_M_RD) != 0) {
+ imask |= ALTR_I2C_ISER_RXOF_EN | ALTR_I2C_ISER_RXRDY_EN;
+ altr_i2c_int_enable(idev, imask, true);
+ /* write the first byte to start the RX */
+ altr_i2c_transfer(idev, 0);
+ } else {
+ imask |= ALTR_I2C_ISR_TXRDY;
+ altr_i2c_int_enable(idev, imask, true);
+ altr_i2c_fill_tx_fifo(idev);
+ }
+ mutex_unlock(&idev->isr_mutex);
+
+ time_left = wait_for_completion_timeout(&idev->msg_complete,
+ ALTR_I2C_XFER_TIMEOUT);
+ altr_i2c_int_enable(idev, imask, false);
+
+ value = readl(idev->base + ALTR_I2C_STATUS) & ALTR_I2C_STAT_CORE;
+ if (value)
+ dev_err(idev->dev, "Core Status not IDLE...\n");
+
+ if (time_left == 0) {
+ idev->msg_err = -ETIMEDOUT;
+ dev_dbg(idev->dev, "Transaction timed out.\n");
+ }
+
+ altr_i2c_core_disable(idev);
+
+ return idev->msg_err;
+}
+
+static int
+altr_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct altr_i2c_dev *idev = i2c_get_adapdata(adap);
+ int i, ret;
+
+ for (i = 0; i < num; i++) {
+ ret = altr_i2c_xfer_msg(idev, msgs++);
+ if (ret)
+ return ret;
+ }
+ return num;
+}
+
+static u32 altr_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm altr_i2c_algo = {
+ .master_xfer = altr_i2c_xfer,
+ .functionality = altr_i2c_func,
+};
+
+static int altr_i2c_probe(struct platform_device *pdev)
+{
+ struct altr_i2c_dev *idev = NULL;
+ struct resource *res;
+ int irq, ret;
+
+ idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
+ if (!idev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ idev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(idev->base))
+ return PTR_ERR(idev->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "missing interrupt resource\n");
+ return irq;
+ }
+
+ idev->i2c_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(idev->i2c_clk)) {
+ dev_err(&pdev->dev, "missing clock\n");
+ return PTR_ERR(idev->i2c_clk);
+ }
+
+ idev->dev = &pdev->dev;
+ init_completion(&idev->msg_complete);
+ spin_lock_init(&idev->lock);
+ mutex_init(&idev->isr_mutex);
+
+ ret = device_property_read_u32(idev->dev, "fifo-size",
+ &idev->fifo_size);
+ if (ret) {
+ dev_err(&pdev->dev, "FIFO size set to default of %d\n",
+ ALTR_I2C_DFLT_FIFO_SZ);
+ idev->fifo_size = ALTR_I2C_DFLT_FIFO_SZ;
+ }
+
+ ret = device_property_read_u32(idev->dev, "clock-frequency",
+ &idev->bus_clk_rate);
+ if (ret) {
+ dev_err(&pdev->dev, "Default to 100kHz\n");
+ idev->bus_clk_rate = 100000; /* default clock rate */
+ }
+
+ if (idev->bus_clk_rate > 400000) {
+ dev_err(&pdev->dev, "invalid clock-frequency %d\n",
+ idev->bus_clk_rate);
+ return -EINVAL;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, altr_i2c_isr_quick,
+ altr_i2c_isr, IRQF_ONESHOT,
+ pdev->name, idev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim IRQ %d\n", irq);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(idev->i2c_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ altr_i2c_init(idev);
+
+ i2c_set_adapdata(&idev->adapter, idev);
+ strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
+ idev->adapter.owner = THIS_MODULE;
+ idev->adapter.algo = &altr_i2c_algo;
+ idev->adapter.dev.parent = &pdev->dev;
+ idev->adapter.dev.of_node = pdev->dev.of_node;
+
+ platform_set_drvdata(pdev, idev);
+
+ ret = i2c_add_adapter(&idev->adapter);
+ if (ret) {
+ clk_disable_unprepare(idev->i2c_clk);
+ return ret;
+ }
+ dev_info(&pdev->dev, "Altera SoftIP I2C Probe Complete\n");
+
+ return 0;
+}
+
+static int altr_i2c_remove(struct platform_device *pdev)
+{
+ struct altr_i2c_dev *idev = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(idev->i2c_clk);
+ i2c_del_adapter(&idev->adapter);
+
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id altr_i2c_of_match[] = {
+ { .compatible = "altr,softip-i2c-v1.0" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, altr_i2c_of_match);
+
+static struct platform_driver altr_i2c_driver = {
+ .probe = altr_i2c_probe,
+ .remove = altr_i2c_remove,
+ .driver = {
+ .name = "altera-i2c",
+ .of_match_table = altr_i2c_of_match,
+ },
+};
+
+module_platform_driver(altr_i2c_driver);
+
+MODULE_DESCRIPTION("Altera Soft IP I2C bus driver");
+MODULE_AUTHOR("Thor Thayer <thor.thayer@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
new file mode 100644
index 000000000..a2f5f992a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -0,0 +1,254 @@
+/*
+ * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
+ *
+ * Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4, and 0x4c (LM63)
+ * located on multiplexed channels 0 and 5-7. We define one
+ * virtual adapter per CPU, which corresponds to two multiplexed
+ * channels:
+ * CPU0: virtual adapter 1, channels 1 and 0
+ * CPU1: virtual adapter 2, channels 2 and 5
+ * CPU2: virtual adapter 3, channels 3 and 6
+ * CPU3: virtual adapter 4, channels 4 and 7
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+extern struct i2c_adapter amd756_smbus;
+
+static struct i2c_adapter *s4882_adapter;
+static struct i2c_algorithm *s4882_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static DEFINE_MUTEX(amd756_lock);
+
+static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ int error;
+
+ /* We exclude the multiplexed addresses */
+ if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+ || addr == 0x18)
+ return -ENXIO;
+
+ mutex_lock(&amd756_lock);
+
+ error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+
+ mutex_unlock(&amd756_lock);
+
+ return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+ channels when it is really needed. This greatly reduces the SMBus
+ overhead, but also assumes that nobody will be writing to the PCA9556
+ in our back. */
+static u8 last_channels;
+
+static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data,
+ u8 channels)
+{
+ int error;
+
+ /* We exclude the non-multiplexed addresses */
+ if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+ return -ENXIO;
+
+ mutex_lock(&amd756_lock);
+
+ if (last_channels != channels) {
+ union i2c_smbus_data mplxdata;
+ mplxdata.byte = channels;
+
+ error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
+ I2C_SMBUS_WRITE, 0x01,
+ I2C_SMBUS_BYTE_DATA,
+ &mplxdata);
+ if (error)
+ goto UNLOCK;
+ last_channels = channels;
+ }
+ error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+
+UNLOCK:
+ mutex_unlock(&amd756_lock);
+ return error;
+}
+
+static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU0: channels 1 and 0 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x03);
+}
+
+static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU1: channels 2 and 5 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x24);
+}
+
+static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU2: channels 3 and 6 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x48);
+}
+
+static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ /* CPU3: channels 4 and 7 enabled */
+ return amd756_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x90);
+}
+
+static int __init amd756_s4882_init(void)
+{
+ int i, error;
+ union i2c_smbus_data ioconfig;
+
+ if (!amd756_smbus.dev.parent)
+ return -ENODEV;
+
+ /* Configure the PCA9556 multiplexer */
+ ioconfig.byte = 0x00; /* All I/O to output mode */
+ error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+ I2C_SMBUS_BYTE_DATA, &ioconfig);
+ if (error) {
+ dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
+ error = -EIO;
+ goto ERROR0;
+ }
+
+ /* Unregister physical bus */
+ i2c_del_adapter(&amd756_smbus);
+
+ printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
+ /* Define the 5 virtual adapters and algorithms structures */
+ if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter),
+ GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto ERROR1;
+ }
+ if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm),
+ GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto ERROR2;
+ }
+
+ /* Fill in the new structures */
+ s4882_algo[0] = *(amd756_smbus.algo);
+ s4882_algo[0].smbus_xfer = amd756_access_virt0;
+ s4882_adapter[0] = amd756_smbus;
+ s4882_adapter[0].algo = s4882_algo;
+ s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
+ for (i = 1; i < 5; i++) {
+ s4882_algo[i] = *(amd756_smbus.algo);
+ s4882_adapter[i] = amd756_smbus;
+ snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
+ "SMBus 8111 adapter (CPU%d)", i-1);
+ s4882_adapter[i].algo = s4882_algo+i;
+ s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
+ }
+ s4882_algo[1].smbus_xfer = amd756_access_virt1;
+ s4882_algo[2].smbus_xfer = amd756_access_virt2;
+ s4882_algo[3].smbus_xfer = amd756_access_virt3;
+ s4882_algo[4].smbus_xfer = amd756_access_virt4;
+
+ /* Register virtual adapters */
+ for (i = 0; i < 5; i++) {
+ error = i2c_add_adapter(s4882_adapter+i);
+ if (error) {
+ printk(KERN_ERR "i2c-amd756-s4882: "
+ "Virtual adapter %d registration "
+ "failed, module not inserted\n", i);
+ for (i--; i >= 0; i--)
+ i2c_del_adapter(s4882_adapter+i);
+ goto ERROR3;
+ }
+ }
+
+ return 0;
+
+ERROR3:
+ kfree(s4882_algo);
+ s4882_algo = NULL;
+ERROR2:
+ kfree(s4882_adapter);
+ s4882_adapter = NULL;
+ERROR1:
+ /* Restore physical bus */
+ i2c_add_adapter(&amd756_smbus);
+ERROR0:
+ return error;
+}
+
+static void __exit amd756_s4882_exit(void)
+{
+ if (s4882_adapter) {
+ int i;
+
+ for (i = 0; i < 5; i++)
+ i2c_del_adapter(s4882_adapter+i);
+ kfree(s4882_adapter);
+ s4882_adapter = NULL;
+ }
+ kfree(s4882_algo);
+ s4882_algo = NULL;
+
+ /* Restore physical bus */
+ if (i2c_add_adapter(&amd756_smbus))
+ printk(KERN_ERR "i2c-amd756-s4882: "
+ "Physical bus restoration failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("S4882 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(amd756_s4882_init);
+module_exit(amd756_s4882_exit);
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
new file mode 100644
index 000000000..274908cd1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -0,0 +1,410 @@
+/*
+ Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
+
+ Shamelessly ripped from i2c-piix4.c:
+
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ 2002-04-08: Added nForce support. (Csaba Halasz)
+ 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
+ 2002-12-28: Rewritten into something that resembles a Linux driver (hch)
+ 2003-11-29: Added back AMD8111 removed by the previous rewrite.
+ (Philip Pokorny)
+*/
+
+/*
+ Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* AMD756 SMBus address offsets */
+#define SMB_ADDR_OFFSET 0xE0
+#define SMB_IOSIZE 16
+#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport)
+#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport)
+#define SMB_HOST_ADDRESS (0x4 + amd756_ioport)
+#define SMB_HOST_DATA (0x6 + amd756_ioport)
+#define SMB_HOST_COMMAND (0x8 + amd756_ioport)
+#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport)
+#define SMB_HAS_DATA (0xA + amd756_ioport)
+#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
+#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport)
+#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport)
+
+/* PCI Address Constants */
+
+/* address of I/O space */
+#define SMBBA 0x058 /* mh */
+#define SMBBANFORCE 0x014
+
+/* general configuration */
+#define SMBGCFG 0x041 /* mh */
+
+/* silicon revision code */
+#define SMBREV 0x008
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* AMD756 constants */
+#define AMD756_QUICK 0x00
+#define AMD756_BYTE 0x01
+#define AMD756_BYTE_DATA 0x02
+#define AMD756_WORD_DATA 0x03
+#define AMD756_PROCESS_CALL 0x04
+#define AMD756_BLOCK_DATA 0x05
+
+static struct pci_driver amd756_driver;
+static unsigned short amd756_ioport;
+
+/*
+ SMBUS event = I/O 28-29 bit 11
+ see E0 for the status bits and enabled in E2
+
+*/
+#define GS_ABRT_STS (1 << 0)
+#define GS_COL_STS (1 << 1)
+#define GS_PRERR_STS (1 << 2)
+#define GS_HST_STS (1 << 3)
+#define GS_HCYC_STS (1 << 4)
+#define GS_TO_STS (1 << 5)
+#define GS_SMB_STS (1 << 11)
+
+#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
+ GS_HCYC_STS | GS_TO_STS )
+
+#define GE_CYC_TYPE_MASK (7)
+#define GE_HOST_STC (1 << 3)
+#define GE_ABORT (1 << 5)
+
+
+static int amd756_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
+ "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
+ inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
+ inb_p(SMB_HOST_DATA));
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
+ dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
+ do {
+ msleep(1);
+ temp = inw_p(SMB_GLOBAL_STATUS);
+ } while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
+ (timeout++ < MAX_TIMEOUT));
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
+ goto abort;
+ }
+ timeout = 0;
+ }
+
+ /* start the transaction by setting the start bit */
+ outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = inw_p(SMB_GLOBAL_STATUS);
+ } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "Completion timeout!\n");
+ goto abort;
+ }
+
+ if (temp & GS_PRERR_STS) {
+ result = -ENXIO;
+ dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
+ }
+
+ if (temp & GS_COL_STS) {
+ result = -EIO;
+ dev_warn(&adap->dev, "SMBus collision!\n");
+ }
+
+ if (temp & GS_TO_STS) {
+ result = -ETIMEDOUT;
+ dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
+ }
+
+ if (temp & GS_HCYC_STS)
+ dev_dbg(&adap->dev, "SMBus protocol success!\n");
+
+ outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+
+#ifdef DEBUG
+ if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
+ dev_dbg(&adap->dev,
+ "Failed reset at end of transaction (%04x)\n", temp);
+ }
+#endif
+
+ dev_dbg(&adap->dev,
+ "Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+ inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+ inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+
+ return result;
+
+ abort:
+ dev_warn(&adap->dev, "Sending abort\n");
+ outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
+ msleep(100);
+ outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+ return -EIO;
+}
+
+/* Return negative errno on error. */
+static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ int i, len;
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ size = AMD756_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMB_HOST_DATA);
+ size = AMD756_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ outb_p(command, SMB_HOST_COMMAND);
+ if (read_write == I2C_SMBUS_WRITE)
+ outw_p(data->byte, SMB_HOST_DATA);
+ size = AMD756_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ outb_p(command, SMB_HOST_COMMAND);
+ if (read_write == I2C_SMBUS_WRITE)
+ outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */
+ size = AMD756_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMB_HOST_ADDRESS);
+ outb_p(command, SMB_HOST_COMMAND);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0)
+ len = 0;
+ if (len > 32)
+ len = 32;
+ outw_p(len, SMB_HOST_DATA);
+ /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i],
+ SMB_HOST_BLOCK_DATA);
+ }
+ size = AMD756_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ /* How about enabling interrupts... */
+ outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
+
+ status = amd756_transaction(adap);
+ if (status)
+ return status;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
+ return 0;
+
+
+ switch (size) {
+ case AMD756_BYTE:
+ data->byte = inw_p(SMB_HOST_DATA);
+ break;
+ case AMD756_BYTE_DATA:
+ data->byte = inw_p(SMB_HOST_DATA);
+ break;
+ case AMD756_WORD_DATA:
+ data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */
+ break;
+ case AMD756_BLOCK_DATA:
+ data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
+ if(data->block[0] > 32)
+ data->block[0] = 32;
+ /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
+ break;
+ }
+
+ return 0;
+}
+
+static u32 amd756_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = amd756_access,
+ .functionality = amd756_func,
+};
+
+struct i2c_adapter amd756_smbus = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
+static const char* chipname[] = {
+ "AMD756", "AMD766", "AMD768",
+ "nVidia nForce", "AMD8111",
+};
+
+static const struct pci_device_id amd756_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
+ .driver_data = AMD756 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
+ .driver_data = AMD766 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443),
+ .driver_data = AMD768 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS),
+ .driver_data = AMD8111 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS),
+ .driver_data = NFORCE },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd756_ids);
+
+static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int nforce = (id->driver_data == NFORCE);
+ int error;
+ u8 temp;
+
+ if (amd756_ioport) {
+ dev_err(&pdev->dev, "Only one device supported "
+ "(you have a strange motherboard, btw)\n");
+ return -ENODEV;
+ }
+
+ if (nforce) {
+ if (PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
+
+ pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
+ amd756_ioport &= 0xfffc;
+ } else { /* amd */
+ if (PCI_FUNC(pdev->devfn) != 3)
+ return -ENODEV;
+
+ pci_read_config_byte(pdev, SMBGCFG, &temp);
+ if ((temp & 128) == 0) {
+ dev_err(&pdev->dev,
+ "Error: SMBus controller I/O not enabled!\n");
+ return -ENODEV;
+ }
+
+ /* Determine the address of the SMBus areas */
+ /* Technically it is a dword but... */
+ pci_read_config_word(pdev, SMBBA, &amd756_ioport);
+ amd756_ioport &= 0xff00;
+ amd756_ioport += SMB_ADDR_OFFSET;
+ }
+
+ error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
+ amd756_driver.name);
+ if (error)
+ return -ENODEV;
+
+ if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
+ dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
+ amd756_ioport);
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(pdev, SMBREV, &temp);
+ dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
+ dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
+
+ /* set up the sysfs linkage to our parent device */
+ amd756_smbus.dev.parent = &pdev->dev;
+
+ snprintf(amd756_smbus.name, sizeof(amd756_smbus.name),
+ "SMBus %s adapter at %04x", chipname[id->driver_data],
+ amd756_ioport);
+
+ error = i2c_add_adapter(&amd756_smbus);
+ if (error)
+ goto out_err;
+
+ return 0;
+
+ out_err:
+ release_region(amd756_ioport, SMB_IOSIZE);
+ return error;
+}
+
+static void amd756_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&amd756_smbus);
+ release_region(amd756_ioport, SMB_IOSIZE);
+}
+
+static struct pci_driver amd756_driver = {
+ .name = "amd756_smbus",
+ .id_table = amd756_ids,
+ .probe = amd756_probe,
+ .remove = amd756_remove,
+};
+
+module_pci_driver(amd756_driver);
+
+MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
+MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(amd756_smbus);
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
new file mode 100644
index 000000000..134567f30
--- /dev/null
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -0,0 +1,493 @@
+/*
+ * SMBus 2.0 driver for AMD-8111 IO-Hub.
+ *
+ * Copyright (c) 2002 Vojtech Pavlik
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver");
+
+struct amd_smbus {
+ struct pci_dev *dev;
+ struct i2c_adapter adapter;
+ int base;
+ int size;
+};
+
+static struct pci_driver amd8111_driver;
+
+/*
+ * AMD PCI control registers definitions.
+ */
+
+#define AMD_PCI_MISC 0x48
+
+#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */
+#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */
+#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */
+
+/*
+ * ACPI 2.0 chapter 13 PCI interface definitions.
+ */
+
+#define AMD_EC_DATA 0x00 /* data register */
+#define AMD_EC_SC 0x04 /* status of controller */
+#define AMD_EC_CMD 0x04 /* command register */
+#define AMD_EC_ICR 0x08 /* interrupt control register */
+
+#define AMD_EC_SC_SMI 0x04 /* smi event pending */
+#define AMD_EC_SC_SCI 0x02 /* sci event pending */
+#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */
+#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */
+#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */
+#define AMD_EC_SC_OBF 0x01 /* data ready for host */
+
+#define AMD_EC_CMD_RD 0x80 /* read EC */
+#define AMD_EC_CMD_WR 0x81 /* write EC */
+#define AMD_EC_CMD_BE 0x82 /* enable burst mode */
+#define AMD_EC_CMD_BD 0x83 /* disable burst mode */
+#define AMD_EC_CMD_QR 0x84 /* query EC */
+
+/*
+ * ACPI 2.0 chapter 13 access of registers of the EC
+ */
+
+static int amd_ec_wait_write(struct amd_smbus *smbus)
+{
+ int timeout = 500;
+
+ while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout)
+ udelay(1);
+
+ if (!timeout) {
+ dev_warn(&smbus->dev->dev,
+ "Timeout while waiting for IBF to clear\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int amd_ec_wait_read(struct amd_smbus *smbus)
+{
+ int timeout = 500;
+
+ while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout)
+ udelay(1);
+
+ if (!timeout) {
+ dev_warn(&smbus->dev->dev,
+ "Timeout while waiting for OBF to set\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
+ unsigned char *data)
+{
+ int status;
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(address, smbus->base + AMD_EC_DATA);
+
+ status = amd_ec_wait_read(smbus);
+ if (status)
+ return status;
+ *data = inb(smbus->base + AMD_EC_DATA);
+
+ return 0;
+}
+
+static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
+ unsigned char data)
+{
+ int status;
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(address, smbus->base + AMD_EC_DATA);
+
+ status = amd_ec_wait_write(smbus);
+ if (status)
+ return status;
+ outb(data, smbus->base + AMD_EC_DATA);
+
+ return 0;
+}
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+
+#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */
+#define AMD_SMB_STS 0x01 /* status */
+#define AMD_SMB_ADDR 0x02 /* address */
+#define AMD_SMB_CMD 0x03 /* command */
+#define AMD_SMB_DATA 0x04 /* 32 data registers */
+#define AMD_SMB_BCNT 0x24 /* number of data bytes */
+#define AMD_SMB_ALRM_A 0x25 /* alarm address */
+#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
+
+#define AMD_SMB_STS_DONE 0x80
+#define AMD_SMB_STS_ALRM 0x40
+#define AMD_SMB_STS_RES 0x20
+#define AMD_SMB_STS_STATUS 0x1f
+
+#define AMD_SMB_STATUS_OK 0x00
+#define AMD_SMB_STATUS_FAIL 0x07
+#define AMD_SMB_STATUS_DNAK 0x10
+#define AMD_SMB_STATUS_DERR 0x11
+#define AMD_SMB_STATUS_CMD_DENY 0x12
+#define AMD_SMB_STATUS_UNKNOWN 0x13
+#define AMD_SMB_STATUS_ACC_DENY 0x17
+#define AMD_SMB_STATUS_TIMEOUT 0x18
+#define AMD_SMB_STATUS_NOTSUP 0x19
+#define AMD_SMB_STATUS_BUSY 0x1A
+#define AMD_SMB_STATUS_PEC 0x1F
+
+#define AMD_SMB_PRTCL_WRITE 0x00
+#define AMD_SMB_PRTCL_READ 0x01
+#define AMD_SMB_PRTCL_QUICK 0x02
+#define AMD_SMB_PRTCL_BYTE 0x04
+#define AMD_SMB_PRTCL_BYTE_DATA 0x06
+#define AMD_SMB_PRTCL_WORD_DATA 0x08
+#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a
+#define AMD_SMB_PRTCL_PROC_CALL 0x0c
+#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
+#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
+#define AMD_SMB_PRTCL_PEC 0x80
+
+
+static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
+{
+ struct amd_smbus *smbus = adap->algo_data;
+ unsigned char protocol, len, pec, temp[2];
+ int i, status;
+
+ protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ
+ : AMD_SMB_PRTCL_WRITE;
+ pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ protocol |= AMD_SMB_PRTCL_QUICK;
+ read_write = I2C_SMBUS_WRITE;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_CMD,
+ command);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->byte);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX);
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ for (i = 0; i < len; i++) {
+ status =
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
+ }
+ protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
+ break;
+
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ if (read_write == I2C_SMBUS_WRITE)
+ for (i = 0; i < len; i++) {
+ status =
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
+ protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
+ break;
+
+ case I2C_SMBUS_PROC_CALL:
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
+ if (status)
+ return status;
+ protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
+ read_write = I2C_SMBUS_READ;
+ break;
+
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX - 1);
+ status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+ if (status)
+ return status;
+ for (i = 0; i < len; i++) {
+ status = amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
+ if (status)
+ return status;
+ }
+ protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+ read_write = I2C_SMBUS_READ;
+ break;
+
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
+ if (status)
+ return status;
+ status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+ if (status)
+ return status;
+
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
+
+ if (~temp[0] & AMD_SMB_STS_DONE) {
+ udelay(500);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
+ }
+
+ if (~temp[0] & AMD_SMB_STS_DONE) {
+ msleep(1);
+ status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+ if (status)
+ return status;
+ }
+
+ if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
+ return -EIO;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+ if (status)
+ return status;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
+ if (status)
+ return status;
+ status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+ if (status)
+ return status;
+ data->word = (temp[1] << 8) | temp[0];
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+ if (status)
+ return status;
+ len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+ /* fall through */
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ for (i = 0; i < len; i++) {
+ status = amd_ec_read(smbus, AMD_SMB_DATA + i,
+ data->block + i + 1);
+ if (status)
+ return status;
+ }
+ data->block[0] = len;
+ break;
+ }
+
+ return 0;
+}
+
+
+static u32 amd8111_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = amd8111_access,
+ .functionality = amd8111_func,
+};
+
+
+static const struct pci_device_id amd8111_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd8111_ids);
+
+static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct amd_smbus *smbus;
+ int error;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+ return -ENODEV;
+
+ smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL);
+ if (!smbus)
+ return -ENOMEM;
+
+ smbus->dev = dev;
+ smbus->base = pci_resource_start(dev, 0);
+ smbus->size = pci_resource_len(dev, 0);
+
+ error = acpi_check_resource_conflict(&dev->resource[0]);
+ if (error) {
+ error = -ENODEV;
+ goto out_kfree;
+ }
+
+ if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
+ error = -EBUSY;
+ goto out_kfree;
+ }
+
+ smbus->adapter.owner = THIS_MODULE;
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+ "SMBus2 AMD8111 adapter at %04x", smbus->base);
+ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+
+ /* set up the sysfs linkage to our parent device */
+ smbus->adapter.dev.parent = &dev->dev;
+
+ pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
+ error = i2c_add_adapter(&smbus->adapter);
+ if (error)
+ goto out_release_region;
+
+ pci_set_drvdata(dev, smbus);
+ return 0;
+
+ out_release_region:
+ release_region(smbus->base, smbus->size);
+ out_kfree:
+ kfree(smbus);
+ return error;
+}
+
+static void amd8111_remove(struct pci_dev *dev)
+{
+ struct amd_smbus *smbus = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&smbus->adapter);
+ release_region(smbus->base, smbus->size);
+ kfree(smbus);
+}
+
+static struct pci_driver amd8111_driver = {
+ .name = "amd8111_smbus2",
+ .id_table = amd8111_ids,
+ .probe = amd8111_probe,
+ .remove = amd8111_remove,
+};
+
+module_pci_driver(amd8111_driver);
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
new file mode 100644
index 000000000..d9401b519
--- /dev/null
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -0,0 +1,979 @@
+/*
+ * Aspeed 24XX/25XX I2C Controller.
+ *
+ * Copyright (C) 2012-2017 ASPEED Technology Inc.
+ * Copyright 2017 IBM Corporation
+ * Copyright 2017 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+/* I2C Register */
+#define ASPEED_I2C_FUN_CTRL_REG 0x00
+#define ASPEED_I2C_AC_TIMING_REG1 0x04
+#define ASPEED_I2C_AC_TIMING_REG2 0x08
+#define ASPEED_I2C_INTR_CTRL_REG 0x0c
+#define ASPEED_I2C_INTR_STS_REG 0x10
+#define ASPEED_I2C_CMD_REG 0x14
+#define ASPEED_I2C_DEV_ADDR_REG 0x18
+#define ASPEED_I2C_BYTE_BUF_REG 0x20
+
+/* Global Register Definition */
+/* 0x00 : I2C Interrupt Status Register */
+/* 0x08 : I2C Interrupt Target Assignment */
+
+/* Device Register Definition */
+/* 0x00 : I2CD Function Control Register */
+#define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15)
+#define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8)
+#define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7)
+#define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6)
+#define ASPEED_I2CD_SLAVE_EN BIT(1)
+#define ASPEED_I2CD_MASTER_EN BIT(0)
+
+/* 0x04 : I2CD Clock and AC Timing Control Register #1 */
+#define ASPEED_I2CD_TIME_TBUF_MASK GENMASK(31, 28)
+#define ASPEED_I2CD_TIME_THDSTA_MASK GENMASK(27, 24)
+#define ASPEED_I2CD_TIME_TACST_MASK GENMASK(23, 20)
+#define ASPEED_I2CD_TIME_SCL_HIGH_SHIFT 16
+#define ASPEED_I2CD_TIME_SCL_HIGH_MASK GENMASK(19, 16)
+#define ASPEED_I2CD_TIME_SCL_LOW_SHIFT 12
+#define ASPEED_I2CD_TIME_SCL_LOW_MASK GENMASK(15, 12)
+#define ASPEED_I2CD_TIME_BASE_DIVISOR_MASK GENMASK(3, 0)
+#define ASPEED_I2CD_TIME_SCL_REG_MAX GENMASK(3, 0)
+/* 0x08 : I2CD Clock and AC Timing Control Register #2 */
+#define ASPEED_NO_TIMEOUT_CTRL 0
+
+/* 0x0c : I2CD Interrupt Control Register &
+ * 0x10 : I2CD Interrupt Status Register
+ *
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
+#define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+#define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
+#define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7)
+#define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6)
+#define ASPEED_I2CD_INTR_ABNORMAL BIT(5)
+#define ASPEED_I2CD_INTR_NORMAL_STOP BIT(4)
+#define ASPEED_I2CD_INTR_ARBIT_LOSS BIT(3)
+#define ASPEED_I2CD_INTR_RX_DONE BIT(2)
+#define ASPEED_I2CD_INTR_TX_NAK BIT(1)
+#define ASPEED_I2CD_INTR_TX_ACK BIT(0)
+#define ASPEED_I2CD_INTR_ALL \
+ (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
+ ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
+ ASPEED_I2CD_INTR_SCL_TIMEOUT | \
+ ASPEED_I2CD_INTR_ABNORMAL | \
+ ASPEED_I2CD_INTR_NORMAL_STOP | \
+ ASPEED_I2CD_INTR_ARBIT_LOSS | \
+ ASPEED_I2CD_INTR_RX_DONE | \
+ ASPEED_I2CD_INTR_TX_NAK | \
+ ASPEED_I2CD_INTR_TX_ACK)
+
+/* 0x14 : I2CD Command/Status Register */
+#define ASPEED_I2CD_SCL_LINE_STS BIT(18)
+#define ASPEED_I2CD_SDA_LINE_STS BIT(17)
+#define ASPEED_I2CD_BUS_BUSY_STS BIT(16)
+#define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11)
+
+/* Command Bit */
+#define ASPEED_I2CD_M_STOP_CMD BIT(5)
+#define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4)
+#define ASPEED_I2CD_M_RX_CMD BIT(3)
+#define ASPEED_I2CD_S_TX_CMD BIT(2)
+#define ASPEED_I2CD_M_TX_CMD BIT(1)
+#define ASPEED_I2CD_M_START_CMD BIT(0)
+
+/* 0x18 : I2CD Slave Device Address Register */
+#define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0)
+
+enum aspeed_i2c_master_state {
+ ASPEED_I2C_MASTER_INACTIVE,
+ ASPEED_I2C_MASTER_START,
+ ASPEED_I2C_MASTER_TX_FIRST,
+ ASPEED_I2C_MASTER_TX,
+ ASPEED_I2C_MASTER_RX_FIRST,
+ ASPEED_I2C_MASTER_RX,
+ ASPEED_I2C_MASTER_STOP,
+};
+
+enum aspeed_i2c_slave_state {
+ ASPEED_I2C_SLAVE_STOP,
+ ASPEED_I2C_SLAVE_START,
+ ASPEED_I2C_SLAVE_READ_REQUESTED,
+ ASPEED_I2C_SLAVE_READ_PROCESSED,
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED,
+ ASPEED_I2C_SLAVE_WRITE_RECEIVED,
+};
+
+struct aspeed_i2c_bus {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ struct reset_control *rst;
+ /* Synchronizes I/O mem access to base. */
+ spinlock_t lock;
+ struct completion cmd_complete;
+ u32 (*get_clk_reg_val)(struct device *dev,
+ u32 divisor);
+ unsigned long parent_clk_frequency;
+ u32 bus_frequency;
+ /* Transaction state. */
+ enum aspeed_i2c_master_state master_state;
+ struct i2c_msg *msgs;
+ size_t buf_index;
+ size_t msgs_index;
+ size_t msgs_count;
+ bool send_stop;
+ int cmd_err;
+ /* Protected only by i2c_lock_bus */
+ int master_xfer_result;
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+ enum aspeed_i2c_slave_state slave_state;
+#endif /* CONFIG_I2C_SLAVE */
+};
+
+static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
+
+static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
+{
+ unsigned long time_left, flags;
+ int ret = 0;
+ u32 command;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ command = readl(bus->base + ASPEED_I2C_CMD_REG);
+
+ if (command & ASPEED_I2CD_SDA_LINE_STS) {
+ /* Bus is idle: no recovery needed. */
+ if (command & ASPEED_I2CD_SCL_LINE_STS)
+ goto out;
+ dev_dbg(bus->dev, "SCL hung (state %x), attempting recovery\n",
+ command);
+
+ reinit_completion(&bus->cmd_complete);
+ writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_timeout(
+ &bus->cmd_complete, bus->adap.timeout);
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (time_left == 0)
+ goto reset_out;
+ else if (bus->cmd_err)
+ goto reset_out;
+ /* Recovery failed. */
+ else if (!(readl(bus->base + ASPEED_I2C_CMD_REG) &
+ ASPEED_I2CD_SCL_LINE_STS))
+ goto reset_out;
+ /* Bus error. */
+ } else {
+ dev_dbg(bus->dev, "SDA hung (state %x), attempting recovery\n",
+ command);
+
+ reinit_completion(&bus->cmd_complete);
+ /* Writes 1 to 8 SCL clock cycles until SDA is released. */
+ writel(ASPEED_I2CD_BUS_RECOVER_CMD,
+ bus->base + ASPEED_I2C_CMD_REG);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_timeout(
+ &bus->cmd_complete, bus->adap.timeout);
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (time_left == 0)
+ goto reset_out;
+ else if (bus->cmd_err)
+ goto reset_out;
+ /* Recovery failed. */
+ else if (!(readl(bus->base + ASPEED_I2C_CMD_REG) &
+ ASPEED_I2CD_SDA_LINE_STS))
+ goto reset_out;
+ }
+
+out:
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return ret;
+
+reset_out:
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return aspeed_i2c_reset(bus);
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
+{
+ u32 command, irq_status, status_ack = 0;
+ struct i2c_client *slave = bus->slave;
+ bool irq_handled = true;
+ u8 value;
+
+ if (!slave) {
+ irq_handled = false;
+ goto out;
+ }
+
+ command = readl(bus->base + ASPEED_I2C_CMD_REG);
+ irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
+
+ /* Slave was requested, restart state machine. */
+ if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
+ status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
+ bus->slave_state = ASPEED_I2C_SLAVE_START;
+ }
+
+ /* Slave is not currently active, irq was for someone else. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
+ irq_handled = false;
+ goto out;
+ }
+
+ dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
+ irq_status, command);
+
+ /* Slave was sent something. */
+ if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
+ value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
+ /* Handle address frame. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
+ if (value & 0x1)
+ bus->slave_state =
+ ASPEED_I2C_SLAVE_READ_REQUESTED;
+ else
+ bus->slave_state =
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED;
+ }
+ status_ack |= ASPEED_I2CD_INTR_RX_DONE;
+ }
+
+ /* Slave was asked to stop. */
+ if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
+ status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
+ if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
+ status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
+
+ switch (bus->slave_state) {
+ case ASPEED_I2C_SLAVE_READ_REQUESTED:
+ if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
+ dev_err(bus->dev, "Unexpected ACK on read request.\n");
+ bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
+
+ i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
+ writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
+ break;
+ case ASPEED_I2C_SLAVE_READ_PROCESSED:
+ status_ack |= ASPEED_I2CD_INTR_TX_ACK;
+ if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
+ dev_err(bus->dev,
+ "Expected ACK after processed read.\n");
+ i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
+ writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
+ break;
+ case ASPEED_I2C_SLAVE_WRITE_REQUESTED:
+ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+ break;
+ case ASPEED_I2C_SLAVE_WRITE_RECEIVED:
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);
+ break;
+ case ASPEED_I2C_SLAVE_STOP:
+ i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+ break;
+ default:
+ dev_err(bus->dev, "unhandled slave_state: %d\n",
+ bus->slave_state);
+ break;
+ }
+
+ if (status_ack != irq_status)
+ dev_err(bus->dev,
+ "irq handled != irq. expected %x, but was %x\n",
+ irq_status, status_ack);
+ writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
+
+out:
+ return irq_handled;
+}
+#endif /* CONFIG_I2C_SLAVE */
+
+/* precondition: bus.lock has been acquired. */
+static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
+{
+ u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD;
+ struct i2c_msg *msg = &bus->msgs[bus->msgs_index];
+ u8 slave_addr = i2c_8bit_addr_from_msg(msg);
+
+ bus->master_state = ASPEED_I2C_MASTER_START;
+ bus->buf_index = 0;
+
+ if (msg->flags & I2C_M_RD) {
+ command |= ASPEED_I2CD_M_RX_CMD;
+ /* Need to let the hardware know to NACK after RX. */
+ if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN))
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+ }
+
+ writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(command, bus->base + ASPEED_I2C_CMD_REG);
+}
+
+/* precondition: bus.lock has been acquired. */
+static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus)
+{
+ bus->master_state = ASPEED_I2C_MASTER_STOP;
+ writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
+}
+
+/* precondition: bus.lock has been acquired. */
+static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus)
+{
+ if (bus->msgs_index + 1 < bus->msgs_count) {
+ bus->msgs_index++;
+ aspeed_i2c_do_start(bus);
+ } else {
+ aspeed_i2c_do_stop(bus);
+ }
+}
+
+static int aspeed_i2c_is_irq_error(u32 irq_status)
+{
+ if (irq_status & ASPEED_I2CD_INTR_ARBIT_LOSS)
+ return -EAGAIN;
+ if (irq_status & (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |
+ ASPEED_I2CD_INTR_SCL_TIMEOUT))
+ return -EBUSY;
+ if (irq_status & (ASPEED_I2CD_INTR_ABNORMAL))
+ return -EPROTO;
+
+ return 0;
+}
+
+static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
+{
+ u32 irq_status, status_ack = 0, command = 0;
+ struct i2c_msg *msg;
+ u8 recv_byte;
+ int ret;
+
+ irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
+ /* Ack all interrupt bits. */
+ writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
+
+ if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
+ goto out_complete;
+ }
+
+ /*
+ * We encountered an interrupt that reports an error: the hardware
+ * should clear the command queue effectively taking us back to the
+ * INACTIVE state.
+ */
+ ret = aspeed_i2c_is_irq_error(irq_status);
+ if (ret < 0) {
+ dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
+ irq_status);
+ bus->cmd_err = ret;
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ goto out_complete;
+ }
+
+ /* We are in an invalid state; reset bus to a known state. */
+ if (!bus->msgs) {
+ dev_err(bus->dev, "bus in unknown state\n");
+ bus->cmd_err = -EIO;
+ if (bus->master_state != ASPEED_I2C_MASTER_STOP)
+ aspeed_i2c_do_stop(bus);
+ goto out_no_complete;
+ }
+ msg = &bus->msgs[bus->msgs_index];
+
+ /*
+ * START is a special case because we still have to handle a subsequent
+ * TX or RX immediately after we handle it, so we handle it here and
+ * then update the state and handle the new state below.
+ */
+ if (bus->master_state == ASPEED_I2C_MASTER_START) {
+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
+ pr_devel("no slave present at %02x\n", msg->addr);
+ status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ bus->cmd_err = -ENXIO;
+ aspeed_i2c_do_stop(bus);
+ goto out_no_complete;
+ }
+ status_ack |= ASPEED_I2CD_INTR_TX_ACK;
+ if (msg->len == 0) { /* SMBUS_QUICK */
+ aspeed_i2c_do_stop(bus);
+ goto out_no_complete;
+ }
+ if (msg->flags & I2C_M_RD)
+ bus->master_state = ASPEED_I2C_MASTER_RX_FIRST;
+ else
+ bus->master_state = ASPEED_I2C_MASTER_TX_FIRST;
+ }
+
+ switch (bus->master_state) {
+ case ASPEED_I2C_MASTER_TX:
+ if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
+ dev_dbg(bus->dev, "slave NACKed TX\n");
+ status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ goto error_and_stop;
+ } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
+ dev_err(bus->dev, "slave failed to ACK TX\n");
+ goto error_and_stop;
+ }
+ status_ack |= ASPEED_I2CD_INTR_TX_ACK;
+ /* fallthrough intended */
+ case ASPEED_I2C_MASTER_TX_FIRST:
+ if (bus->buf_index < msg->len) {
+ bus->master_state = ASPEED_I2C_MASTER_TX;
+ writel(msg->buf[bus->buf_index++],
+ bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(ASPEED_I2CD_M_TX_CMD,
+ bus->base + ASPEED_I2C_CMD_REG);
+ } else {
+ aspeed_i2c_next_msg_or_stop(bus);
+ }
+ goto out_no_complete;
+ case ASPEED_I2C_MASTER_RX_FIRST:
+ /* RX may not have completed yet (only address cycle) */
+ if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
+ goto out_no_complete;
+ /* fallthrough intended */
+ case ASPEED_I2C_MASTER_RX:
+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
+ dev_err(bus->dev, "master failed to RX\n");
+ goto error_and_stop;
+ }
+ status_ack |= ASPEED_I2CD_INTR_RX_DONE;
+
+ recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
+ msg->buf[bus->buf_index++] = recv_byte;
+
+ if (msg->flags & I2C_M_RECV_LEN) {
+ if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) {
+ bus->cmd_err = -EPROTO;
+ aspeed_i2c_do_stop(bus);
+ goto out_no_complete;
+ }
+ msg->len = recv_byte +
+ ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1);
+ msg->flags &= ~I2C_M_RECV_LEN;
+ }
+
+ if (bus->buf_index < msg->len) {
+ bus->master_state = ASPEED_I2C_MASTER_RX;
+ command = ASPEED_I2CD_M_RX_CMD;
+ if (bus->buf_index + 1 == msg->len)
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+ writel(command, bus->base + ASPEED_I2C_CMD_REG);
+ } else {
+ aspeed_i2c_next_msg_or_stop(bus);
+ }
+ goto out_no_complete;
+ case ASPEED_I2C_MASTER_STOP:
+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
+ dev_err(bus->dev, "master failed to STOP\n");
+ bus->cmd_err = -EIO;
+ /* Do not STOP as we have already tried. */
+ } else {
+ status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ }
+
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ goto out_complete;
+ case ASPEED_I2C_MASTER_INACTIVE:
+ dev_err(bus->dev,
+ "master received interrupt 0x%08x, but is inactive\n",
+ irq_status);
+ bus->cmd_err = -EIO;
+ /* Do not STOP as we should be inactive. */
+ goto out_complete;
+ default:
+ WARN(1, "unknown master state\n");
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ bus->cmd_err = -EINVAL;
+ goto out_complete;
+ }
+error_and_stop:
+ bus->cmd_err = -EIO;
+ aspeed_i2c_do_stop(bus);
+ goto out_no_complete;
+out_complete:
+ bus->msgs = NULL;
+ if (bus->cmd_err)
+ bus->master_xfer_result = bus->cmd_err;
+ else
+ bus->master_xfer_result = bus->msgs_index + 1;
+ complete(&bus->cmd_complete);
+out_no_complete:
+ if (irq_status != status_ack)
+ dev_err(bus->dev,
+ "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
+ irq_status, status_ack);
+ return !!irq_status;
+}
+
+static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
+{
+ struct aspeed_i2c_bus *bus = dev_id;
+ bool ret;
+
+ spin_lock(&bus->lock);
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (IS_ENABLED(CONFIG_I2C_SLAVE) && aspeed_i2c_slave_irq(bus)) {
+ dev_dbg(bus->dev, "irq handled by slave.\n");
+ ret = true;
+ goto out;
+ }
+#endif /* CONFIG_I2C_SLAVE */
+
+ ret = aspeed_i2c_master_irq(bus);
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+out:
+#endif
+ spin_unlock(&bus->lock);
+ return ret ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
+ unsigned long time_left, flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ bus->cmd_err = 0;
+
+ /* If bus is busy, attempt recovery. We assume a single master
+ * environment.
+ */
+ if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) {
+ spin_unlock_irqrestore(&bus->lock, flags);
+ ret = aspeed_i2c_recover_bus(bus);
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&bus->lock, flags);
+ }
+
+ bus->cmd_err = 0;
+ bus->msgs = msgs;
+ bus->msgs_index = 0;
+ bus->msgs_count = num;
+
+ reinit_completion(&bus->cmd_complete);
+ aspeed_i2c_do_start(bus);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ time_left = wait_for_completion_timeout(&bus->cmd_complete,
+ bus->adap.timeout);
+
+ if (time_left == 0)
+ return -ETIMEDOUT;
+ else
+ return bus->master_xfer_result;
+}
+
+static u32 aspeed_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+/* precondition: bus.lock has been acquired. */
+static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr)
+{
+ u32 addr_reg_val, func_ctrl_reg_val;
+
+ /* Set slave addr. */
+ addr_reg_val = readl(bus->base + ASPEED_I2C_DEV_ADDR_REG);
+ addr_reg_val &= ~ASPEED_I2CD_DEV_ADDR_MASK;
+ addr_reg_val |= slave_addr & ASPEED_I2CD_DEV_ADDR_MASK;
+ writel(addr_reg_val, bus->base + ASPEED_I2C_DEV_ADDR_REG);
+
+ /* Turn on slave mode. */
+ func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN;
+ writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+}
+
+static int aspeed_i2c_reg_slave(struct i2c_client *client)
+{
+ struct aspeed_i2c_bus *bus = i2c_get_adapdata(client->adapter);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (bus->slave) {
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return -EINVAL;
+ }
+
+ __aspeed_i2c_reg_slave(bus, client->addr);
+
+ bus->slave = client;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return 0;
+}
+
+static int aspeed_i2c_unreg_slave(struct i2c_client *client)
+{
+ struct aspeed_i2c_bus *bus = i2c_get_adapdata(client->adapter);
+ u32 func_ctrl_reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ if (!bus->slave) {
+ spin_unlock_irqrestore(&bus->lock, flags);
+ return -EINVAL;
+ }
+
+ /* Turn off slave mode. */
+ func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN;
+ writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+ bus->slave = NULL;
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return 0;
+}
+#endif /* CONFIG_I2C_SLAVE */
+
+static const struct i2c_algorithm aspeed_i2c_algo = {
+ .master_xfer = aspeed_i2c_master_xfer,
+ .functionality = aspeed_i2c_functionality,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ .reg_slave = aspeed_i2c_reg_slave,
+ .unreg_slave = aspeed_i2c_unreg_slave,
+#endif /* CONFIG_I2C_SLAVE */
+};
+
+static u32 aspeed_i2c_get_clk_reg_val(struct device *dev,
+ u32 clk_high_low_mask,
+ u32 divisor)
+{
+ u32 base_clk_divisor, clk_high_low_max, clk_high, clk_low, tmp;
+
+ /*
+ * SCL_high and SCL_low represent a value 1 greater than what is stored
+ * since a zero divider is meaningless. Thus, the max value each can
+ * store is every bit set + 1. Since SCL_high and SCL_low are added
+ * together (see below), the max value of both is the max value of one
+ * them times two.
+ */
+ clk_high_low_max = (clk_high_low_mask + 1) * 2;
+
+ /*
+ * The actual clock frequency of SCL is:
+ * SCL_freq = APB_freq / (base_freq * (SCL_high + SCL_low))
+ * = APB_freq / divisor
+ * where base_freq is a programmable clock divider; its value is
+ * base_freq = 1 << base_clk_divisor
+ * SCL_high is the number of base_freq clock cycles that SCL stays high
+ * and SCL_low is the number of base_freq clock cycles that SCL stays
+ * low for a period of SCL.
+ * The actual register has a minimum SCL_high and SCL_low minimum of 1;
+ * thus, they start counting at zero. So
+ * SCL_high = clk_high + 1
+ * SCL_low = clk_low + 1
+ * Thus,
+ * SCL_freq = APB_freq /
+ * ((1 << base_clk_divisor) * (clk_high + 1 + clk_low + 1))
+ * The documentation recommends clk_high >= clk_high_max / 2 and
+ * clk_low >= clk_low_max / 2 - 1 when possible; this last constraint
+ * gives us the following solution:
+ */
+ base_clk_divisor = divisor > clk_high_low_max ?
+ ilog2((divisor - 1) / clk_high_low_max) + 1 : 0;
+
+ if (base_clk_divisor > ASPEED_I2CD_TIME_BASE_DIVISOR_MASK) {
+ base_clk_divisor = ASPEED_I2CD_TIME_BASE_DIVISOR_MASK;
+ clk_low = clk_high_low_mask;
+ clk_high = clk_high_low_mask;
+ dev_err(dev,
+ "clamping clock divider: divider requested, %u, is greater than largest possible divider, %u.\n",
+ divisor, (1 << base_clk_divisor) * clk_high_low_max);
+ } else {
+ tmp = (divisor + (1 << base_clk_divisor) - 1)
+ >> base_clk_divisor;
+ clk_low = tmp / 2;
+ clk_high = tmp - clk_low;
+
+ if (clk_high)
+ clk_high--;
+
+ if (clk_low)
+ clk_low--;
+ }
+
+
+ return ((clk_high << ASPEED_I2CD_TIME_SCL_HIGH_SHIFT)
+ & ASPEED_I2CD_TIME_SCL_HIGH_MASK)
+ | ((clk_low << ASPEED_I2CD_TIME_SCL_LOW_SHIFT)
+ & ASPEED_I2CD_TIME_SCL_LOW_MASK)
+ | (base_clk_divisor
+ & ASPEED_I2CD_TIME_BASE_DIVISOR_MASK);
+}
+
+static u32 aspeed_i2c_24xx_get_clk_reg_val(struct device *dev, u32 divisor)
+{
+ /*
+ * clk_high and clk_low are each 3 bits wide, so each can hold a max
+ * value of 8 giving a clk_high_low_max of 16.
+ */
+ return aspeed_i2c_get_clk_reg_val(dev, GENMASK(2, 0), divisor);
+}
+
+static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor)
+{
+ /*
+ * clk_high and clk_low are each 4 bits wide, so each can hold a max
+ * value of 16 giving a clk_high_low_max of 32.
+ */
+ return aspeed_i2c_get_clk_reg_val(dev, GENMASK(3, 0), divisor);
+}
+
+/* precondition: bus.lock has been acquired. */
+static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
+{
+ u32 divisor, clk_reg_val;
+
+ divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency);
+ clk_reg_val = readl(bus->base + ASPEED_I2C_AC_TIMING_REG1);
+ clk_reg_val &= (ASPEED_I2CD_TIME_TBUF_MASK |
+ ASPEED_I2CD_TIME_THDSTA_MASK |
+ ASPEED_I2CD_TIME_TACST_MASK);
+ clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor);
+ writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1);
+ writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2);
+
+ return 0;
+}
+
+/* precondition: bus.lock has been acquired. */
+static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
+ struct platform_device *pdev)
+{
+ u32 fun_ctrl_reg = ASPEED_I2CD_MASTER_EN;
+ int ret;
+
+ /* Disable everything. */
+ writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+ ret = aspeed_i2c_init_clk(bus);
+ if (ret < 0)
+ return ret;
+
+ if (!of_property_read_bool(pdev->dev.of_node, "multi-master"))
+ fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS;
+
+ /* Enable Master Mode */
+ writel(readl(bus->base + ASPEED_I2C_FUN_CTRL_REG) | fun_ctrl_reg,
+ bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /* If slave has already been registered, re-enable it. */
+ if (bus->slave)
+ __aspeed_i2c_reg_slave(bus, bus->slave->addr);
+#endif /* CONFIG_I2C_SLAVE */
+
+ /* Set interrupt generation of I2C controller */
+ writel(ASPEED_I2CD_INTR_ALL, bus->base + ASPEED_I2C_INTR_CTRL_REG);
+
+ return 0;
+}
+
+static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus)
+{
+ struct platform_device *pdev = to_platform_device(bus->dev);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&bus->lock, flags);
+
+ /* Disable and ack all interrupts. */
+ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG);
+ writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG);
+
+ ret = aspeed_i2c_init(bus, pdev);
+
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return ret;
+}
+
+static const struct of_device_id aspeed_i2c_bus_of_table[] = {
+ {
+ .compatible = "aspeed,ast2400-i2c-bus",
+ .data = aspeed_i2c_24xx_get_clk_reg_val,
+ },
+ {
+ .compatible = "aspeed,ast2500-i2c-bus",
+ .data = aspeed_i2c_25xx_get_clk_reg_val,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
+
+static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct aspeed_i2c_bus *bus;
+ struct clk *parent_clk;
+ struct resource *res;
+ int irq, ret;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ bus->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(bus->base))
+ return PTR_ERR(bus->base);
+
+ parent_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(parent_clk))
+ return PTR_ERR(parent_clk);
+ bus->parent_clk_frequency = clk_get_rate(parent_clk);
+ /* We just need the clock rate, we don't actually use the clk object. */
+ devm_clk_put(&pdev->dev, parent_clk);
+
+ bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
+ if (IS_ERR(bus->rst)) {
+ dev_err(&pdev->dev,
+ "missing or invalid reset controller device tree entry\n");
+ return PTR_ERR(bus->rst);
+ }
+ reset_control_deassert(bus->rst);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "bus-frequency", &bus->bus_frequency);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Could not read bus-frequency property\n");
+ bus->bus_frequency = 100000;
+ }
+
+ match = of_match_node(aspeed_i2c_bus_of_table, pdev->dev.of_node);
+ if (!match)
+ bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
+ else
+ bus->get_clk_reg_val = (u32 (*)(struct device *, u32))
+ match->data;
+
+ /* Initialize the I2C adapter */
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
+ bus->adap.owner = THIS_MODULE;
+ bus->adap.retries = 0;
+ bus->adap.timeout = 5 * HZ;
+ bus->adap.algo = &aspeed_i2c_algo;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = pdev->dev.of_node;
+ strlcpy(bus->adap.name, pdev->name, sizeof(bus->adap.name));
+ i2c_set_adapdata(&bus->adap, bus);
+
+ bus->dev = &pdev->dev;
+
+ /* Clean up any left over interrupt state. */
+ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG);
+ writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG);
+ /*
+ * bus.lock does not need to be held because the interrupt handler has
+ * not been enabled yet.
+ */
+ ret = aspeed_i2c_init(bus, pdev);
+ if (ret < 0)
+ return ret;
+
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq,
+ 0, dev_name(&pdev->dev), bus);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_add_adapter(&bus->adap);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, bus);
+
+ dev_info(bus->dev, "i2c bus %d registered, irq %d\n",
+ bus->adap.nr, irq);
+
+ return 0;
+}
+
+static int aspeed_i2c_remove_bus(struct platform_device *pdev)
+{
+ struct aspeed_i2c_bus *bus = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bus->lock, flags);
+
+ /* Disable everything. */
+ writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG);
+
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ reset_control_assert(bus->rst);
+
+ i2c_del_adapter(&bus->adap);
+
+ return 0;
+}
+
+static struct platform_driver aspeed_i2c_bus_driver = {
+ .probe = aspeed_i2c_probe_bus,
+ .remove = aspeed_i2c_remove_bus,
+ .driver = {
+ .name = "aspeed-i2c-bus",
+ .of_match_table = aspeed_i2c_bus_of_table,
+ },
+};
+module_platform_driver(aspeed_i2c_bus_driver);
+
+MODULE_AUTHOR("Brendan Higgins <brendanhiggins@google.com>");
+MODULE_DESCRIPTION("Aspeed I2C Bus Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 000000000..29947eb90
--- /dev/null
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,1263 @@
+/*
+ * i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+ *
+ * Copyright (C) 2011 Weinmann Medical GmbH
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Evolved from original work by:
+ * Copyright (C) 2004 Rick Bronson
+ * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+ *
+ * Borrowed heavily from original work by:
+ * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-atmel.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
+
+#define DEFAULT_TWI_CLK_HZ 100000 /* max 400 Kbits/s */
+#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
+#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
+#define AUTOSUSPEND_TIMEOUT 2000
+#define AT91_I2C_MAX_ALT_CMD_DATA_SIZE 256
+
+/* AT91 TWI register definitions */
+#define AT91_TWI_CR 0x0000 /* Control Register */
+#define AT91_TWI_START BIT(0) /* Send a Start Condition */
+#define AT91_TWI_STOP BIT(1) /* Send a Stop Condition */
+#define AT91_TWI_MSEN BIT(2) /* Master Transfer Enable */
+#define AT91_TWI_MSDIS BIT(3) /* Master Transfer Disable */
+#define AT91_TWI_SVEN BIT(4) /* Slave Transfer Enable */
+#define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */
+#define AT91_TWI_QUICK BIT(6) /* SMBus quick command */
+#define AT91_TWI_SWRST BIT(7) /* Software Reset */
+#define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */
+#define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */
+#define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */
+#define AT91_TWI_RHRCLR BIT(25) /* Receive Holding Register Clear */
+#define AT91_TWI_LOCKCLR BIT(26) /* Lock Clear */
+#define AT91_TWI_FIFOEN BIT(28) /* FIFO Enable */
+#define AT91_TWI_FIFODIS BIT(29) /* FIFO Disable */
+
+#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
+#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */
+#define AT91_TWI_MREAD BIT(12) /* Master Read Direction */
+
+#define AT91_TWI_IADR 0x000c /* Internal Address Register */
+
+#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
+#define AT91_TWI_CWGR_HOLD_MAX 0x1f
+#define AT91_TWI_CWGR_HOLD(x) (((x) & AT91_TWI_CWGR_HOLD_MAX) << 24)
+
+#define AT91_TWI_SR 0x0020 /* Status Register */
+#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */
+#define AT91_TWI_RXRDY BIT(1) /* Receive Holding Register Ready */
+#define AT91_TWI_TXRDY BIT(2) /* Transmit Holding Register Ready */
+#define AT91_TWI_OVRE BIT(6) /* Overrun Error */
+#define AT91_TWI_UNRE BIT(7) /* Underrun Error */
+#define AT91_TWI_NACK BIT(8) /* Not Acknowledged */
+#define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */
+
+#define AT91_TWI_INT_MASK \
+ (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK)
+
+#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */
+#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */
+#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */
+#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */
+#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
+
+#define AT91_TWI_ACR 0x0040 /* Alternative Command Register */
+#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
+#define AT91_TWI_ACR_DIR BIT(8)
+
+#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */
+#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0)
+#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0)
+#define AT91_TWI_FMR_RXRDYM(mode) (((mode) & 0x3) << 4)
+#define AT91_TWI_FMR_RXRDYM_MASK (0x3 << 4)
+#define AT91_TWI_ONE_DATA 0x0
+#define AT91_TWI_TWO_DATA 0x1
+#define AT91_TWI_FOUR_DATA 0x2
+
+#define AT91_TWI_FLR 0x0054 /* FIFO Level Register */
+
+#define AT91_TWI_FSR 0x0060 /* FIFO Status Register */
+#define AT91_TWI_FIER 0x0064 /* FIFO Interrupt Enable Register */
+#define AT91_TWI_FIDR 0x0068 /* FIFO Interrupt Disable Register */
+#define AT91_TWI_FIMR 0x006c /* FIFO Interrupt Mask Register */
+
+#define AT91_TWI_VER 0x00fc /* Version Register */
+
+struct at91_twi_pdata {
+ unsigned clk_max_div;
+ unsigned clk_offset;
+ bool has_unre_flag;
+ bool has_alt_cmd;
+ bool has_hold_field;
+ struct at_dma_slave dma_slave;
+};
+
+struct at91_twi_dma {
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct scatterlist sg[2];
+ struct dma_async_tx_descriptor *data_desc;
+ enum dma_data_direction direction;
+ bool buf_mapped;
+ bool xfer_in_progress;
+};
+
+struct at91_twi_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_msg *msg;
+ int irq;
+ unsigned imr;
+ unsigned transfer_status;
+ struct i2c_adapter adapter;
+ unsigned twi_cwgr_reg;
+ struct at91_twi_pdata *pdata;
+ bool use_dma;
+ bool use_alt_cmd;
+ bool recv_len_abort;
+ u32 fifo_size;
+ struct at91_twi_dma dma;
+};
+
+static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
+{
+ return readl_relaxed(dev->base + reg);
+}
+
+static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
+{
+ writel_relaxed(val, dev->base + reg);
+}
+
+static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
+{
+ at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK);
+}
+
+static void at91_twi_irq_save(struct at91_twi_dev *dev)
+{
+ dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK;
+ at91_disable_twi_interrupts(dev);
+}
+
+static void at91_twi_irq_restore(struct at91_twi_dev *dev)
+{
+ at91_twi_write(dev, AT91_TWI_IER, dev->imr);
+}
+
+static void at91_init_twi_bus(struct at91_twi_dev *dev)
+{
+ at91_disable_twi_interrupts(dev);
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
+ /* FIFO should be enabled immediately after the software reset */
+ if (dev->fifo_size)
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_FIFOEN);
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
+ at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
+}
+
+/*
+ * Calculate symmetric clock as stated in datasheet:
+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
+ */
+static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
+{
+ int ckdiv, cdiv, div, hold = 0;
+ struct at91_twi_pdata *pdata = dev->pdata;
+ int offset = pdata->clk_offset;
+ int max_ckdiv = pdata->clk_max_div;
+ u32 twd_hold_time_ns = 0;
+
+ div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
+ 2 * twi_clk) - offset);
+ ckdiv = fls(div >> 8);
+ cdiv = div >> ckdiv;
+
+ if (ckdiv > max_ckdiv) {
+ dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
+ ckdiv, max_ckdiv);
+ ckdiv = max_ckdiv;
+ cdiv = 255;
+ }
+
+ if (pdata->has_hold_field) {
+ of_property_read_u32(dev->dev->of_node, "i2c-sda-hold-time-ns",
+ &twd_hold_time_ns);
+
+ /*
+ * hold time = HOLD + 3 x T_peripheral_clock
+ * Use clk rate in kHz to prevent overflows when computing
+ * hold.
+ */
+ hold = DIV_ROUND_UP(twd_hold_time_ns
+ * (clk_get_rate(dev->clk) / 1000), 1000000);
+ hold -= 3;
+ if (hold < 0)
+ hold = 0;
+ if (hold > AT91_TWI_CWGR_HOLD_MAX) {
+ dev_warn(dev->dev,
+ "HOLD field set to its maximum value (%d instead of %d)\n",
+ AT91_TWI_CWGR_HOLD_MAX, hold);
+ hold = AT91_TWI_CWGR_HOLD_MAX;
+ }
+ }
+
+ dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
+ | AT91_TWI_CWGR_HOLD(hold);
+
+ dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns)\n",
+ cdiv, ckdiv, hold, twd_hold_time_ns);
+}
+
+static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
+{
+ struct at91_twi_dma *dma = &dev->dma;
+
+ at91_twi_irq_save(dev);
+
+ if (dma->xfer_in_progress) {
+ if (dma->direction == DMA_FROM_DEVICE)
+ dmaengine_terminate_all(dma->chan_rx);
+ else
+ dmaengine_terminate_all(dma->chan_tx);
+ dma->xfer_in_progress = false;
+ }
+ if (dma->buf_mapped) {
+ dma_unmap_single(dev->dev, sg_dma_address(&dma->sg[0]),
+ dev->buf_len, dma->direction);
+ dma->buf_mapped = false;
+ }
+
+ at91_twi_irq_restore(dev);
+}
+
+static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+{
+ if (!dev->buf_len)
+ return;
+
+ /* 8bit write works with and without FIFO */
+ writeb_relaxed(*dev->buf, dev->base + AT91_TWI_THR);
+
+ /* send stop when last byte has been written */
+ if (--dev->buf_len == 0) {
+ if (!dev->use_alt_cmd)
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+ at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_TXRDY);
+ }
+
+ dev_dbg(dev->dev, "wrote 0x%x, to go %zu\n", *dev->buf, dev->buf_len);
+
+ ++dev->buf;
+}
+
+static void at91_twi_write_data_dma_callback(void *data)
+{
+ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
+
+ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]),
+ dev->buf_len, DMA_TO_DEVICE);
+
+ /*
+ * When this callback is called, THR/TX FIFO is likely not to be empty
+ * yet. So we have to wait for TXCOMP or NACK bits to be set into the
+ * Status Register to be sure that the STOP bit has been sent and the
+ * transfer is completed. The NACK interrupt has already been enabled,
+ * we just have to enable TXCOMP one.
+ */
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
+ if (!dev->use_alt_cmd)
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+}
+
+static void at91_twi_write_data_dma(struct at91_twi_dev *dev)
+{
+ dma_addr_t dma_addr;
+ struct dma_async_tx_descriptor *txdesc;
+ struct at91_twi_dma *dma = &dev->dma;
+ struct dma_chan *chan_tx = dma->chan_tx;
+ unsigned int sg_len = 1;
+
+ if (!dev->buf_len)
+ return;
+
+ dma->direction = DMA_TO_DEVICE;
+
+ at91_twi_irq_save(dev);
+ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev->dev, dma_addr)) {
+ dev_err(dev->dev, "dma map failed\n");
+ return;
+ }
+ dma->buf_mapped = true;
+ at91_twi_irq_restore(dev);
+
+ if (dev->fifo_size) {
+ size_t part1_len, part2_len;
+ struct scatterlist *sg;
+ unsigned fifo_mr;
+
+ sg_len = 0;
+
+ part1_len = dev->buf_len & ~0x3;
+ if (part1_len) {
+ sg = &dma->sg[sg_len++];
+ sg_dma_len(sg) = part1_len;
+ sg_dma_address(sg) = dma_addr;
+ }
+
+ part2_len = dev->buf_len & 0x3;
+ if (part2_len) {
+ sg = &dma->sg[sg_len++];
+ sg_dma_len(sg) = part2_len;
+ sg_dma_address(sg) = dma_addr + part1_len;
+ }
+
+ /*
+ * DMA controller is triggered when at least 4 data can be
+ * written into the TX FIFO
+ */
+ fifo_mr = at91_twi_read(dev, AT91_TWI_FMR);
+ fifo_mr &= ~AT91_TWI_FMR_TXRDYM_MASK;
+ fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_FOUR_DATA);
+ at91_twi_write(dev, AT91_TWI_FMR, fifo_mr);
+ } else {
+ sg_dma_len(&dma->sg[0]) = dev->buf_len;
+ sg_dma_address(&dma->sg[0]) = dma_addr;
+ }
+
+ txdesc = dmaengine_prep_slave_sg(chan_tx, dma->sg, sg_len,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc) {
+ dev_err(dev->dev, "dma prep slave sg failed\n");
+ goto error;
+ }
+
+ txdesc->callback = at91_twi_write_data_dma_callback;
+ txdesc->callback_param = dev;
+
+ dma->xfer_in_progress = true;
+ dmaengine_submit(txdesc);
+ dma_async_issue_pending(chan_tx);
+
+ return;
+
+error:
+ at91_twi_dma_cleanup(dev);
+}
+
+static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+{
+ /*
+ * If we are in this case, it means there is garbage data in RHR, so
+ * delete them.
+ */
+ if (!dev->buf_len) {
+ at91_twi_read(dev, AT91_TWI_RHR);
+ return;
+ }
+
+ /* 8bit read works with and without FIFO */
+ *dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR);
+ --dev->buf_len;
+
+ /* return if aborting, we only needed to read RHR to clear RXRDY*/
+ if (dev->recv_len_abort)
+ return;
+
+ /* handle I2C_SMBUS_BLOCK_DATA */
+ if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
+ /* ensure length byte is a valid value */
+ if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) {
+ dev->msg->flags &= ~I2C_M_RECV_LEN;
+ dev->buf_len += *dev->buf;
+ dev->msg->len = dev->buf_len + 1;
+ dev_dbg(dev->dev, "received block length %zu\n",
+ dev->buf_len);
+ } else {
+ /* abort and send the stop by reading one more byte */
+ dev->recv_len_abort = true;
+ dev->buf_len = 1;
+ }
+ }
+
+ /* send stop if second but last byte has been read */
+ if (!dev->use_alt_cmd && dev->buf_len == 1)
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+
+ dev_dbg(dev->dev, "read 0x%x, to go %zu\n", *dev->buf, dev->buf_len);
+
+ ++dev->buf;
+}
+
+static void at91_twi_read_data_dma_callback(void *data)
+{
+ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
+ unsigned ier = AT91_TWI_TXCOMP;
+
+ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]),
+ dev->buf_len, DMA_FROM_DEVICE);
+
+ if (!dev->use_alt_cmd) {
+ /* The last two bytes have to be read without using dma */
+ dev->buf += dev->buf_len - 2;
+ dev->buf_len = 2;
+ ier |= AT91_TWI_RXRDY;
+ }
+ at91_twi_write(dev, AT91_TWI_IER, ier);
+}
+
+static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
+{
+ dma_addr_t dma_addr;
+ struct dma_async_tx_descriptor *rxdesc;
+ struct at91_twi_dma *dma = &dev->dma;
+ struct dma_chan *chan_rx = dma->chan_rx;
+ size_t buf_len;
+
+ buf_len = (dev->use_alt_cmd) ? dev->buf_len : dev->buf_len - 2;
+ dma->direction = DMA_FROM_DEVICE;
+
+ /* Keep in mind that we won't use dma to read the last two bytes */
+ at91_twi_irq_save(dev);
+ dma_addr = dma_map_single(dev->dev, dev->buf, buf_len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev->dev, dma_addr)) {
+ dev_err(dev->dev, "dma map failed\n");
+ return;
+ }
+ dma->buf_mapped = true;
+ at91_twi_irq_restore(dev);
+
+ if (dev->fifo_size && IS_ALIGNED(buf_len, 4)) {
+ unsigned fifo_mr;
+
+ /*
+ * DMA controller is triggered when at least 4 data can be
+ * read from the RX FIFO
+ */
+ fifo_mr = at91_twi_read(dev, AT91_TWI_FMR);
+ fifo_mr &= ~AT91_TWI_FMR_RXRDYM_MASK;
+ fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_FOUR_DATA);
+ at91_twi_write(dev, AT91_TWI_FMR, fifo_mr);
+ }
+
+ sg_dma_len(&dma->sg[0]) = buf_len;
+ sg_dma_address(&dma->sg[0]) = dma_addr;
+
+ rxdesc = dmaengine_prep_slave_sg(chan_rx, dma->sg, 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!rxdesc) {
+ dev_err(dev->dev, "dma prep slave sg failed\n");
+ goto error;
+ }
+
+ rxdesc->callback = at91_twi_read_data_dma_callback;
+ rxdesc->callback_param = dev;
+
+ dma->xfer_in_progress = true;
+ dmaengine_submit(rxdesc);
+ dma_async_issue_pending(dma->chan_rx);
+
+ return;
+
+error:
+ at91_twi_dma_cleanup(dev);
+}
+
+static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
+{
+ struct at91_twi_dev *dev = dev_id;
+ const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
+ const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
+
+ if (!irqstatus)
+ return IRQ_NONE;
+ /*
+ * In reception, the behavior of the twi device (before sama5d2) is
+ * weird. There is some magic about RXRDY flag! When a data has been
+ * almost received, the reception of a new one is anticipated if there
+ * is no stop command to send. That is the reason why ask for sending
+ * the stop command not on the last data but on the second last one.
+ *
+ * Unfortunately, we could still have the RXRDY flag set even if the
+ * transfer is done and we have read the last data. It might happen
+ * when the i2c slave device sends too quickly data after receiving the
+ * ack from the master. The data has been almost received before having
+ * the order to send stop. In this case, sending the stop command could
+ * cause a RXRDY interrupt with a TXCOMP one. It is better to manage
+ * the RXRDY interrupt first in order to not keep garbage data in the
+ * Receive Holding Register for the next transfer.
+ */
+ if (irqstatus & AT91_TWI_RXRDY) {
+ /*
+ * Read all available bytes at once by polling RXRDY usable w/
+ * and w/o FIFO. With FIFO enabled we could also read RXFL and
+ * avoid polling RXRDY.
+ */
+ do {
+ at91_twi_read_next_byte(dev);
+ } while (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY);
+ }
+
+ /*
+ * When a NACK condition is detected, the I2C controller sets the NACK,
+ * TXCOMP and TXRDY bits all together in the Status Register (SR).
+ *
+ * 1 - Handling NACK errors with CPU write transfer.
+ *
+ * In such case, we should not write the next byte into the Transmit
+ * Holding Register (THR) otherwise the I2C controller would start a new
+ * transfer and the I2C slave is likely to reply by another NACK.
+ *
+ * 2 - Handling NACK errors with DMA write transfer.
+ *
+ * By setting the TXRDY bit in the SR, the I2C controller also triggers
+ * the DMA controller to write the next data into the THR. Then the
+ * result depends on the hardware version of the I2C controller.
+ *
+ * 2a - Without support of the Alternative Command mode.
+ *
+ * This is the worst case: the DMA controller is triggered to write the
+ * next data into the THR, hence starting a new transfer: the I2C slave
+ * is likely to reply by another NACK.
+ * Concurrently, this interrupt handler is likely to be called to manage
+ * the first NACK before the I2C controller detects the second NACK and
+ * sets once again the NACK bit into the SR.
+ * When handling the first NACK, this interrupt handler disables the I2C
+ * controller interruptions, especially the NACK interrupt.
+ * Hence, the NACK bit is pending into the SR. This is why we should
+ * read the SR to clear all pending interrupts at the beginning of
+ * at91_do_twi_transfer() before actually starting a new transfer.
+ *
+ * 2b - With support of the Alternative Command mode.
+ *
+ * When a NACK condition is detected, the I2C controller also locks the
+ * THR (and sets the LOCK bit in the SR): even though the DMA controller
+ * is triggered by the TXRDY bit to write the next data into the THR,
+ * this data actually won't go on the I2C bus hence a second NACK is not
+ * generated.
+ */
+ if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) {
+ at91_disable_twi_interrupts(dev);
+ complete(&dev->cmd_complete);
+ } else if (irqstatus & AT91_TWI_TXRDY) {
+ at91_twi_write_next_byte(dev);
+ }
+
+ /* catch error flags */
+ dev->transfer_status |= status;
+
+ return IRQ_HANDLED;
+}
+
+static int at91_do_twi_transfer(struct at91_twi_dev *dev)
+{
+ int ret;
+ unsigned long time_left;
+ bool has_unre_flag = dev->pdata->has_unre_flag;
+ bool has_alt_cmd = dev->pdata->has_alt_cmd;
+
+ /*
+ * WARNING: the TXCOMP bit in the Status Register is NOT a clear on
+ * read flag but shows the state of the transmission at the time the
+ * Status Register is read. According to the programmer datasheet,
+ * TXCOMP is set when both holding register and internal shifter are
+ * empty and STOP condition has been sent.
+ * Consequently, we should enable NACK interrupt rather than TXCOMP to
+ * detect transmission failure.
+ * Indeed let's take the case of an i2c write command using DMA.
+ * Whenever the slave doesn't acknowledge a byte, the LOCK, NACK and
+ * TXCOMP bits are set together into the Status Register.
+ * LOCK is a clear on write bit, which is set to prevent the DMA
+ * controller from sending new data on the i2c bus after a NACK
+ * condition has happened. Once locked, this i2c peripheral stops
+ * triggering the DMA controller for new data but it is more than
+ * likely that a new DMA transaction is already in progress, writing
+ * into the Transmit Holding Register. Since the peripheral is locked,
+ * these new data won't be sent to the i2c bus but they will remain
+ * into the Transmit Holding Register, so TXCOMP bit is cleared.
+ * Then when the interrupt handler is called, the Status Register is
+ * read: the TXCOMP bit is clear but NACK bit is still set. The driver
+ * manage the error properly, without waiting for timeout.
+ * This case can be reproduced easyly when writing into an at24 eeprom.
+ *
+ * Besides, the TXCOMP bit is already set before the i2c transaction
+ * has been started. For read transactions, this bit is cleared when
+ * writing the START bit into the Control Register. So the
+ * corresponding interrupt can safely be enabled just after.
+ * However for write transactions managed by the CPU, we first write
+ * into THR, so TXCOMP is cleared. Then we can safely enable TXCOMP
+ * interrupt. If TXCOMP interrupt were enabled before writing into THR,
+ * the interrupt handler would be called immediately and the i2c command
+ * would be reported as completed.
+ * Also when a write transaction is managed by the DMA controller,
+ * enabling the TXCOMP interrupt in this function may lead to a race
+ * condition since we don't know whether the TXCOMP interrupt is enabled
+ * before or after the DMA has started to write into THR. So the TXCOMP
+ * interrupt is enabled later by at91_twi_write_data_dma_callback().
+ * Immediately after in that DMA callback, if the alternative command
+ * mode is not used, we still need to send the STOP condition manually
+ * writing the corresponding bit into the Control Register.
+ */
+
+ dev_dbg(dev->dev, "transfer: %s %zu bytes.\n",
+ (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
+
+ reinit_completion(&dev->cmd_complete);
+ dev->transfer_status = 0;
+
+ /* Clear pending interrupts, such as NACK. */
+ at91_twi_read(dev, AT91_TWI_SR);
+
+ if (dev->fifo_size) {
+ unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR);
+
+ /* Reset FIFO mode register */
+ fifo_mr &= ~(AT91_TWI_FMR_TXRDYM_MASK |
+ AT91_TWI_FMR_RXRDYM_MASK);
+ fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_ONE_DATA);
+ fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_ONE_DATA);
+ at91_twi_write(dev, AT91_TWI_FMR, fifo_mr);
+
+ /* Flush FIFOs */
+ at91_twi_write(dev, AT91_TWI_CR,
+ AT91_TWI_THRCLR | AT91_TWI_RHRCLR);
+ }
+
+ if (!dev->buf_len) {
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK);
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
+ } else if (dev->msg->flags & I2C_M_RD) {
+ unsigned start_flags = AT91_TWI_START;
+
+ /* if only one byte is to be read, immediately stop transfer */
+ if (!dev->use_alt_cmd && dev->buf_len <= 1 &&
+ !(dev->msg->flags & I2C_M_RECV_LEN))
+ start_flags |= AT91_TWI_STOP;
+ at91_twi_write(dev, AT91_TWI_CR, start_flags);
+ /*
+ * When using dma without alternative command mode, the last
+ * byte has to be read manually in order to not send the stop
+ * command too late and then to receive extra data.
+ * In practice, there are some issues if you use the dma to
+ * read n-1 bytes because of latency.
+ * Reading n-2 bytes with dma and the two last ones manually
+ * seems to be the best solution.
+ */
+ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) {
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK);
+ at91_twi_read_data_dma(dev);
+ } else {
+ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP |
+ AT91_TWI_NACK |
+ AT91_TWI_RXRDY);
+ }
+ } else {
+ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) {
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK);
+ at91_twi_write_data_dma(dev);
+ } else {
+ at91_twi_write_next_byte(dev);
+ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP | AT91_TWI_NACK |
+ (dev->buf_len ? AT91_TWI_TXRDY : 0));
+ }
+ }
+
+ time_left = wait_for_completion_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (time_left == 0) {
+ dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR);
+ dev_err(dev->dev, "controller timed out\n");
+ at91_init_twi_bus(dev);
+ ret = -ETIMEDOUT;
+ goto error;
+ }
+ if (dev->transfer_status & AT91_TWI_NACK) {
+ dev_dbg(dev->dev, "received nack\n");
+ ret = -EREMOTEIO;
+ goto error;
+ }
+ if (dev->transfer_status & AT91_TWI_OVRE) {
+ dev_err(dev->dev, "overrun while reading\n");
+ ret = -EIO;
+ goto error;
+ }
+ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
+ dev_err(dev->dev, "underrun while writing\n");
+ ret = -EIO;
+ goto error;
+ }
+ if ((has_alt_cmd || dev->fifo_size) &&
+ (dev->transfer_status & AT91_TWI_LOCK)) {
+ dev_err(dev->dev, "tx locked\n");
+ ret = -EIO;
+ goto error;
+ }
+ if (dev->recv_len_abort) {
+ dev_err(dev->dev, "invalid smbus block length recvd\n");
+ ret = -EPROTO;
+ goto error;
+ }
+
+ dev_dbg(dev->dev, "transfer complete\n");
+
+ return 0;
+
+error:
+ /* first stop DMA transfer if still in progress */
+ at91_twi_dma_cleanup(dev);
+ /* then flush THR/FIFO and unlock TX if locked */
+ if ((has_alt_cmd || dev->fifo_size) &&
+ (dev->transfer_status & AT91_TWI_LOCK)) {
+ dev_dbg(dev->dev, "unlock tx\n");
+ at91_twi_write(dev, AT91_TWI_CR,
+ AT91_TWI_THRCLR | AT91_TWI_LOCKCLR);
+ }
+ return ret;
+}
+
+static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
+{
+ struct at91_twi_dev *dev = i2c_get_adapdata(adap);
+ int ret;
+ unsigned int_addr_flag = 0;
+ struct i2c_msg *m_start = msg;
+ bool is_read;
+ u8 *dma_buf = NULL;
+
+ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+
+ ret = pm_runtime_get_sync(dev->dev);
+ if (ret < 0)
+ goto out;
+
+ if (num == 2) {
+ int internal_address = 0;
+ int i;
+
+ /* 1st msg is put into the internal address, start with 2nd */
+ m_start = &msg[1];
+ for (i = 0; i < msg->len; ++i) {
+ const unsigned addr = msg->buf[msg->len - 1 - i];
+
+ internal_address |= addr << (8 * i);
+ int_addr_flag += AT91_TWI_IADRSZ_1;
+ }
+ at91_twi_write(dev, AT91_TWI_IADR, internal_address);
+ }
+
+ dev->use_alt_cmd = false;
+ is_read = (m_start->flags & I2C_M_RD);
+ if (dev->pdata->has_alt_cmd) {
+ if (m_start->len > 0 &&
+ m_start->len < AT91_I2C_MAX_ALT_CMD_DATA_SIZE) {
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMEN);
+ at91_twi_write(dev, AT91_TWI_ACR,
+ AT91_TWI_ACR_DATAL(m_start->len) |
+ ((is_read) ? AT91_TWI_ACR_DIR : 0));
+ dev->use_alt_cmd = true;
+ } else {
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS);
+ }
+ }
+
+ at91_twi_write(dev, AT91_TWI_MMR,
+ (m_start->addr << 16) |
+ int_addr_flag |
+ ((!dev->use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0));
+
+ dev->buf_len = m_start->len;
+ dev->buf = m_start->buf;
+ dev->msg = m_start;
+ dev->recv_len_abort = false;
+
+ if (dev->use_dma) {
+ dma_buf = i2c_get_dma_safe_msg_buf(m_start, 1);
+ if (!dma_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ dev->buf = dma_buf;
+ }
+
+ ret = at91_do_twi_transfer(dev);
+ i2c_put_dma_safe_msg_buf(dma_buf, m_start, !ret);
+
+ ret = (ret < 0) ? ret : num;
+out:
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+
+ return ret;
+}
+
+/*
+ * The hardware can handle at most two messages concatenated by a
+ * repeated start via it's internal address feature.
+ */
+static const struct i2c_adapter_quirks at91_twi_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
+ .max_comb_1st_msg_len = 3,
+};
+
+static u32 at91_twi_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm at91_twi_algorithm = {
+ .master_xfer = at91_twi_xfer,
+ .functionality = at91_twi_func,
+};
+
+static struct at91_twi_pdata at91rm9200_config = {
+ .clk_max_div = 5,
+ .clk_offset = 3,
+ .has_unre_flag = true,
+ .has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static struct at91_twi_pdata at91sam9261_config = {
+ .clk_max_div = 5,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static struct at91_twi_pdata at91sam9260_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static struct at91_twi_pdata at91sam9g20_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static struct at91_twi_pdata at91sam9g10_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static const struct platform_device_id at91_twi_devtypes[] = {
+ {
+ .name = "i2c-at91rm9200",
+ .driver_data = (unsigned long) &at91rm9200_config,
+ }, {
+ .name = "i2c-at91sam9261",
+ .driver_data = (unsigned long) &at91sam9261_config,
+ }, {
+ .name = "i2c-at91sam9260",
+ .driver_data = (unsigned long) &at91sam9260_config,
+ }, {
+ .name = "i2c-at91sam9g20",
+ .driver_data = (unsigned long) &at91sam9g20_config,
+ }, {
+ .name = "i2c-at91sam9g10",
+ .driver_data = (unsigned long) &at91sam9g10_config,
+ }, {
+ /* sentinel */
+ }
+};
+
+#if defined(CONFIG_OF)
+static struct at91_twi_pdata at91sam9x5_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = false,
+};
+
+static struct at91_twi_pdata sama5d4_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
+ .has_alt_cmd = false,
+ .has_hold_field = true,
+};
+
+static struct at91_twi_pdata sama5d2_config = {
+ .clk_max_div = 7,
+ .clk_offset = 3,
+ .has_unre_flag = true,
+ .has_alt_cmd = true,
+ .has_hold_field = true,
+};
+
+static const struct of_device_id atmel_twi_dt_ids[] = {
+ {
+ .compatible = "atmel,at91rm9200-i2c",
+ .data = &at91rm9200_config,
+ } , {
+ .compatible = "atmel,at91sam9260-i2c",
+ .data = &at91sam9260_config,
+ } , {
+ .compatible = "atmel,at91sam9261-i2c",
+ .data = &at91sam9261_config,
+ } , {
+ .compatible = "atmel,at91sam9g20-i2c",
+ .data = &at91sam9g20_config,
+ } , {
+ .compatible = "atmel,at91sam9g10-i2c",
+ .data = &at91sam9g10_config,
+ }, {
+ .compatible = "atmel,at91sam9x5-i2c",
+ .data = &at91sam9x5_config,
+ }, {
+ .compatible = "atmel,sama5d4-i2c",
+ .data = &sama5d4_config,
+ }, {
+ .compatible = "atmel,sama5d2-i2c",
+ .data = &sama5d2_config,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+#endif
+
+static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
+{
+ int ret = 0;
+ struct dma_slave_config slave_config;
+ struct at91_twi_dma *dma = &dev->dma;
+ enum dma_slave_buswidth addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+
+ /*
+ * The actual width of the access will be chosen in
+ * dmaengine_prep_slave_sg():
+ * for each buffer in the scatter-gather list, if its size is aligned
+ * to addr_width then addr_width accesses will be performed to transfer
+ * the buffer. On the other hand, if the buffer size is not aligned to
+ * addr_width then the buffer is transferred using single byte accesses.
+ * Please refer to the Atmel eXtended DMA controller driver.
+ * When FIFOs are used, the TXRDYM threshold can always be set to
+ * trigger the XDMAC when at least 4 data can be written into the TX
+ * FIFO, even if single byte accesses are performed.
+ * However the RXRDYM threshold must be set to fit the access width,
+ * deduced from buffer length, so the XDMAC is triggered properly to
+ * read data from the RX FIFO.
+ */
+ if (dev->fifo_size)
+ addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ memset(&slave_config, 0, sizeof(slave_config));
+ slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
+ slave_config.src_addr_width = addr_width;
+ slave_config.src_maxburst = 1;
+ slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR;
+ slave_config.dst_addr_width = addr_width;
+ slave_config.dst_maxburst = 1;
+ slave_config.device_fc = false;
+
+ dma->chan_tx = dma_request_slave_channel_reason(dev->dev, "tx");
+ if (IS_ERR(dma->chan_tx)) {
+ ret = PTR_ERR(dma->chan_tx);
+ dma->chan_tx = NULL;
+ goto error;
+ }
+
+ dma->chan_rx = dma_request_slave_channel_reason(dev->dev, "rx");
+ if (IS_ERR(dma->chan_rx)) {
+ ret = PTR_ERR(dma->chan_rx);
+ dma->chan_rx = NULL;
+ goto error;
+ }
+
+ slave_config.direction = DMA_MEM_TO_DEV;
+ if (dmaengine_slave_config(dma->chan_tx, &slave_config)) {
+ dev_err(dev->dev, "failed to configure tx channel\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ slave_config.direction = DMA_DEV_TO_MEM;
+ if (dmaengine_slave_config(dma->chan_rx, &slave_config)) {
+ dev_err(dev->dev, "failed to configure rx channel\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ sg_init_table(dma->sg, 2);
+ dma->buf_mapped = false;
+ dma->xfer_in_progress = false;
+ dev->use_dma = true;
+
+ dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+ return ret;
+
+error:
+ if (ret != -EPROBE_DEFER)
+ dev_info(dev->dev, "can't get DMA channel, continue without DMA support\n");
+ if (dma->chan_rx)
+ dma_release_channel(dma->chan_rx);
+ if (dma->chan_tx)
+ dma_release_channel(dma->chan_tx);
+ return ret;
+}
+
+static struct at91_twi_pdata *at91_twi_get_driver_data(
+ struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
+ if (!match)
+ return NULL;
+ return (struct at91_twi_pdata *)match->data;
+ }
+ return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
+}
+
+static int at91_twi_probe(struct platform_device *pdev)
+{
+ struct at91_twi_dev *dev;
+ struct resource *mem;
+ int rc;
+ u32 phy_addr;
+ u32 bus_clk_rate;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ init_completion(&dev->cmd_complete);
+ dev->dev = &pdev->dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+ phy_addr = mem->start;
+
+ dev->pdata = at91_twi_get_driver_data(pdev);
+ if (!dev->pdata)
+ return -ENODEV;
+
+ dev->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0)
+ return dev->irq;
+
+ rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0,
+ dev_name(dev->dev), dev);
+ if (rc) {
+ dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
+ return rc;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = devm_clk_get(dev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(dev->dev, "no clock defined\n");
+ return -ENODEV;
+ }
+ rc = clk_prepare_enable(dev->clk);
+ if (rc)
+ return rc;
+
+ if (dev->dev->of_node) {
+ rc = at91_twi_configure_dma(dev, phy_addr);
+ if (rc == -EPROBE_DEFER) {
+ clk_disable_unprepare(dev->clk);
+ return rc;
+ }
+ }
+
+ if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size",
+ &dev->fifo_size)) {
+ dev_info(dev->dev, "Using FIFO (%u data)\n", dev->fifo_size);
+ }
+
+ rc = of_property_read_u32(dev->dev->of_node, "clock-frequency",
+ &bus_clk_rate);
+ if (rc)
+ bus_clk_rate = DEFAULT_TWI_CLK_HZ;
+
+ at91_calc_twi_clock(dev, bus_clk_rate);
+ at91_init_twi_bus(dev);
+
+ snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
+ i2c_set_adapdata(&dev->adapter, dev);
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_DEPRECATED;
+ dev->adapter.algo = &at91_twi_algorithm;
+ dev->adapter.quirks = &at91_twi_quirks;
+ dev->adapter.dev.parent = dev->dev;
+ dev->adapter.nr = pdev->id;
+ dev->adapter.timeout = AT91_I2C_TIMEOUT;
+ dev->adapter.dev.of_node = pdev->dev.of_node;
+
+ pm_runtime_set_autosuspend_delay(dev->dev, AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(dev->dev);
+ pm_runtime_set_active(dev->dev);
+ pm_runtime_enable(dev->dev);
+
+ rc = i2c_add_numbered_adapter(&dev->adapter);
+ if (rc) {
+ clk_disable_unprepare(dev->clk);
+
+ pm_runtime_disable(dev->dev);
+ pm_runtime_set_suspended(dev->dev);
+
+ return rc;
+ }
+
+ dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n",
+ at91_twi_read(dev, AT91_TWI_VER));
+ return 0;
+}
+
+static int at91_twi_remove(struct platform_device *pdev)
+{
+ struct at91_twi_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+ clk_disable_unprepare(dev->clk);
+
+ pm_runtime_disable(dev->dev);
+ pm_runtime_set_suspended(dev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int at91_twi_runtime_suspend(struct device *dev)
+{
+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(twi_dev->clk);
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int at91_twi_runtime_resume(struct device *dev)
+{
+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_default_state(dev);
+
+ return clk_prepare_enable(twi_dev->clk);
+}
+
+static int at91_twi_suspend_noirq(struct device *dev)
+{
+ if (!pm_runtime_status_suspended(dev))
+ at91_twi_runtime_suspend(dev);
+
+ return 0;
+}
+
+static int at91_twi_resume_noirq(struct device *dev)
+{
+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
+ int ret;
+
+ if (!pm_runtime_status_suspended(dev)) {
+ ret = at91_twi_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ pm_runtime_mark_last_busy(dev);
+ pm_request_autosuspend(dev);
+
+ at91_init_twi_bus(twi_dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops at91_twi_pm = {
+ .suspend_noirq = at91_twi_suspend_noirq,
+ .resume_noirq = at91_twi_resume_noirq,
+ .runtime_suspend = at91_twi_runtime_suspend,
+ .runtime_resume = at91_twi_runtime_resume,
+};
+
+#define at91_twi_pm_ops (&at91_twi_pm)
+#else
+#define at91_twi_pm_ops NULL
+#endif
+
+static struct platform_driver at91_twi_driver = {
+ .probe = at91_twi_probe,
+ .remove = at91_twi_remove,
+ .id_table = at91_twi_devtypes,
+ .driver = {
+ .name = "at91_i2c",
+ .of_match_table = of_match_ptr(atmel_twi_dt_ids),
+ .pm = at91_twi_pm_ops,
+ },
+};
+
+static int __init at91_twi_init(void)
+{
+ return platform_driver_register(&at91_twi_driver);
+}
+
+static void __exit at91_twi_exit(void)
+{
+ platform_driver_unregister(&at91_twi_driver);
+}
+
+subsys_initcall(at91_twi_init);
+module_exit(at91_twi_exit);
+
+MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
new file mode 100644
index 000000000..5bcb1f0bb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -0,0 +1,401 @@
+/*
+ * i2c-au1550.c: SMBus (i2c) adapter for Alchemy PSC interface
+ * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
+ *
+ * 2.6 port by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * The documentation describes this as an SMBus controller, but it doesn't
+ * understand any of the SMBus protocol in hardware. It's really an I2C
+ * controller that could emulate most of the SMBus in software.
+ *
+ * This is just a skeleton adapter to use with the Au1550 PSC
+ * algorithm. It was developed for the Pb1550, but will work with
+ * any Au1550 board that has a similar PSC configuration.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+#define PSC_SEL 0x00
+#define PSC_CTRL 0x04
+#define PSC_SMBCFG 0x08
+#define PSC_SMBMSK 0x0C
+#define PSC_SMBPCR 0x10
+#define PSC_SMBSTAT 0x14
+#define PSC_SMBEVNT 0x18
+#define PSC_SMBTXRX 0x1C
+#define PSC_SMBTMR 0x20
+
+struct i2c_au1550_data {
+ void __iomem *psc_base;
+ int xfer_timeout;
+ struct i2c_adapter adap;
+};
+
+static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
+{
+ __raw_writel(v, a->psc_base + r);
+ wmb();
+}
+
+static inline unsigned long RD(struct i2c_au1550_data *a, int r)
+{
+ return __raw_readl(a->psc_base + r);
+}
+
+static int wait_xfer_done(struct i2c_au1550_data *adap)
+{
+ int i;
+
+ /* Wait for Tx Buffer Empty */
+ for (i = 0; i < adap->xfer_timeout; i++) {
+ if (RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_TE)
+ return 0;
+
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_au1550_data *adap)
+{
+ unsigned long stat;
+
+ if (wait_xfer_done(adap))
+ return -ETIMEDOUT;
+
+ stat = RD(adap, PSC_SMBEVNT);
+ if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int wait_master_done(struct i2c_au1550_data *adap)
+{
+ int i;
+
+ /* Wait for Master Done. */
+ for (i = 0; i < 2 * adap->xfer_timeout; i++) {
+ if ((RD(adap, PSC_SMBEVNT) & PSC_SMBEVNT_MD) != 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int
+do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
+{
+ unsigned long stat;
+
+ /* Reset the FIFOs, clear events. */
+ stat = RD(adap, PSC_SMBSTAT);
+ WR(adap, PSC_SMBEVNT, PSC_SMBEVNT_ALLCLR);
+
+ if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
+ WR(adap, PSC_SMBPCR, PSC_SMBPCR_DC);
+ while ((RD(adap, PSC_SMBPCR) & PSC_SMBPCR_DC) != 0)
+ cpu_relax();
+ udelay(50);
+ }
+
+ /* Write out the i2c chip address and specify operation */
+ addr <<= 1;
+ if (rd)
+ addr |= 1;
+
+ /* zero-byte xfers stop immediately */
+ if (q)
+ addr |= PSC_SMBTXRX_STP;
+
+ /* Put byte into fifo, start up master. */
+ WR(adap, PSC_SMBTXRX, addr);
+ WR(adap, PSC_SMBPCR, PSC_SMBPCR_MS);
+ if (wait_ack(adap))
+ return -EIO;
+ return (q) ? wait_master_done(adap) : 0;
+}
+
+static int wait_for_rx_byte(struct i2c_au1550_data *adap, unsigned char *out)
+{
+ int j;
+
+ if (wait_xfer_done(adap))
+ return -EIO;
+
+ j = adap->xfer_timeout * 100;
+ do {
+ j--;
+ if (j <= 0)
+ return -EIO;
+
+ if ((RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_RE) == 0)
+ j = 0;
+ else
+ udelay(1);
+ } while (j > 0);
+
+ *out = RD(adap, PSC_SMBTXRX);
+
+ return 0;
+}
+
+static int i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+
+ if (len == 0)
+ return 0;
+
+ /* A read is performed by stuffing the transmit fifo with
+ * zero bytes for timing, waiting for bytes to appear in the
+ * receive fifo, then reading the bytes.
+ */
+ i = 0;
+ while (i < (len - 1)) {
+ WR(adap, PSC_SMBTXRX, 0);
+ if (wait_for_rx_byte(adap, &buf[i]))
+ return -EIO;
+
+ i++;
+ }
+
+ /* The last byte has to indicate transfer done. */
+ WR(adap, PSC_SMBTXRX, PSC_SMBTXRX_STP);
+ if (wait_master_done(adap))
+ return -EIO;
+
+ buf[i] = (unsigned char)(RD(adap, PSC_SMBTXRX) & 0xff);
+ return 0;
+}
+
+static int i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
+ unsigned int len)
+{
+ int i;
+ unsigned long data;
+
+ if (len == 0)
+ return 0;
+
+ i = 0;
+ while (i < (len-1)) {
+ data = buf[i];
+ WR(adap, PSC_SMBTXRX, data);
+ if (wait_ack(adap))
+ return -EIO;
+ i++;
+ }
+
+ /* The last byte has to indicate transfer done. */
+ data = buf[i];
+ data |= PSC_SMBTXRX_STP;
+ WR(adap, PSC_SMBTXRX, data);
+ if (wait_master_done(adap))
+ return -EIO;
+ return 0;
+}
+
+static int
+au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_au1550_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *p;
+ int i, err = 0;
+
+ WR(adap, PSC_CTRL, PSC_CTRL_ENABLE);
+
+ for (i = 0; !err && i < num; i++) {
+ p = &msgs[i];
+ err = do_address(adap, p->addr, p->flags & I2C_M_RD,
+ (p->len == 0));
+ if (err || !p->len)
+ continue;
+ if (p->flags & I2C_M_RD)
+ err = i2c_read(adap, p->buf, p->len);
+ else
+ err = i2c_write(adap, p->buf, p->len);
+ }
+
+ /* Return the number of messages processed, or the error code.
+ */
+ if (err == 0)
+ err = num;
+
+ WR(adap, PSC_CTRL, PSC_CTRL_SUSPEND);
+
+ return err;
+}
+
+static u32 au1550_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm au1550_algo = {
+ .master_xfer = au1550_xfer,
+ .functionality = au1550_func,
+};
+
+static void i2c_au1550_setup(struct i2c_au1550_data *priv)
+{
+ unsigned long cfg;
+
+ WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
+ WR(priv, PSC_SEL, PSC_SEL_PS_SMBUSMODE);
+ WR(priv, PSC_SMBCFG, 0);
+ WR(priv, PSC_CTRL, PSC_CTRL_ENABLE);
+ while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
+ cpu_relax();
+
+ cfg = PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | PSC_SMBCFG_DD_DISABLE;
+ WR(priv, PSC_SMBCFG, cfg);
+
+ /* Divide by 8 to get a 6.25 MHz clock. The later protocol
+ * timings are based on this clock.
+ */
+ cfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
+ WR(priv, PSC_SMBCFG, cfg);
+ WR(priv, PSC_SMBMSK, PSC_SMBMSK_ALLMASK);
+
+ /* Set the protocol timer values. See Table 71 in the
+ * Au1550 Data Book for standard timing values.
+ */
+ WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(20) | \
+ PSC_SMBTMR_SET_PU(20) | PSC_SMBTMR_SET_SH(20) | \
+ PSC_SMBTMR_SET_SU(20) | PSC_SMBTMR_SET_CL(20) | \
+ PSC_SMBTMR_SET_CH(20));
+
+ cfg |= PSC_SMBCFG_DE_ENABLE;
+ WR(priv, PSC_SMBCFG, cfg);
+ while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
+ cpu_relax();
+
+ WR(priv, PSC_CTRL, PSC_CTRL_SUSPEND);
+}
+
+static void i2c_au1550_disable(struct i2c_au1550_data *priv)
+{
+ WR(priv, PSC_SMBCFG, 0);
+ WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ * Prior to calling us, the 50MHz clock frequency and routing
+ * must have been set up for the PSC indicated by the adapter.
+ */
+static int
+i2c_au1550_probe(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv;
+ struct resource *r;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->psc_base))
+ return PTR_ERR(priv->psc_base);
+
+ priv->xfer_timeout = 200;
+
+ priv->adap.nr = pdev->id;
+ priv->adap.algo = &au1550_algo;
+ priv->adap.algo_data = priv;
+ priv->adap.dev.parent = &pdev->dev;
+ strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
+
+ /* Now, set up the PSC for SMBus PIO mode. */
+ i2c_au1550_setup(priv);
+
+ ret = i2c_add_numbered_adapter(&priv->adap);
+ if (ret) {
+ i2c_au1550_disable(priv);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ return 0;
+}
+
+static int i2c_au1550_remove(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ i2c_au1550_disable(priv);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_au1550_suspend(struct device *dev)
+{
+ struct i2c_au1550_data *priv = dev_get_drvdata(dev);
+
+ i2c_au1550_disable(priv);
+
+ return 0;
+}
+
+static int i2c_au1550_resume(struct device *dev)
+{
+ struct i2c_au1550_data *priv = dev_get_drvdata(dev);
+
+ i2c_au1550_setup(priv);
+
+ return 0;
+}
+
+static const struct dev_pm_ops i2c_au1550_pmops = {
+ .suspend = i2c_au1550_suspend,
+ .resume = i2c_au1550_resume,
+};
+
+#define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops)
+
+#else
+#define AU1XPSC_SMBUS_PMOPS NULL
+#endif
+
+static struct platform_driver au1xpsc_smbus_driver = {
+ .driver = {
+ .name = "au1xpsc_smbus",
+ .pm = AU1XPSC_SMBUS_PMOPS,
+ },
+ .probe = i2c_au1550_probe,
+ .remove = i2c_au1550_remove,
+};
+
+module_platform_driver(au1xpsc_smbus_driver);
+
+MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
+MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:au1xpsc_smbus");
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
new file mode 100644
index 000000000..fb5bac079
--- /dev/null
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -0,0 +1,626 @@
+/*
+ * This driver implements I2C master functionality using the LSI API2C
+ * controller.
+ *
+ * NOTE: The controller has a limitation in that it can only do transfers of
+ * maximum 255 bytes at a time. If a larger transfer is attempted, error code
+ * (-EINVAL) is returned.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#define SCL_WAIT_TIMEOUT_NS 25000000
+#define I2C_XFER_TIMEOUT (msecs_to_jiffies(250))
+#define I2C_STOP_TIMEOUT (msecs_to_jiffies(100))
+#define FIFO_SIZE 8
+
+#define GLOBAL_CONTROL 0x00
+#define GLOBAL_MST_EN BIT(0)
+#define GLOBAL_SLV_EN BIT(1)
+#define GLOBAL_IBML_EN BIT(2)
+#define INTERRUPT_STATUS 0x04
+#define INTERRUPT_ENABLE 0x08
+#define INT_SLV BIT(1)
+#define INT_MST BIT(0)
+#define WAIT_TIMER_CONTROL 0x0c
+#define WT_EN BIT(15)
+#define WT_VALUE(_x) ((_x) & 0x7fff)
+#define IBML_TIMEOUT 0x10
+#define IBML_LOW_MEXT 0x14
+#define IBML_LOW_SEXT 0x18
+#define TIMER_CLOCK_DIV 0x1c
+#define I2C_BUS_MONITOR 0x20
+#define BM_SDAC BIT(3)
+#define BM_SCLC BIT(2)
+#define BM_SDAS BIT(1)
+#define BM_SCLS BIT(0)
+#define SOFT_RESET 0x24
+#define MST_COMMAND 0x28
+#define CMD_BUSY (1<<3)
+#define CMD_MANUAL (0x00 | CMD_BUSY)
+#define CMD_AUTO (0x01 | CMD_BUSY)
+#define MST_RX_XFER 0x2c
+#define MST_TX_XFER 0x30
+#define MST_ADDR_1 0x34
+#define MST_ADDR_2 0x38
+#define MST_DATA 0x3c
+#define MST_TX_FIFO 0x40
+#define MST_RX_FIFO 0x44
+#define MST_INT_ENABLE 0x48
+#define MST_INT_STATUS 0x4c
+#define MST_STATUS_RFL (1 << 13) /* RX FIFO serivce */
+#define MST_STATUS_TFL (1 << 12) /* TX FIFO service */
+#define MST_STATUS_SNS (1 << 11) /* Manual mode done */
+#define MST_STATUS_SS (1 << 10) /* Automatic mode done */
+#define MST_STATUS_SCC (1 << 9) /* Stop complete */
+#define MST_STATUS_IP (1 << 8) /* Invalid parameter */
+#define MST_STATUS_TSS (1 << 7) /* Timeout */
+#define MST_STATUS_AL (1 << 6) /* Arbitration lost */
+#define MST_STATUS_ND (1 << 5) /* NAK on data phase */
+#define MST_STATUS_NA (1 << 4) /* NAK on address phase */
+#define MST_STATUS_NAK (MST_STATUS_NA | \
+ MST_STATUS_ND)
+#define MST_STATUS_ERR (MST_STATUS_NAK | \
+ MST_STATUS_AL | \
+ MST_STATUS_IP)
+#define MST_TX_BYTES_XFRD 0x50
+#define MST_RX_BYTES_XFRD 0x54
+#define SCL_HIGH_PERIOD 0x80
+#define SCL_LOW_PERIOD 0x84
+#define SPIKE_FLTR_LEN 0x88
+#define SDA_SETUP_TIME 0x8c
+#define SDA_HOLD_TIME 0x90
+
+/**
+ * axxia_i2c_dev - I2C device context
+ * @base: pointer to register struct
+ * @msg: pointer to current message
+ * @msg_xfrd: number of bytes transferred in msg
+ * @msg_err: error code for completed message
+ * @msg_complete: xfer completion object
+ * @dev: device reference
+ * @adapter: core i2c abstraction
+ * @i2c_clk: clock reference for i2c input clock
+ * @bus_clk_rate: current i2c bus clock rate
+ */
+struct axxia_i2c_dev {
+ void __iomem *base;
+ struct i2c_msg *msg;
+ size_t msg_xfrd;
+ int msg_err;
+ struct completion msg_complete;
+ struct device *dev;
+ struct i2c_adapter adapter;
+ struct clk *i2c_clk;
+ u32 bus_clk_rate;
+};
+
+static void i2c_int_disable(struct axxia_i2c_dev *idev, u32 mask)
+{
+ u32 int_en;
+
+ int_en = readl(idev->base + MST_INT_ENABLE);
+ writel(int_en & ~mask, idev->base + MST_INT_ENABLE);
+}
+
+static void i2c_int_enable(struct axxia_i2c_dev *idev, u32 mask)
+{
+ u32 int_en;
+
+ int_en = readl(idev->base + MST_INT_ENABLE);
+ writel(int_en | mask, idev->base + MST_INT_ENABLE);
+}
+
+/**
+ * ns_to_clk - Convert time (ns) to clock cycles for the given clock frequency.
+ */
+static u32 ns_to_clk(u64 ns, u32 clk_mhz)
+{
+ return div_u64(ns * clk_mhz, 1000);
+}
+
+static int axxia_i2c_init(struct axxia_i2c_dev *idev)
+{
+ u32 divisor = clk_get_rate(idev->i2c_clk) / idev->bus_clk_rate;
+ u32 clk_mhz = clk_get_rate(idev->i2c_clk) / 1000000;
+ u32 t_setup;
+ u32 t_high, t_low;
+ u32 tmo_clk;
+ u32 prescale;
+ unsigned long timeout;
+
+ dev_dbg(idev->dev, "rate=%uHz per_clk=%uMHz -> ratio=1:%u\n",
+ idev->bus_clk_rate, clk_mhz, divisor);
+
+ /* Reset controller */
+ writel(0x01, idev->base + SOFT_RESET);
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (readl(idev->base + SOFT_RESET) & 1) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(idev->dev, "Soft reset failed\n");
+ break;
+ }
+ }
+
+ /* Enable Master Mode */
+ writel(0x1, idev->base + GLOBAL_CONTROL);
+
+ if (idev->bus_clk_rate <= 100000) {
+ /* Standard mode SCL 50/50, tSU:DAT = 250 ns */
+ t_high = divisor * 1 / 2;
+ t_low = divisor * 1 / 2;
+ t_setup = ns_to_clk(250, clk_mhz);
+ } else {
+ /* Fast mode SCL 33/66, tSU:DAT = 100 ns */
+ t_high = divisor * 1 / 3;
+ t_low = divisor * 2 / 3;
+ t_setup = ns_to_clk(100, clk_mhz);
+ }
+
+ /* SCL High Time */
+ writel(t_high, idev->base + SCL_HIGH_PERIOD);
+ /* SCL Low Time */
+ writel(t_low, idev->base + SCL_LOW_PERIOD);
+ /* SDA Setup Time */
+ writel(t_setup, idev->base + SDA_SETUP_TIME);
+ /* SDA Hold Time, 300ns */
+ writel(ns_to_clk(300, clk_mhz), idev->base + SDA_HOLD_TIME);
+ /* Filter <50ns spikes */
+ writel(ns_to_clk(50, clk_mhz), idev->base + SPIKE_FLTR_LEN);
+
+ /* Configure Time-Out Registers */
+ tmo_clk = ns_to_clk(SCL_WAIT_TIMEOUT_NS, clk_mhz);
+
+ /* Find prescaler value that makes tmo_clk fit in 15-bits counter. */
+ for (prescale = 0; prescale < 15; ++prescale) {
+ if (tmo_clk <= 0x7fff)
+ break;
+ tmo_clk >>= 1;
+ }
+ if (tmo_clk > 0x7fff)
+ tmo_clk = 0x7fff;
+
+ /* Prescale divider (log2) */
+ writel(prescale, idev->base + TIMER_CLOCK_DIV);
+ /* Timeout in divided clocks */
+ writel(WT_EN | WT_VALUE(tmo_clk), idev->base + WAIT_TIMER_CONTROL);
+
+ /* Mask all master interrupt bits */
+ i2c_int_disable(idev, ~0);
+
+ /* Interrupt enable */
+ writel(0x01, idev->base + INTERRUPT_ENABLE);
+
+ return 0;
+}
+
+static int i2c_m_rd(const struct i2c_msg *msg)
+{
+ return (msg->flags & I2C_M_RD) != 0;
+}
+
+static int i2c_m_ten(const struct i2c_msg *msg)
+{
+ return (msg->flags & I2C_M_TEN) != 0;
+}
+
+static int i2c_m_recv_len(const struct i2c_msg *msg)
+{
+ return (msg->flags & I2C_M_RECV_LEN) != 0;
+}
+
+/**
+ * axxia_i2c_empty_rx_fifo - Fetch data from RX FIFO and update SMBus block
+ * transfer length if this is the first byte of such a transfer.
+ */
+static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
+{
+ struct i2c_msg *msg = idev->msg;
+ size_t rx_fifo_avail = readl(idev->base + MST_RX_FIFO);
+ int bytes_to_transfer = min(rx_fifo_avail, msg->len - idev->msg_xfrd);
+
+ while (bytes_to_transfer-- > 0) {
+ int c = readl(idev->base + MST_DATA);
+
+ if (idev->msg_xfrd == 0 && i2c_m_recv_len(msg)) {
+ /*
+ * Check length byte for SMBus block read
+ */
+ if (c <= 0 || c > I2C_SMBUS_BLOCK_MAX) {
+ idev->msg_err = -EPROTO;
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ complete(&idev->msg_complete);
+ break;
+ }
+ msg->len = 1 + c;
+ writel(msg->len, idev->base + MST_RX_XFER);
+ }
+ msg->buf[idev->msg_xfrd++] = c;
+ }
+
+ return 0;
+}
+
+/**
+ * axxia_i2c_fill_tx_fifo - Fill TX FIFO from current message buffer.
+ * @return: Number of bytes left to transfer.
+ */
+static int axxia_i2c_fill_tx_fifo(struct axxia_i2c_dev *idev)
+{
+ struct i2c_msg *msg = idev->msg;
+ size_t tx_fifo_avail = FIFO_SIZE - readl(idev->base + MST_TX_FIFO);
+ int bytes_to_transfer = min(tx_fifo_avail, msg->len - idev->msg_xfrd);
+ int ret = msg->len - idev->msg_xfrd - bytes_to_transfer;
+
+ while (bytes_to_transfer-- > 0)
+ writel(msg->buf[idev->msg_xfrd++], idev->base + MST_DATA);
+
+ return ret;
+}
+
+static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
+{
+ struct axxia_i2c_dev *idev = _dev;
+ u32 status;
+
+ if (!(readl(idev->base + INTERRUPT_STATUS) & INT_MST))
+ return IRQ_NONE;
+
+ /* Read interrupt status bits */
+ status = readl(idev->base + MST_INT_STATUS);
+
+ if (!idev->msg) {
+ dev_warn(idev->dev, "unexpected interrupt\n");
+ goto out;
+ }
+
+ /* RX FIFO needs service? */
+ if (i2c_m_rd(idev->msg) && (status & MST_STATUS_RFL))
+ axxia_i2c_empty_rx_fifo(idev);
+
+ /* TX FIFO needs service? */
+ if (!i2c_m_rd(idev->msg) && (status & MST_STATUS_TFL)) {
+ if (axxia_i2c_fill_tx_fifo(idev) == 0)
+ i2c_int_disable(idev, MST_STATUS_TFL);
+ }
+
+ if (unlikely(status & MST_STATUS_ERR)) {
+ /* Transfer error */
+ i2c_int_disable(idev, ~0);
+ if (status & MST_STATUS_AL)
+ idev->msg_err = -EAGAIN;
+ else if (status & MST_STATUS_NAK)
+ idev->msg_err = -ENXIO;
+ else
+ idev->msg_err = -EIO;
+ dev_dbg(idev->dev, "error %#x, addr=%#x rx=%u/%u tx=%u/%u\n",
+ status,
+ idev->msg->addr,
+ readl(idev->base + MST_RX_BYTES_XFRD),
+ readl(idev->base + MST_RX_XFER),
+ readl(idev->base + MST_TX_BYTES_XFRD),
+ readl(idev->base + MST_TX_XFER));
+ complete(&idev->msg_complete);
+ } else if (status & MST_STATUS_SCC) {
+ /* Stop completed */
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ complete(&idev->msg_complete);
+ } else if (status & MST_STATUS_SNS) {
+ /* Transfer done */
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
+ axxia_i2c_empty_rx_fifo(idev);
+ complete(&idev->msg_complete);
+ } else if (status & MST_STATUS_TSS) {
+ /* Transfer timeout */
+ idev->msg_err = -ETIMEDOUT;
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ complete(&idev->msg_complete);
+ }
+
+out:
+ /* Clear interrupt */
+ writel(INT_MST, idev->base + INTERRUPT_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
+{
+ u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
+ u32 rx_xfer, tx_xfer;
+ u32 addr_1, addr_2;
+ unsigned long time_left;
+ unsigned int wt_value;
+
+ idev->msg = msg;
+ idev->msg_xfrd = 0;
+ reinit_completion(&idev->msg_complete);
+
+ if (i2c_m_ten(msg)) {
+ /* 10-bit address
+ * addr_1: 5'b11110 | addr[9:8] | (R/nW)
+ * addr_2: addr[7:0]
+ */
+ addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06);
+ if (i2c_m_rd(msg))
+ addr_1 |= 1; /* Set the R/nW bit of the address */
+ addr_2 = msg->addr & 0xFF;
+ } else {
+ /* 7-bit address
+ * addr_1: addr[6:0] | (R/nW)
+ * addr_2: dont care
+ */
+ addr_1 = i2c_8bit_addr_from_msg(msg);
+ addr_2 = 0;
+ }
+
+ if (i2c_m_rd(msg)) {
+ /* I2C read transfer */
+ rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len;
+ tx_xfer = 0;
+ } else {
+ /* I2C write transfer */
+ rx_xfer = 0;
+ tx_xfer = msg->len;
+ }
+
+ writel(rx_xfer, idev->base + MST_RX_XFER);
+ writel(tx_xfer, idev->base + MST_TX_XFER);
+ writel(addr_1, idev->base + MST_ADDR_1);
+ writel(addr_2, idev->base + MST_ADDR_2);
+
+ if (i2c_m_rd(msg))
+ int_mask |= MST_STATUS_RFL;
+ else if (axxia_i2c_fill_tx_fifo(idev) != 0)
+ int_mask |= MST_STATUS_TFL;
+
+ wt_value = WT_VALUE(readl(idev->base + WAIT_TIMER_CONTROL));
+ /* Disable wait timer temporarly */
+ writel(wt_value, idev->base + WAIT_TIMER_CONTROL);
+ /* Check if timeout error happened */
+ if (idev->msg_err)
+ goto out;
+
+ /* Start manual mode */
+ writel(CMD_MANUAL, idev->base + MST_COMMAND);
+
+ writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL);
+
+ i2c_int_enable(idev, int_mask);
+
+ time_left = wait_for_completion_timeout(&idev->msg_complete,
+ I2C_XFER_TIMEOUT);
+
+ i2c_int_disable(idev, int_mask);
+
+ if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
+ dev_warn(idev->dev, "busy after xfer\n");
+
+ if (time_left == 0) {
+ idev->msg_err = -ETIMEDOUT;
+ i2c_recover_bus(&idev->adapter);
+ axxia_i2c_init(idev);
+ }
+
+out:
+ if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO &&
+ idev->msg_err != -ETIMEDOUT)
+ axxia_i2c_init(idev);
+
+ return idev->msg_err;
+}
+
+static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
+{
+ u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC | MST_STATUS_TSS;
+ unsigned long time_left;
+
+ reinit_completion(&idev->msg_complete);
+
+ /* Issue stop */
+ writel(0xb, idev->base + MST_COMMAND);
+ i2c_int_enable(idev, int_mask);
+ time_left = wait_for_completion_timeout(&idev->msg_complete,
+ I2C_STOP_TIMEOUT);
+ i2c_int_disable(idev, int_mask);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
+ dev_warn(idev->dev, "busy after stop\n");
+
+ return 0;
+}
+
+static int
+axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+ int i;
+ int ret = 0;
+
+ idev->msg_err = 0;
+ i2c_int_enable(idev, MST_STATUS_TSS);
+
+ for (i = 0; ret == 0 && i < num; ++i)
+ ret = axxia_i2c_xfer_msg(idev, &msgs[i]);
+
+ axxia_i2c_stop(idev);
+
+ return ret ? : i;
+}
+
+static int axxia_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+
+ return !!(readl(idev->base + I2C_BUS_MONITOR) & BM_SCLS);
+}
+
+static void axxia_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+ u32 tmp;
+
+ /* Preserve SDA Control */
+ tmp = readl(idev->base + I2C_BUS_MONITOR) & BM_SDAC;
+ if (!val)
+ tmp |= BM_SCLC;
+ writel(tmp, idev->base + I2C_BUS_MONITOR);
+}
+
+static int axxia_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+
+ return !!(readl(idev->base + I2C_BUS_MONITOR) & BM_SDAS);
+}
+
+static struct i2c_bus_recovery_info axxia_i2c_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = axxia_i2c_get_scl,
+ .set_scl = axxia_i2c_set_scl,
+ .get_sda = axxia_i2c_get_sda,
+};
+
+static u32 axxia_i2c_func(struct i2c_adapter *adap)
+{
+ u32 caps = (I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA);
+ return caps;
+}
+
+static const struct i2c_algorithm axxia_i2c_algo = {
+ .master_xfer = axxia_i2c_xfer,
+ .functionality = axxia_i2c_func,
+};
+
+static const struct i2c_adapter_quirks axxia_i2c_quirks = {
+ .max_read_len = 255,
+ .max_write_len = 255,
+};
+
+static int axxia_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct axxia_i2c_dev *idev = NULL;
+ struct resource *res;
+ void __iomem *base;
+ int irq;
+ int ret = 0;
+
+ idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
+ if (!idev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "missing interrupt resource\n");
+ return irq;
+ }
+
+ idev->i2c_clk = devm_clk_get(&pdev->dev, "i2c");
+ if (IS_ERR(idev->i2c_clk)) {
+ dev_err(&pdev->dev, "missing clock\n");
+ return PTR_ERR(idev->i2c_clk);
+ }
+
+ idev->base = base;
+ idev->dev = &pdev->dev;
+ init_completion(&idev->msg_complete);
+
+ of_property_read_u32(np, "clock-frequency", &idev->bus_clk_rate);
+ if (idev->bus_clk_rate == 0)
+ idev->bus_clk_rate = 100000; /* default clock rate */
+
+ ret = clk_prepare_enable(idev->i2c_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ ret = axxia_i2c_init(idev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize\n");
+ goto error_disable_clk;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, axxia_i2c_isr, 0,
+ pdev->name, idev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim IRQ%d\n", irq);
+ goto error_disable_clk;
+ }
+
+ i2c_set_adapdata(&idev->adapter, idev);
+ strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
+ idev->adapter.owner = THIS_MODULE;
+ idev->adapter.algo = &axxia_i2c_algo;
+ idev->adapter.bus_recovery_info = &axxia_i2c_recovery_info;
+ idev->adapter.quirks = &axxia_i2c_quirks;
+ idev->adapter.dev.parent = &pdev->dev;
+ idev->adapter.dev.of_node = pdev->dev.of_node;
+
+ platform_set_drvdata(pdev, idev);
+
+ ret = i2c_add_adapter(&idev->adapter);
+ if (ret)
+ goto error_disable_clk;
+
+ return 0;
+
+error_disable_clk:
+ clk_disable_unprepare(idev->i2c_clk);
+ return ret;
+}
+
+static int axxia_i2c_remove(struct platform_device *pdev)
+{
+ struct axxia_i2c_dev *idev = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(idev->i2c_clk);
+ i2c_del_adapter(&idev->adapter);
+
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id axxia_i2c_of_match[] = {
+ { .compatible = "lsi,api2c", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, axxia_i2c_of_match);
+
+static struct platform_driver axxia_i2c_driver = {
+ .probe = axxia_i2c_probe,
+ .remove = axxia_i2c_remove,
+ .driver = {
+ .name = "axxia-i2c",
+ .of_match_table = axxia_i2c_of_match,
+ },
+};
+
+module_platform_driver(axxia_i2c_driver);
+
+MODULE_DESCRIPTION("Axxia I2C Bus driver");
+MODULE_AUTHOR("Anders Berg <anders.berg@lsi.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
new file mode 100644
index 000000000..4c8c3bc46
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -0,0 +1,580 @@
+/*
+ * Copyright (C) 2014 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define CFG_OFFSET 0x00
+#define CFG_RESET_SHIFT 31
+#define CFG_EN_SHIFT 30
+#define CFG_M_RETRY_CNT_SHIFT 16
+#define CFG_M_RETRY_CNT_MASK 0x0f
+
+#define TIM_CFG_OFFSET 0x04
+#define TIM_CFG_MODE_400_SHIFT 31
+
+#define M_FIFO_CTRL_OFFSET 0x0c
+#define M_FIFO_RX_FLUSH_SHIFT 31
+#define M_FIFO_TX_FLUSH_SHIFT 30
+#define M_FIFO_RX_CNT_SHIFT 16
+#define M_FIFO_RX_CNT_MASK 0x7f
+#define M_FIFO_RX_THLD_SHIFT 8
+#define M_FIFO_RX_THLD_MASK 0x3f
+
+#define M_CMD_OFFSET 0x30
+#define M_CMD_START_BUSY_SHIFT 31
+#define M_CMD_STATUS_SHIFT 25
+#define M_CMD_STATUS_MASK 0x07
+#define M_CMD_STATUS_SUCCESS 0x0
+#define M_CMD_STATUS_LOST_ARB 0x1
+#define M_CMD_STATUS_NACK_ADDR 0x2
+#define M_CMD_STATUS_NACK_DATA 0x3
+#define M_CMD_STATUS_TIMEOUT 0x4
+#define M_CMD_PROTOCOL_SHIFT 9
+#define M_CMD_PROTOCOL_MASK 0xf
+#define M_CMD_PROTOCOL_BLK_WR 0x7
+#define M_CMD_PROTOCOL_BLK_RD 0x8
+#define M_CMD_PEC_SHIFT 8
+#define M_CMD_RD_CNT_SHIFT 0
+#define M_CMD_RD_CNT_MASK 0xff
+
+#define IE_OFFSET 0x38
+#define IE_M_RX_FIFO_FULL_SHIFT 31
+#define IE_M_RX_THLD_SHIFT 30
+#define IE_M_START_BUSY_SHIFT 28
+#define IE_M_TX_UNDERRUN_SHIFT 27
+
+#define IS_OFFSET 0x3c
+#define IS_M_RX_FIFO_FULL_SHIFT 31
+#define IS_M_RX_THLD_SHIFT 30
+#define IS_M_START_BUSY_SHIFT 28
+#define IS_M_TX_UNDERRUN_SHIFT 27
+
+#define M_TX_OFFSET 0x40
+#define M_TX_WR_STATUS_SHIFT 31
+#define M_TX_DATA_SHIFT 0
+#define M_TX_DATA_MASK 0xff
+
+#define M_RX_OFFSET 0x44
+#define M_RX_STATUS_SHIFT 30
+#define M_RX_STATUS_MASK 0x03
+#define M_RX_PEC_ERR_SHIFT 29
+#define M_RX_DATA_SHIFT 0
+#define M_RX_DATA_MASK 0xff
+
+#define I2C_TIMEOUT_MSEC 50000
+#define M_TX_RX_FIFO_SIZE 64
+
+enum bus_speed_index {
+ I2C_SPD_100K = 0,
+ I2C_SPD_400K,
+};
+
+struct bcm_iproc_i2c_dev {
+ struct device *device;
+ int irq;
+
+ void __iomem *base;
+
+ struct i2c_adapter adapter;
+ unsigned int bus_speed;
+
+ struct completion done;
+ int xfer_is_done;
+
+ struct i2c_msg *msg;
+
+ /* bytes that have been transferred */
+ unsigned int tx_bytes;
+};
+
+/*
+ * Can be expanded in the future if more interrupt status bits are utilized
+ */
+#define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT))
+
+static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = data;
+ u32 status = readl(iproc_i2c->base + IS_OFFSET);
+
+ status &= ISR_MASK;
+
+ if (!status)
+ return IRQ_NONE;
+
+ /* TX FIFO is empty and we have more data to send */
+ if (status & BIT(IS_M_TX_UNDERRUN_SHIFT)) {
+ struct i2c_msg *msg = iproc_i2c->msg;
+ unsigned int tx_bytes = msg->len - iproc_i2c->tx_bytes;
+ unsigned int i;
+ u32 val;
+
+ /* can only fill up to the FIFO size */
+ tx_bytes = min_t(unsigned int, tx_bytes, M_TX_RX_FIFO_SIZE);
+ for (i = 0; i < tx_bytes; i++) {
+ /* start from where we left over */
+ unsigned int idx = iproc_i2c->tx_bytes + i;
+
+ val = msg->buf[idx];
+
+ /* mark the last byte */
+ if (idx == msg->len - 1) {
+ u32 tmp;
+
+ val |= BIT(M_TX_WR_STATUS_SHIFT);
+
+ /*
+ * Since this is the last byte, we should
+ * now disable TX FIFO underrun interrupt
+ */
+ tmp = readl(iproc_i2c->base + IE_OFFSET);
+ tmp &= ~BIT(IE_M_TX_UNDERRUN_SHIFT);
+ writel(tmp, iproc_i2c->base + IE_OFFSET);
+ }
+
+ /* load data into TX FIFO */
+ writel(val, iproc_i2c->base + M_TX_OFFSET);
+ }
+ /* update number of transferred bytes */
+ iproc_i2c->tx_bytes += tx_bytes;
+ }
+
+ if (status & BIT(IS_M_START_BUSY_SHIFT)) {
+ iproc_i2c->xfer_is_done = 1;
+ complete(&iproc_i2c->done);
+ }
+
+ writel(status, iproc_i2c->base + IS_OFFSET);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+ u32 val;
+
+ /* put controller in reset */
+ val = readl(iproc_i2c->base + CFG_OFFSET);
+ val |= 1 << CFG_RESET_SHIFT;
+ val &= ~(1 << CFG_EN_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+
+ /* wait 100 usec per spec */
+ udelay(100);
+
+ /* bring controller out of reset */
+ val &= ~(1 << CFG_RESET_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+
+ /* flush TX/RX FIFOs and set RX FIFO threshold to zero */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ /* disable all interrupts */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+
+ /* clear all pending interrupts */
+ writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
+
+ return 0;
+}
+
+static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
+ bool enable)
+{
+ u32 val;
+
+ val = readl(iproc_i2c->base + CFG_OFFSET);
+ if (enable)
+ val |= BIT(CFG_EN_SHIFT);
+ else
+ val &= ~BIT(CFG_EN_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+}
+
+static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
+ struct i2c_msg *msg)
+{
+ u32 val;
+
+ val = readl(iproc_i2c->base + M_CMD_OFFSET);
+ val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
+
+ switch (val) {
+ case M_CMD_STATUS_SUCCESS:
+ return 0;
+
+ case M_CMD_STATUS_LOST_ARB:
+ dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
+ return -EAGAIN;
+
+ case M_CMD_STATUS_NACK_ADDR:
+ dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
+ return -ENXIO;
+
+ case M_CMD_STATUS_NACK_DATA:
+ dev_dbg(iproc_i2c->device, "NAK data\n");
+ return -ENXIO;
+
+ case M_CMD_STATUS_TIMEOUT:
+ dev_dbg(iproc_i2c->device, "bus timeout\n");
+ return -ETIMEDOUT;
+
+ default:
+ dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
+
+ /* re-initialize i2c for recovery */
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+ bcm_iproc_i2c_init(iproc_i2c);
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+
+ return -EIO;
+ }
+}
+
+static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
+ struct i2c_msg *msg)
+{
+ int ret, i;
+ u8 addr;
+ u32 val;
+ unsigned int tx_bytes;
+ unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MSEC);
+
+ /* check if bus is busy */
+ if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
+ BIT(M_CMD_START_BUSY_SHIFT))) {
+ dev_warn(iproc_i2c->device, "bus is busy\n");
+ return -EBUSY;
+ }
+
+ iproc_i2c->msg = msg;
+
+ /* format and load slave address into the TX FIFO */
+ addr = i2c_8bit_addr_from_msg(msg);
+ writel(addr, iproc_i2c->base + M_TX_OFFSET);
+
+ /*
+ * For a write transaction, load data into the TX FIFO. Only allow
+ * loading up to TX FIFO size - 1 bytes of data since the first byte
+ * has been used up by the slave address
+ */
+ tx_bytes = min_t(unsigned int, msg->len, M_TX_RX_FIFO_SIZE - 1);
+ if (!(msg->flags & I2C_M_RD)) {
+ for (i = 0; i < tx_bytes; i++) {
+ val = msg->buf[i];
+
+ /* mark the last byte */
+ if (i == msg->len - 1)
+ val |= 1 << M_TX_WR_STATUS_SHIFT;
+
+ writel(val, iproc_i2c->base + M_TX_OFFSET);
+ }
+ iproc_i2c->tx_bytes = tx_bytes;
+ }
+
+ /* mark as incomplete before starting the transaction */
+ reinit_completion(&iproc_i2c->done);
+ iproc_i2c->xfer_is_done = 0;
+
+ /*
+ * Enable the "start busy" interrupt, which will be triggered after the
+ * transaction is done, i.e., the internal start_busy bit, transitions
+ * from 1 to 0.
+ */
+ val = BIT(IE_M_START_BUSY_SHIFT);
+
+ /*
+ * If TX data size is larger than the TX FIFO, need to enable TX
+ * underrun interrupt, which will be triggerred when the TX FIFO is
+ * empty. When that happens we can then pump more data into the FIFO
+ */
+ if (!(msg->flags & I2C_M_RD) &&
+ msg->len > iproc_i2c->tx_bytes)
+ val |= BIT(IE_M_TX_UNDERRUN_SHIFT);
+
+ writel(val, iproc_i2c->base + IE_OFFSET);
+
+ /*
+ * Now we can activate the transfer. For a read operation, specify the
+ * number of bytes to read
+ */
+ val = BIT(M_CMD_START_BUSY_SHIFT);
+ if (msg->flags & I2C_M_RD) {
+ val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
+ (msg->len << M_CMD_RD_CNT_SHIFT);
+ } else {
+ val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
+ }
+ writel(val, iproc_i2c->base + M_CMD_OFFSET);
+
+ time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
+
+ /* disable all interrupts */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ /* read it back to flush the write */
+ readl(iproc_i2c->base + IE_OFFSET);
+
+ /* make sure the interrupt handler isn't running */
+ synchronize_irq(iproc_i2c->irq);
+
+ if (!time_left && !iproc_i2c->xfer_is_done) {
+ dev_err(iproc_i2c->device, "transaction timed out\n");
+
+ /* flush FIFOs */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+ (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ return -ETIMEDOUT;
+ }
+
+ ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
+ if (ret) {
+ /* flush both TX/RX FIFOs */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+ (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ return ret;
+ }
+
+ /*
+ * For a read operation, we now need to load the data from FIFO
+ * into the memory buffer
+ */
+ if (msg->flags & I2C_M_RD) {
+ for (i = 0; i < msg->len; i++) {
+ msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
+ M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
+ }
+ }
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
+ int ret, i;
+
+ /* go through all messages */
+ for (i = 0; i < num; i++) {
+ ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
+ if (ret) {
+ dev_dbg(iproc_i2c->device, "xfer failed\n");
+ return ret;
+ }
+ }
+
+ return num;
+}
+
+static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm bcm_iproc_algo = {
+ .master_xfer = bcm_iproc_i2c_xfer,
+ .functionality = bcm_iproc_i2c_functionality,
+};
+
+static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
+ /* need to reserve one byte in the FIFO for the slave address */
+ .max_read_len = M_TX_RX_FIFO_SIZE - 1,
+};
+
+static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+ unsigned int bus_speed;
+ u32 val;
+ int ret = of_property_read_u32(iproc_i2c->device->of_node,
+ "clock-frequency", &bus_speed);
+ if (ret < 0) {
+ dev_info(iproc_i2c->device,
+ "unable to interpret clock-frequency DT property\n");
+ bus_speed = 100000;
+ }
+
+ if (bus_speed < 100000) {
+ dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
+ bus_speed);
+ dev_err(iproc_i2c->device,
+ "valid speeds are 100khz and 400khz\n");
+ return -EINVAL;
+ } else if (bus_speed < 400000) {
+ bus_speed = 100000;
+ } else {
+ bus_speed = 400000;
+ }
+
+ iproc_i2c->bus_speed = bus_speed;
+ val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
+ val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
+ val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
+ writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
+
+ dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_probe(struct platform_device *pdev)
+{
+ int irq, ret = 0;
+ struct bcm_iproc_i2c_dev *iproc_i2c;
+ struct i2c_adapter *adap;
+ struct resource *res;
+
+ iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
+ GFP_KERNEL);
+ if (!iproc_i2c)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, iproc_i2c);
+ iproc_i2c->device = &pdev->dev;
+ init_completion(&iproc_i2c->done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res);
+ if (IS_ERR(iproc_i2c->base))
+ return PTR_ERR(iproc_i2c->base);
+
+ ret = bcm_iproc_i2c_init(iproc_i2c);
+ if (ret)
+ return ret;
+
+ ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
+ if (ret)
+ return ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(iproc_i2c->device, "no irq resource\n");
+ return irq;
+ }
+ iproc_i2c->irq = irq;
+
+ ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0,
+ pdev->name, iproc_i2c);
+ if (ret < 0) {
+ dev_err(iproc_i2c->device, "unable to request irq %i\n", irq);
+ return ret;
+ }
+
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+
+ adap = &iproc_i2c->adapter;
+ i2c_set_adapdata(adap, iproc_i2c);
+ strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
+ adap->algo = &bcm_iproc_algo;
+ adap->quirks = &bcm_iproc_i2c_quirks;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ return i2c_add_adapter(adap);
+}
+
+static int bcm_iproc_i2c_remove(struct platform_device *pdev)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
+
+ /* make sure there's no pending interrupt when we remove the adapter */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ readl(iproc_i2c->base + IE_OFFSET);
+ synchronize_irq(iproc_i2c->irq);
+
+ i2c_del_adapter(&iproc_i2c->adapter);
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int bcm_iproc_i2c_suspend(struct device *dev)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
+
+ /* make sure there's no pending interrupt when we go into suspend */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ readl(iproc_i2c->base + IE_OFFSET);
+ synchronize_irq(iproc_i2c->irq);
+
+ /* now disable the controller */
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_resume(struct device *dev)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
+ int ret;
+ u32 val;
+
+ /*
+ * Power domain could have been shut off completely in system deep
+ * sleep, so re-initialize the block here
+ */
+ ret = bcm_iproc_i2c_init(iproc_i2c);
+ if (ret)
+ return ret;
+
+ /* configure to the desired bus speed */
+ val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
+ val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
+ val |= (iproc_i2c->bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
+ writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
+
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+
+ return 0;
+}
+
+static const struct dev_pm_ops bcm_iproc_i2c_pm_ops = {
+ .suspend_late = &bcm_iproc_i2c_suspend,
+ .resume_early = &bcm_iproc_i2c_resume
+};
+
+#define BCM_IPROC_I2C_PM_OPS (&bcm_iproc_i2c_pm_ops)
+#else
+#define BCM_IPROC_I2C_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct of_device_id bcm_iproc_i2c_of_match[] = {
+ { .compatible = "brcm,iproc-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
+
+static struct platform_driver bcm_iproc_i2c_driver = {
+ .driver = {
+ .name = "bcm-iproc-i2c",
+ .of_match_table = bcm_iproc_i2c_of_match,
+ .pm = BCM_IPROC_I2C_PM_OPS,
+ },
+ .probe = bcm_iproc_i2c_probe,
+ .remove = bcm_iproc_i2c_remove,
+};
+module_platform_driver(bcm_iproc_i2c_driver);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
new file mode 100644
index 000000000..4e489a9d1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -0,0 +1,902 @@
+/*
+ * 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/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(&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 = i2c_8bit_addr_from_msg(msg);
+
+ 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)
+ 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, bcm_kona_i2c_of_match);
+
+static struct platform_driver bcm_kona_i2c_driver = {
+ .driver = {
+ .name = "bcm-kona-i2c",
+ .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");
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
new file mode 100644
index 000000000..db1ab9ccc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -0,0 +1,450 @@
+/*
+ * BCM2835 master mode driver
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define BCM2835_I2C_C 0x0
+#define BCM2835_I2C_S 0x4
+#define BCM2835_I2C_DLEN 0x8
+#define BCM2835_I2C_A 0xc
+#define BCM2835_I2C_FIFO 0x10
+#define BCM2835_I2C_DIV 0x14
+#define BCM2835_I2C_DEL 0x18
+/*
+ * 16-bit field for the number of SCL cycles to wait after rising SCL
+ * before deciding the slave is not responding. 0 disables the
+ * timeout detection.
+ */
+#define BCM2835_I2C_CLKT 0x1c
+
+#define BCM2835_I2C_C_READ BIT(0)
+#define BCM2835_I2C_C_CLEAR BIT(4) /* bits 4 and 5 both clear */
+#define BCM2835_I2C_C_ST BIT(7)
+#define BCM2835_I2C_C_INTD BIT(8)
+#define BCM2835_I2C_C_INTT BIT(9)
+#define BCM2835_I2C_C_INTR BIT(10)
+#define BCM2835_I2C_C_I2CEN BIT(15)
+
+#define BCM2835_I2C_S_TA BIT(0)
+#define BCM2835_I2C_S_DONE BIT(1)
+#define BCM2835_I2C_S_TXW BIT(2)
+#define BCM2835_I2C_S_RXR BIT(3)
+#define BCM2835_I2C_S_TXD BIT(4)
+#define BCM2835_I2C_S_RXD BIT(5)
+#define BCM2835_I2C_S_TXE BIT(6)
+#define BCM2835_I2C_S_RXF BIT(7)
+#define BCM2835_I2C_S_ERR BIT(8)
+#define BCM2835_I2C_S_CLKT BIT(9)
+#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */
+
+#define BCM2835_I2C_FEDL_SHIFT 16
+#define BCM2835_I2C_REDL_SHIFT 0
+
+#define BCM2835_I2C_CDIV_MIN 0x0002
+#define BCM2835_I2C_CDIV_MAX 0xFFFE
+
+struct bcm2835_i2c_dev {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+ int irq;
+ u32 bus_clk_rate;
+ struct i2c_adapter adapter;
+ struct completion completion;
+ struct i2c_msg *curr_msg;
+ int num_msgs;
+ u32 msg_err;
+ u8 *msg_buf;
+ size_t msg_buf_remaining;
+};
+
+static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
+ u32 reg, u32 val)
+{
+ writel(val, i2c_dev->regs + reg);
+}
+
+static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
+{
+ return readl(i2c_dev->regs + reg);
+}
+
+static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
+{
+ u32 divider, redl, fedl;
+
+ divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
+ i2c_dev->bus_clk_rate);
+ /*
+ * Per the datasheet, the register is always interpreted as an even
+ * number, by rounding down. In other words, the LSB is ignored. So,
+ * if the LSB is set, increment the divider to avoid any issue.
+ */
+ if (divider & 1)
+ divider++;
+ if ((divider < BCM2835_I2C_CDIV_MIN) ||
+ (divider > BCM2835_I2C_CDIV_MAX)) {
+ dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
+ return -EINVAL;
+ }
+
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
+
+ /*
+ * Number of core clocks to wait after falling edge before
+ * outputting the next data bit. Note that both FEDL and REDL
+ * can't be greater than CDIV/2.
+ */
+ fedl = max(divider / 16, 1u);
+
+ /*
+ * Number of core clocks to wait after rising edge before
+ * sampling the next incoming data bit.
+ */
+ redl = max(divider / 4, 1u);
+
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
+ (fedl << BCM2835_I2C_FEDL_SHIFT) |
+ (redl << BCM2835_I2C_REDL_SHIFT));
+ return 0;
+}
+
+static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
+{
+ u32 val;
+
+ while (i2c_dev->msg_buf_remaining) {
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+ if (!(val & BCM2835_I2C_S_TXD))
+ break;
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_FIFO,
+ *i2c_dev->msg_buf);
+ i2c_dev->msg_buf++;
+ i2c_dev->msg_buf_remaining--;
+ }
+}
+
+static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev)
+{
+ u32 val;
+
+ while (i2c_dev->msg_buf_remaining) {
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+ if (!(val & BCM2835_I2C_S_RXD))
+ break;
+ *i2c_dev->msg_buf = bcm2835_i2c_readl(i2c_dev,
+ BCM2835_I2C_FIFO);
+ i2c_dev->msg_buf++;
+ i2c_dev->msg_buf_remaining--;
+ }
+}
+
+/*
+ * Repeated Start Condition (Sr)
+ * The BCM2835 ARM Peripherals datasheet mentions a way to trigger a Sr when it
+ * talks about reading from a slave with 10 bit address. This is achieved by
+ * issuing a write, poll the I2CS.TA flag and wait for it to be set, and then
+ * issue a read.
+ * A comment in https://github.com/raspberrypi/linux/issues/254 shows how the
+ * firmware actually does it using polling and says that it's a workaround for
+ * a problem in the state machine.
+ * It turns out that it is possible to use the TXW interrupt to know when the
+ * transfer is active, provided the FIFO has not been prefilled.
+ */
+
+static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev)
+{
+ u32 c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN;
+ struct i2c_msg *msg = i2c_dev->curr_msg;
+ bool last_msg = (i2c_dev->num_msgs == 1);
+
+ if (!i2c_dev->num_msgs)
+ return;
+
+ i2c_dev->num_msgs--;
+ i2c_dev->msg_buf = msg->buf;
+ i2c_dev->msg_buf_remaining = msg->len;
+
+ if (msg->flags & I2C_M_RD)
+ c |= BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR;
+ else
+ c |= BCM2835_I2C_C_INTT;
+
+ if (last_msg)
+ c |= BCM2835_I2C_C_INTD;
+
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+}
+
+static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev)
+{
+ i2c_dev->curr_msg = NULL;
+ i2c_dev->num_msgs = 0;
+
+ i2c_dev->msg_buf = NULL;
+ i2c_dev->msg_buf_remaining = 0;
+}
+
+/*
+ * Note about I2C_C_CLEAR on error:
+ * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in
+ * non-idle state and I2C_C_READ, it sets an abort_rx flag and runs through
+ * the state machine to send a NACK and a STOP. Since we're setting CLEAR
+ * without I2CEN, that NACK will be hanging around queued up for next time
+ * we start the engine.
+ */
+
+static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
+{
+ struct bcm2835_i2c_dev *i2c_dev = data;
+ u32 val, err;
+
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+
+ err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
+ if (err) {
+ i2c_dev->msg_err = err;
+ goto complete;
+ }
+
+ if (val & BCM2835_I2C_S_DONE) {
+ if (!i2c_dev->curr_msg) {
+ dev_err(i2c_dev->dev, "Got unexpected interrupt (from firmware?)\n");
+ } else if (i2c_dev->curr_msg->flags & I2C_M_RD) {
+ bcm2835_drain_rxfifo(i2c_dev);
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+ }
+
+ if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining)
+ i2c_dev->msg_err = BCM2835_I2C_S_LEN;
+ else
+ i2c_dev->msg_err = 0;
+ goto complete;
+ }
+
+ if (val & BCM2835_I2C_S_TXW) {
+ if (!i2c_dev->msg_buf_remaining) {
+ i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
+ goto complete;
+ }
+
+ bcm2835_fill_txfifo(i2c_dev);
+
+ if (i2c_dev->num_msgs && !i2c_dev->msg_buf_remaining) {
+ i2c_dev->curr_msg++;
+ bcm2835_i2c_start_transfer(i2c_dev);
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ if (val & BCM2835_I2C_S_RXR) {
+ if (!i2c_dev->msg_buf_remaining) {
+ i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
+ goto complete;
+ }
+
+ bcm2835_drain_rxfifo(i2c_dev);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+
+complete:
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT |
+ BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE);
+ complete(&i2c_dev->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ unsigned long time_left;
+ int i, ret;
+
+ for (i = 0; i < (num - 1); i++)
+ if (msgs[i].flags & I2C_M_RD) {
+ dev_warn_once(i2c_dev->dev,
+ "only one read message supported, has to be last\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = bcm2835_i2c_set_divider(i2c_dev);
+ if (ret)
+ return ret;
+
+ i2c_dev->curr_msg = msgs;
+ i2c_dev->num_msgs = num;
+ reinit_completion(&i2c_dev->completion);
+
+ bcm2835_i2c_start_transfer(i2c_dev);
+
+ time_left = wait_for_completion_timeout(&i2c_dev->completion,
+ adap->timeout);
+
+ bcm2835_i2c_finish_transfer(i2c_dev);
+
+ if (!time_left) {
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
+ BCM2835_I2C_C_CLEAR);
+ dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if (!i2c_dev->msg_err)
+ return num;
+
+ dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
+
+ if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
+ return -EREMOTEIO;
+
+ return -EIO;
+}
+
+static u32 bcm2835_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm bcm2835_i2c_algo = {
+ .master_xfer = bcm2835_i2c_xfer,
+ .functionality = bcm2835_i2c_func,
+};
+
+/*
+ * This HW was reported to have problems with clock stretching:
+ * http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html
+ * https://www.raspberrypi.org/forums/viewtopic.php?p=146272
+ */
+static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
+ .flags = I2C_AQ_NO_CLK_STRETCH,
+};
+
+static int bcm2835_i2c_probe(struct platform_device *pdev)
+{
+ struct bcm2835_i2c_dev *i2c_dev;
+ struct resource *mem, *irq;
+ int ret;
+ struct i2c_adapter *adap;
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, i2c_dev);
+ i2c_dev->dev = &pdev->dev;
+ init_completion(&i2c_dev->completion);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(i2c_dev->regs))
+ return PTR_ERR(i2c_dev->regs);
+
+ i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_dev->clk)) {
+ if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c_dev->bus_clk_rate);
+ if (ret < 0) {
+ dev_warn(&pdev->dev,
+ "Could not read clock-frequency property\n");
+ i2c_dev->bus_clk_rate = 100000;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ return -ENODEV;
+ }
+ i2c_dev->irq = irq->start;
+
+ ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED,
+ dev_name(&pdev->dev), i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not request IRQ\n");
+ return -ENODEV;
+ }
+
+ adap = &i2c_dev->adapter;
+ i2c_set_adapdata(adap, i2c_dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_DEPRECATED;
+ strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
+ adap->algo = &bcm2835_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+ adap->quirks = &bcm2835_i2c_quirks;
+
+ /*
+ * Disable the hardware clock stretching timeout. SMBUS
+ * specifies a limit for how long the device can stretch the
+ * clock, but core I2C doesn't.
+ */
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_CLKT, 0);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ free_irq(i2c_dev->irq, i2c_dev);
+
+ return ret;
+}
+
+static int bcm2835_i2c_remove(struct platform_device *pdev)
+{
+ struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ free_irq(i2c_dev->irq, i2c_dev);
+ i2c_del_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_i2c_of_match[] = {
+ { .compatible = "brcm,bcm2835-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match);
+
+static struct platform_driver bcm2835_i2c_driver = {
+ .probe = bcm2835_i2c_probe,
+ .remove = bcm2835_i2c_remove,
+ .driver = {
+ .name = "i2c-bcm2835",
+ .of_match_table = bcm2835_i2c_of_match,
+ },
+};
+module_platform_driver(bcm2835_i2c_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
+MODULE_DESCRIPTION("BCM2835 I2C bus adapter");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-bcm2835");
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
new file mode 100644
index 000000000..1e8890601
--- /dev/null
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -0,0 +1,735 @@
+/*
+ * Copyright (C) 2014 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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+
+#define N_DATA_REGS 8
+
+/*
+ * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register
+ * size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per
+ * data register whereas STB SoCs use 4 byte per data register transfer,
+ * account for this difference in total count per transaction and mask to
+ * use.
+ */
+#define BSC_CNT_REG1_MASK(nb) (nb == 1 ? GENMASK(3, 0) : GENMASK(5, 0))
+#define BSC_CNT_REG1_SHIFT 0
+
+/* BSC CTL register field definitions */
+#define BSC_CTL_REG_DTF_MASK 0x00000003
+#define BSC_CTL_REG_SCL_SEL_MASK 0x00000030
+#define BSC_CTL_REG_SCL_SEL_SHIFT 4
+#define BSC_CTL_REG_INT_EN_MASK 0x00000040
+#define BSC_CTL_REG_INT_EN_SHIFT 6
+#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080
+
+/* BSC_IIC_ENABLE r/w enable and interrupt field definitions */
+#define BSC_IIC_EN_RESTART_MASK 0x00000040
+#define BSC_IIC_EN_NOSTART_MASK 0x00000020
+#define BSC_IIC_EN_NOSTOP_MASK 0x00000010
+#define BSC_IIC_EN_NOACK_MASK 0x00000004
+#define BSC_IIC_EN_INTRP_MASK 0x00000002
+#define BSC_IIC_EN_ENABLE_MASK 0x00000001
+
+/* BSC_CTLHI control register field definitions */
+#define BSC_CTLHI_REG_INPUT_SWITCHING_LEVEL_MASK 0x00000080
+#define BSC_CTLHI_REG_DATAREG_SIZE_MASK 0x00000040
+#define BSC_CTLHI_REG_IGNORE_ACK_MASK 0x00000002
+#define BSC_CTLHI_REG_WAIT_DIS_MASK 0x00000001
+
+#define I2C_TIMEOUT 100 /* msecs */
+
+/* Condition mask used for non combined transfer */
+#define COND_RESTART BSC_IIC_EN_RESTART_MASK
+#define COND_NOSTART BSC_IIC_EN_NOSTART_MASK
+#define COND_NOSTOP BSC_IIC_EN_NOSTOP_MASK
+#define COND_START_STOP (COND_RESTART | COND_NOSTART | COND_NOSTOP)
+
+/* BSC data transfer direction */
+#define DTF_WR_MASK 0x00000000
+#define DTF_RD_MASK 0x00000001
+/* BSC data transfer direction combined format */
+#define DTF_RD_WR_MASK 0x00000002
+#define DTF_WR_RD_MASK 0x00000003
+
+#define INT_ENABLE true
+#define INT_DISABLE false
+
+/* BSC block register map structure to cache fields to be written */
+struct bsc_regs {
+ u32 chip_address; /* slave address */
+ u32 data_in[N_DATA_REGS]; /* tx data buffer*/
+ u32 cnt_reg; /* rx/tx data length */
+ u32 ctl_reg; /* control register */
+ u32 iic_enable; /* xfer enable and status */
+ u32 data_out[N_DATA_REGS]; /* rx data buffer */
+ u32 ctlhi_reg; /* more control fields */
+ u32 scl_param; /* reserved */
+};
+
+struct bsc_clk_param {
+ u32 hz;
+ u32 scl_mask;
+ u32 div_mask;
+};
+
+enum bsc_xfer_cmd {
+ CMD_WR,
+ CMD_RD,
+ CMD_WR_NOACK,
+ CMD_RD_NOACK,
+};
+
+static char const *cmd_string[] = {
+ [CMD_WR] = "WR",
+ [CMD_RD] = "RD",
+ [CMD_WR_NOACK] = "WR NOACK",
+ [CMD_RD_NOACK] = "RD NOACK",
+};
+
+enum bus_speeds {
+ SPD_375K,
+ SPD_390K,
+ SPD_187K,
+ SPD_200K,
+ SPD_93K,
+ SPD_97K,
+ SPD_46K,
+ SPD_50K
+};
+
+static const struct bsc_clk_param bsc_clk[] = {
+ [SPD_375K] = {
+ .hz = 375000,
+ .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = 0
+ },
+ [SPD_390K] = {
+ .hz = 390000,
+ .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = 0
+ },
+ [SPD_187K] = {
+ .hz = 187500,
+ .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = 0
+ },
+ [SPD_200K] = {
+ .hz = 200000,
+ .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = 0
+ },
+ [SPD_93K] = {
+ .hz = 93750,
+ .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = BSC_CTL_REG_DIV_CLK_MASK
+ },
+ [SPD_97K] = {
+ .hz = 97500,
+ .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = BSC_CTL_REG_DIV_CLK_MASK
+ },
+ [SPD_46K] = {
+ .hz = 46875,
+ .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = BSC_CTL_REG_DIV_CLK_MASK
+ },
+ [SPD_50K] = {
+ .hz = 50000,
+ .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT,
+ .div_mask = BSC_CTL_REG_DIV_CLK_MASK
+ }
+};
+
+struct brcmstb_i2c_dev {
+ struct device *device;
+ void __iomem *base;
+ void __iomem *irq_base;
+ int irq;
+ struct bsc_regs *bsc_regmap;
+ struct i2c_adapter adapter;
+ struct completion done;
+ bool is_suspended;
+ u32 clk_freq_hz;
+ int data_regsz;
+};
+
+/* register accessors for both be and le cpu arch */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __bsc_readl(_reg) ioread32be(_reg)
+#define __bsc_writel(_val, _reg) iowrite32be(_val, _reg)
+#else
+#define __bsc_readl(_reg) ioread32(_reg)
+#define __bsc_writel(_val, _reg) iowrite32(_val, _reg)
+#endif
+
+#define bsc_readl(_dev, _reg) \
+ __bsc_readl(_dev->base + offsetof(struct bsc_regs, _reg))
+
+#define bsc_writel(_dev, _val, _reg) \
+ __bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg))
+
+static inline int brcmstb_i2c_get_xfersz(struct brcmstb_i2c_dev *dev)
+{
+ return (N_DATA_REGS * dev->data_regsz);
+}
+
+static inline int brcmstb_i2c_get_data_regsz(struct brcmstb_i2c_dev *dev)
+{
+ return dev->data_regsz;
+}
+
+static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev,
+ bool int_en)
+{
+
+ if (int_en)
+ /* Enable BSC CTL interrupt line */
+ dev->bsc_regmap->ctl_reg |= BSC_CTL_REG_INT_EN_MASK;
+ else
+ /* Disable BSC CTL interrupt line */
+ dev->bsc_regmap->ctl_reg &= ~BSC_CTL_REG_INT_EN_MASK;
+
+ barrier();
+ bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg);
+}
+
+static irqreturn_t brcmstb_i2c_isr(int irq, void *devid)
+{
+ struct brcmstb_i2c_dev *dev = devid;
+ u32 status_bsc_ctl = bsc_readl(dev, ctl_reg);
+ u32 status_iic_intrp = bsc_readl(dev, iic_enable);
+
+ dev_dbg(dev->device, "isr CTL_REG %x IIC_EN %x\n",
+ status_bsc_ctl, status_iic_intrp);
+
+ if (!(status_bsc_ctl & BSC_CTL_REG_INT_EN_MASK))
+ return IRQ_NONE;
+
+ brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
+ complete(&dev->done);
+
+ dev_dbg(dev->device, "isr handled");
+ return IRQ_HANDLED;
+}
+
+/* Wait for device to be ready */
+static int brcmstb_i2c_wait_if_busy(struct brcmstb_i2c_dev *dev)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT);
+
+ while ((bsc_readl(dev, iic_enable) & BSC_IIC_EN_INTRP_MASK)) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ cpu_relax();
+ }
+ return 0;
+}
+
+/* i2c xfer completion function, handles both irq and polling mode */
+static int brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev *dev)
+{
+ int ret = 0;
+ unsigned long timeout = msecs_to_jiffies(I2C_TIMEOUT);
+
+ if (dev->irq >= 0) {
+ if (!wait_for_completion_timeout(&dev->done, timeout))
+ ret = -ETIMEDOUT;
+ } else {
+ /* we are in polling mode */
+ u32 bsc_intrp;
+ unsigned long time_left = jiffies + timeout;
+
+ do {
+ bsc_intrp = bsc_readl(dev, iic_enable) &
+ BSC_IIC_EN_INTRP_MASK;
+ if (time_after(jiffies, time_left)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ cpu_relax();
+ } while (!bsc_intrp);
+ }
+
+ if (dev->irq < 0 || ret == -ETIMEDOUT)
+ brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
+
+ return ret;
+}
+
+/* Set xfer START/STOP conditions for subsequent transfer */
+static void brcmstb_set_i2c_start_stop(struct brcmstb_i2c_dev *dev,
+ u32 cond_flag)
+{
+ u32 regval = dev->bsc_regmap->iic_enable;
+
+ dev->bsc_regmap->iic_enable = (regval & ~COND_START_STOP) | cond_flag;
+}
+
+/* Send I2C request check completion */
+static int brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev *dev,
+ enum bsc_xfer_cmd cmd)
+{
+ int rc = 0;
+ struct bsc_regs *pi2creg = dev->bsc_regmap;
+
+ /* Make sure the hardware is ready */
+ rc = brcmstb_i2c_wait_if_busy(dev);
+ if (rc < 0)
+ return rc;
+
+ /* only if we are in interrupt mode */
+ if (dev->irq >= 0)
+ reinit_completion(&dev->done);
+
+ /* enable BSC CTL interrupt line */
+ brcmstb_i2c_enable_disable_irq(dev, INT_ENABLE);
+
+ /* initiate transfer by setting iic_enable */
+ pi2creg->iic_enable |= BSC_IIC_EN_ENABLE_MASK;
+ bsc_writel(dev, pi2creg->iic_enable, iic_enable);
+
+ /* Wait for transaction to finish or timeout */
+ rc = brcmstb_i2c_wait_for_completion(dev);
+ if (rc) {
+ dev_dbg(dev->device, "intr timeout for cmd %s\n",
+ cmd_string[cmd]);
+ goto cmd_out;
+ }
+
+ if ((cmd == CMD_RD || cmd == CMD_WR) &&
+ bsc_readl(dev, iic_enable) & BSC_IIC_EN_NOACK_MASK) {
+ rc = -EREMOTEIO;
+ dev_dbg(dev->device, "controller received NOACK intr for %s\n",
+ cmd_string[cmd]);
+ }
+
+cmd_out:
+ bsc_writel(dev, 0, cnt_reg);
+ bsc_writel(dev, 0, iic_enable);
+
+ return rc;
+}
+
+/* Actual data transfer through the BSC master */
+static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
+ u8 *buf, unsigned int len,
+ struct i2c_msg *pmsg)
+{
+ int cnt, byte, i, rc;
+ enum bsc_xfer_cmd cmd;
+ u32 ctl_reg;
+ struct bsc_regs *pi2creg = dev->bsc_regmap;
+ int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
+ int data_regsz = brcmstb_i2c_get_data_regsz(dev);
+
+ /* see if the transaction needs to check NACK conditions */
+ if (no_ack) {
+ cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
+ : CMD_WR_NOACK;
+ pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
+ } else {
+ cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD : CMD_WR;
+ pi2creg->ctlhi_reg &= ~BSC_CTLHI_REG_IGNORE_ACK_MASK;
+ }
+ bsc_writel(dev, pi2creg->ctlhi_reg, ctlhi_reg);
+
+ /* set data transfer direction */
+ ctl_reg = pi2creg->ctl_reg & ~BSC_CTL_REG_DTF_MASK;
+ if (cmd == CMD_WR || cmd == CMD_WR_NOACK)
+ pi2creg->ctl_reg = ctl_reg | DTF_WR_MASK;
+ else
+ pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK;
+
+ /* set the read/write length */
+ bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) &
+ (len << BSC_CNT_REG1_SHIFT), cnt_reg);
+
+ /* Write data into data_in register */
+
+ if (cmd == CMD_WR || cmd == CMD_WR_NOACK) {
+ for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
+ u32 word = 0;
+
+ for (byte = 0; byte < data_regsz; byte++) {
+ word >>= BITS_PER_BYTE;
+ if ((cnt + byte) < len)
+ word |= buf[cnt + byte] <<
+ (BITS_PER_BYTE * (data_regsz - 1));
+ }
+ bsc_writel(dev, word, data_in[i]);
+ }
+ }
+
+ /* Initiate xfer, the function will return on completion */
+ rc = brcmstb_send_i2c_cmd(dev, cmd);
+
+ if (rc != 0) {
+ dev_dbg(dev->device, "%s failure", cmd_string[cmd]);
+ return rc;
+ }
+
+ /* Read data from data_out register */
+ if (cmd == CMD_RD || cmd == CMD_RD_NOACK) {
+ for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
+ u32 data = bsc_readl(dev, data_out[i]);
+
+ for (byte = 0; byte < data_regsz &&
+ (byte + cnt) < len; byte++) {
+ buf[cnt + byte] = data & 0xff;
+ data >>= BITS_PER_BYTE;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Write a single byte of data to the i2c bus */
+static int brcmstb_i2c_write_data_byte(struct brcmstb_i2c_dev *dev,
+ u8 *buf, unsigned int nak_expected)
+{
+ enum bsc_xfer_cmd cmd = nak_expected ? CMD_WR : CMD_WR_NOACK;
+
+ bsc_writel(dev, 1, cnt_reg);
+ bsc_writel(dev, *buf, data_in);
+
+ return brcmstb_send_i2c_cmd(dev, cmd);
+}
+
+/* Send i2c address */
+static int brcmstb_i2c_do_addr(struct brcmstb_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);
+ bsc_writel(dev, addr, chip_address);
+
+ /* Second byte is the remaining 8 bits */
+ addr = msg->addr & 0xFF;
+ if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
+ return -EREMOTEIO;
+
+ if (msg->flags & I2C_M_RD) {
+ /* For read, send restart without stop condition */
+ brcmstb_set_i2c_start_stop(dev, COND_RESTART
+ | COND_NOSTOP);
+ /* Then re-send the first byte with the read bit set */
+ addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
+ if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
+ return -EREMOTEIO;
+
+ }
+ } else {
+ addr = i2c_8bit_addr_from_msg(msg);
+
+ bsc_writel(dev, addr, chip_address);
+ }
+
+ return 0;
+}
+
+/* Master transfer function */
+static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct brcmstb_i2c_dev *dev = i2c_get_adapdata(adapter);
+ struct i2c_msg *pmsg;
+ int rc = 0;
+ int i;
+ int bytes_to_xfer;
+ u8 *tmp_buf;
+ int len = 0;
+ int xfersz = brcmstb_i2c_get_xfersz(dev);
+ u32 cond, cond_per_msg;
+
+ if (dev->is_suspended)
+ return -EBUSY;
+
+ /* Loop through all messages */
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ len = pmsg->len;
+ tmp_buf = pmsg->buf;
+
+ dev_dbg(dev->device,
+ "msg# %d/%d flg %x buf %x len %d\n", i,
+ num - 1, pmsg->flags,
+ pmsg->buf ? pmsg->buf[0] : '0', pmsg->len);
+
+ if (i < (num - 1) && (msgs[i + 1].flags & I2C_M_NOSTART))
+ cond = ~COND_START_STOP;
+ else
+ cond = COND_RESTART | COND_NOSTOP;
+
+ brcmstb_set_i2c_start_stop(dev, cond);
+
+ /* Send slave address */
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ rc = brcmstb_i2c_do_addr(dev, pmsg);
+ if (rc < 0) {
+ dev_dbg(dev->device,
+ "NACK for addr %2.2x msg#%d rc = %d\n",
+ pmsg->addr, i, rc);
+ goto out;
+ }
+ }
+
+ cond_per_msg = cond;
+
+ /* Perform data transfer */
+ while (len) {
+ bytes_to_xfer = min(len, xfersz);
+
+ if (len <= xfersz) {
+ if (i == (num - 1))
+ cond_per_msg = cond_per_msg &
+ ~(COND_RESTART | COND_NOSTOP);
+ else
+ cond_per_msg = cond;
+ } else {
+ cond_per_msg = (cond_per_msg & ~COND_RESTART) |
+ COND_NOSTOP;
+ }
+
+ brcmstb_set_i2c_start_stop(dev, cond_per_msg);
+
+ rc = brcmstb_i2c_xfer_bsc_data(dev, tmp_buf,
+ bytes_to_xfer, pmsg);
+ if (rc < 0)
+ goto out;
+
+ len -= bytes_to_xfer;
+ tmp_buf += bytes_to_xfer;
+
+ cond_per_msg = COND_NOSTART | COND_NOSTOP;
+ }
+ }
+
+ rc = num;
+out:
+ return rc;
+
+}
+
+static u32 brcmstb_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR
+ | I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm brcmstb_i2c_algo = {
+ .master_xfer = brcmstb_i2c_xfer,
+ .functionality = brcmstb_i2c_functionality,
+};
+
+static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev)
+{
+ int i = 0, num_speeds = ARRAY_SIZE(bsc_clk);
+ u32 clk_freq_hz = dev->clk_freq_hz;
+
+ for (i = 0; i < num_speeds; i++) {
+ if (bsc_clk[i].hz == clk_freq_hz) {
+ dev->bsc_regmap->ctl_reg &= ~(BSC_CTL_REG_SCL_SEL_MASK
+ | BSC_CTL_REG_DIV_CLK_MASK);
+ dev->bsc_regmap->ctl_reg |= (bsc_clk[i].scl_mask |
+ bsc_clk[i].div_mask);
+ bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg);
+ break;
+ }
+ }
+
+ /* in case we did not get find a valid speed */
+ if (i == num_speeds) {
+ i = (bsc_readl(dev, ctl_reg) & BSC_CTL_REG_SCL_SEL_MASK) >>
+ BSC_CTL_REG_SCL_SEL_SHIFT;
+ dev_warn(dev->device, "leaving current clock-frequency @ %dHz\n",
+ bsc_clk[i].hz);
+ }
+}
+
+static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev)
+{
+ if (brcmstb_i2c_get_data_regsz(dev) == sizeof(u32))
+ /* set 4 byte data in/out xfers */
+ dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK;
+ else
+ dev->bsc_regmap->ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK;
+
+ bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg);
+ /* set bus speed */
+ brcmstb_i2c_set_bus_speed(dev);
+}
+
+static int brcmstb_i2c_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct brcmstb_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *iomem;
+ const char *int_name;
+
+ /* Allocate memory for private data structure */
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL);
+ if (!dev->bsc_regmap)
+ 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)) {
+ rc = -ENOMEM;
+ goto probe_errorout;
+ }
+
+ rc = of_property_read_string(dev->device->of_node, "interrupt-names",
+ &int_name);
+ if (rc < 0)
+ int_name = NULL;
+
+ /* Get the interrupt number */
+ dev->irq = platform_get_irq(pdev, 0);
+
+ /* disable the bsc interrupt line */
+ brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
+
+ /* register the ISR handler */
+ rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr,
+ IRQF_SHARED,
+ int_name ? int_name : pdev->name,
+ dev);
+
+ if (rc) {
+ dev_dbg(dev->device, "falling back to polling mode");
+ dev->irq = -1;
+ }
+
+ if (of_property_read_u32(dev->device->of_node,
+ "clock-frequency", &dev->clk_freq_hz)) {
+ dev_warn(dev->device, "setting clock-frequency@%dHz\n",
+ bsc_clk[0].hz);
+ dev->clk_freq_hz = bsc_clk[0].hz;
+ }
+
+ /* set the data in/out register size for compatible SoCs */
+ if (of_device_is_compatible(dev->device->of_node,
+ "brcm,brcmper-i2c"))
+ dev->data_regsz = sizeof(u8);
+ else
+ dev->data_regsz = sizeof(u32);
+
+ brcmstb_i2c_set_bsc_reg_defaults(dev);
+
+ /* Add the i2c adapter */
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ strlcpy(adap->name, "Broadcom STB : ", sizeof(adap->name));
+ if (int_name)
+ strlcat(adap->name, int_name, sizeof(adap->name));
+ adap->algo = &brcmstb_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+ rc = i2c_add_adapter(adap);
+ if (rc)
+ goto probe_errorout;
+
+ dev_info(dev->device, "%s@%dhz registered in %s mode\n",
+ int_name ? int_name : " ", dev->clk_freq_hz,
+ (dev->irq >= 0) ? "interrupt" : "polling");
+
+ return 0;
+
+probe_errorout:
+ return rc;
+}
+
+static int brcmstb_i2c_remove(struct platform_device *pdev)
+{
+ struct brcmstb_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcmstb_i2c_suspend(struct device *dev)
+{
+ struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
+ i2c_dev->is_suspended = true;
+ i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
+
+ return 0;
+}
+
+static int brcmstb_i2c_resume(struct device *dev)
+{
+ struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
+ brcmstb_i2c_set_bsc_reg_defaults(i2c_dev);
+ i2c_dev->is_suspended = false;
+ i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend,
+ brcmstb_i2c_resume);
+
+static const struct of_device_id brcmstb_i2c_of_match[] = {
+ {.compatible = "brcm,brcmstb-i2c"},
+ {.compatible = "brcm,brcmper-i2c"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match);
+
+static struct platform_driver brcmstb_i2c_driver = {
+ .driver = {
+ .name = "brcmstb-i2c",
+ .of_match_table = brcmstb_i2c_of_match,
+ .pm = &brcmstb_i2c_pm,
+ },
+ .probe = brcmstb_i2c_probe,
+ .remove = brcmstb_i2c_remove,
+};
+module_platform_driver(brcmstb_i2c_driver);
+
+MODULE_AUTHOR("Kamal Dasu <kdasu@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Settop I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
new file mode 100644
index 000000000..2150afdcc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -0,0 +1,1033 @@
+/*
+ * I2C bus driver for the Cadence I2C controller.
+ *
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any
+ * later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+
+/* Register offsets for the I2C device. */
+#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
+#define CDNS_I2C_SR_OFFSET 0x04 /* Status Register, RO */
+#define CDNS_I2C_ADDR_OFFSET 0x08 /* I2C Address Register, RW */
+#define CDNS_I2C_DATA_OFFSET 0x0C /* I2C Data Register, RW */
+#define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */
+#define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
+#define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
+#define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */
+#define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */
+
+/* Control Register Bit mask definitions */
+#define CDNS_I2C_CR_HOLD BIT(4) /* Hold Bus bit */
+#define CDNS_I2C_CR_ACK_EN BIT(3)
+#define CDNS_I2C_CR_NEA BIT(2)
+#define CDNS_I2C_CR_MS BIT(1)
+/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */
+#define CDNS_I2C_CR_RW BIT(0)
+/* 1 = Auto init FIFO to zeroes */
+#define CDNS_I2C_CR_CLR_FIFO BIT(6)
+#define CDNS_I2C_CR_DIVA_SHIFT 14
+#define CDNS_I2C_CR_DIVA_MASK (3 << CDNS_I2C_CR_DIVA_SHIFT)
+#define CDNS_I2C_CR_DIVB_SHIFT 8
+#define CDNS_I2C_CR_DIVB_MASK (0x3f << CDNS_I2C_CR_DIVB_SHIFT)
+
+/* Status Register Bit mask definitions */
+#define CDNS_I2C_SR_BA BIT(8)
+#define CDNS_I2C_SR_RXDV BIT(5)
+
+/*
+ * I2C Address Register Bit mask definitions
+ * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
+ * bits. A write access to this register always initiates a transfer if the I2C
+ * is in master mode.
+ */
+#define CDNS_I2C_ADDR_MASK 0x000003FF /* I2C Address Mask */
+
+/*
+ * I2C Interrupt Registers Bit mask definitions
+ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
+ * bit definitions.
+ */
+#define CDNS_I2C_IXR_ARB_LOST BIT(9)
+#define CDNS_I2C_IXR_RX_UNF BIT(7)
+#define CDNS_I2C_IXR_TX_OVF BIT(6)
+#define CDNS_I2C_IXR_RX_OVF BIT(5)
+#define CDNS_I2C_IXR_SLV_RDY BIT(4)
+#define CDNS_I2C_IXR_TO BIT(3)
+#define CDNS_I2C_IXR_NACK BIT(2)
+#define CDNS_I2C_IXR_DATA BIT(1)
+#define CDNS_I2C_IXR_COMP BIT(0)
+
+#define CDNS_I2C_IXR_ALL_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
+ CDNS_I2C_IXR_RX_UNF | \
+ CDNS_I2C_IXR_TX_OVF | \
+ CDNS_I2C_IXR_RX_OVF | \
+ CDNS_I2C_IXR_SLV_RDY | \
+ CDNS_I2C_IXR_TO | \
+ CDNS_I2C_IXR_NACK | \
+ CDNS_I2C_IXR_DATA | \
+ CDNS_I2C_IXR_COMP)
+
+#define CDNS_I2C_IXR_ERR_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
+ CDNS_I2C_IXR_RX_UNF | \
+ CDNS_I2C_IXR_TX_OVF | \
+ CDNS_I2C_IXR_RX_OVF | \
+ CDNS_I2C_IXR_NACK)
+
+#define CDNS_I2C_ENABLED_INTR_MASK (CDNS_I2C_IXR_ARB_LOST | \
+ CDNS_I2C_IXR_RX_UNF | \
+ CDNS_I2C_IXR_TX_OVF | \
+ CDNS_I2C_IXR_RX_OVF | \
+ CDNS_I2C_IXR_NACK | \
+ CDNS_I2C_IXR_DATA | \
+ CDNS_I2C_IXR_COMP)
+
+#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
+/* timeout for pm runtime autosuspend */
+#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
+
+#define CDNS_I2C_FIFO_DEPTH 16
+/* FIFO depth at which the DATA interrupt occurs */
+#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
+#define CDNS_I2C_MAX_TRANSFER_SIZE 255
+/* Transfer size in multiples of data interrupt depth */
+#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
+
+#define DRIVER_NAME "cdns-i2c"
+
+#define CDNS_I2C_SPEED_MAX 400000
+#define CDNS_I2C_SPEED_DEFAULT 100000
+
+#define CDNS_I2C_DIVA_MAX 4
+#define CDNS_I2C_DIVB_MAX 64
+
+#define CDNS_I2C_TIMEOUT_MAX 0xFF
+
+#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
+
+#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
+#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
+
+/**
+ * struct cdns_i2c - I2C device private data structure
+ *
+ * @dev: Pointer to device structure
+ * @membase: Base address of the I2C device
+ * @adap: I2C adapter instance
+ * @p_msg: Message pointer
+ * @err_status: Error status in Interrupt Status Register
+ * @xfer_done: Transfer complete status
+ * @p_send_buf: Pointer to transmit buffer
+ * @p_recv_buf: Pointer to receive buffer
+ * @send_count: Number of bytes still expected to send
+ * @recv_count: Number of bytes still expected to receive
+ * @curr_recv_count: Number of bytes to be received in current transfer
+ * @irq: IRQ number
+ * @input_clk: Input clock to I2C controller
+ * @i2c_clk: Maximum I2C clock speed
+ * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
+ * @clk: Pointer to struct clk
+ * @clk_rate_change_nb: Notifier block for clock rate changes
+ * @quirks: flag for broken hold bit usage in r1p10
+ */
+struct cdns_i2c {
+ struct device *dev;
+ void __iomem *membase;
+ struct i2c_adapter adap;
+ struct i2c_msg *p_msg;
+ int err_status;
+ struct completion xfer_done;
+ unsigned char *p_send_buf;
+ unsigned char *p_recv_buf;
+ unsigned int send_count;
+ unsigned int recv_count;
+ unsigned int curr_recv_count;
+ int irq;
+ unsigned long input_clk;
+ unsigned int i2c_clk;
+ unsigned int bus_hold_flag;
+ struct clk *clk;
+ struct notifier_block clk_rate_change_nb;
+ u32 quirks;
+};
+
+struct cdns_platform_data {
+ u32 quirks;
+};
+
+#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \
+ clk_rate_change_nb)
+
+/**
+ * cdns_i2c_clear_bus_hold - Clear bus hold bit
+ * @id: Pointer to driver data struct
+ *
+ * Helper to clear the controller's bus hold bit.
+ */
+static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
+{
+ u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ if (reg & CDNS_I2C_CR_HOLD)
+ cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
+}
+
+static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
+{
+ return (hold_wrkaround &&
+ (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1));
+}
+
+/**
+ * cdns_i2c_isr - Interrupt handler for the I2C device
+ * @irq: irq number for the I2C device
+ * @ptr: void pointer to cdns_i2c structure
+ *
+ * This function handles the data interrupt, transfer complete interrupt and
+ * the error interrupts of the I2C device.
+ *
+ * Return: IRQ_HANDLED always
+ */
+static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
+{
+ unsigned int isr_status, avail_bytes, updatetx;
+ unsigned int bytes_to_send;
+ bool hold_quirk;
+ struct cdns_i2c *id = ptr;
+ /* Signal completion only after everything is updated */
+ int done_flag = 0;
+ irqreturn_t status = IRQ_NONE;
+
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+ /* Handling nack and arbitration lost interrupt */
+ if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
+ done_flag = 1;
+ status = IRQ_HANDLED;
+ }
+
+ /*
+ * Check if transfer size register needs to be updated again for a
+ * large data receive operation.
+ */
+ updatetx = 0;
+ if (id->recv_count > id->curr_recv_count)
+ updatetx = 1;
+
+ hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
+
+ /* When receiving, handle data interrupt and completion interrupt */
+ if (id->p_recv_buf &&
+ ((isr_status & CDNS_I2C_IXR_COMP) ||
+ (isr_status & CDNS_I2C_IXR_DATA))) {
+ /* Read data if receive data valid is set */
+ while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
+ CDNS_I2C_SR_RXDV) {
+ /*
+ * Clear hold bit that was set for FIFO control if
+ * RX data left is less than FIFO depth, unless
+ * repeated start is selected.
+ */
+ if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) &&
+ !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+
+ *(id->p_recv_buf)++ =
+ cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+ id->recv_count--;
+ id->curr_recv_count--;
+
+ if (cdns_is_holdquirk(id, hold_quirk))
+ break;
+ }
+
+ /*
+ * The controller sends NACK to the slave when transfer size
+ * register reaches zero without considering the HOLD bit.
+ * This workaround is implemented for large data transfers to
+ * maintain transfer size non-zero while performing a large
+ * receive operation.
+ */
+ if (cdns_is_holdquirk(id, hold_quirk)) {
+ /* wait while fifo is full */
+ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
+ (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
+ ;
+
+ /*
+ * Check number of bytes to be received against maximum
+ * transfer size and update register accordingly.
+ */
+ if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
+ CDNS_I2C_TRANSFER_SIZE) {
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
+ CDNS_I2C_FIFO_DEPTH;
+ } else {
+ cdns_i2c_writereg(id->recv_count -
+ CDNS_I2C_FIFO_DEPTH,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = id->recv_count;
+ }
+ } else if (id->recv_count && !hold_quirk &&
+ !id->curr_recv_count) {
+
+ /* Set the slave address in address register*/
+ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+ CDNS_I2C_ADDR_OFFSET);
+
+ if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ } else {
+ cdns_i2c_writereg(id->recv_count,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = id->recv_count;
+ }
+ }
+
+ /* Clear hold (if not repeated start) and signal completion */
+ if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
+ if (!id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+ done_flag = 1;
+ }
+
+ status = IRQ_HANDLED;
+ }
+
+ /* When sending, handle transfer complete interrupt */
+ if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
+ /*
+ * If there is more data to be sent, calculate the
+ * space available in FIFO and fill with that many bytes.
+ */
+ if (id->send_count) {
+ avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
+
+ while (bytes_to_send--) {
+ cdns_i2c_writereg(
+ (*(id->p_send_buf)++),
+ CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
+ }
+ } else {
+ /*
+ * Signal the completion of transaction and
+ * clear the hold bus bit if there are no
+ * further messages to be processed.
+ */
+ done_flag = 1;
+ }
+ if (!id->send_count && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+
+ status = IRQ_HANDLED;
+ }
+
+ /* Update the status for errors */
+ id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
+ if (id->err_status)
+ status = IRQ_HANDLED;
+
+ if (done_flag)
+ complete(&id->xfer_done);
+
+ return status;
+}
+
+/**
+ * cdns_i2c_mrecv - Prepare and start a master receive operation
+ * @id: pointer to the i2c device structure
+ */
+static void cdns_i2c_mrecv(struct cdns_i2c *id)
+{
+ unsigned int ctrl_reg;
+ unsigned int isr_status;
+
+ id->p_recv_buf = id->p_msg->buf;
+ id->recv_count = id->p_msg->len;
+
+ /* Put the controller in master receive mode and clear the FIFO */
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
+
+ if (id->p_msg->flags & I2C_M_RECV_LEN)
+ id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+
+ id->curr_recv_count = id->recv_count;
+
+ /*
+ * Check for the message size against FIFO depth and set the
+ * 'hold bus' bit if it is greater than FIFO depth.
+ */
+ if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
+ ctrl_reg |= CDNS_I2C_CR_HOLD;
+
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+ /* Clear the interrupts in interrupt status register */
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+ /*
+ * The no. of bytes to receive is checked against the limit of
+ * max transfer size. Set transfer size register with no of bytes
+ * receive if it is less than transfer size and transfer size if
+ * it is more. Enable the interrupts.
+ */
+ if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ } else {
+ cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
+ }
+
+ /* Set the slave address in address register - triggers operation */
+ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+ CDNS_I2C_ADDR_OFFSET);
+ /* Clear the bus hold flag if bytes to receive is less than FIFO size */
+ if (!id->bus_hold_flag &&
+ ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
+ (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
+ cdns_i2c_clear_bus_hold(id);
+ cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+}
+
+/**
+ * cdns_i2c_msend - Prepare and start a master send operation
+ * @id: pointer to the i2c device
+ */
+static void cdns_i2c_msend(struct cdns_i2c *id)
+{
+ unsigned int avail_bytes;
+ unsigned int bytes_to_send;
+ unsigned int ctrl_reg;
+ unsigned int isr_status;
+
+ id->p_recv_buf = NULL;
+ id->p_send_buf = id->p_msg->buf;
+ id->send_count = id->p_msg->len;
+
+ /* Set the controller in Master transmit mode and clear the FIFO. */
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg &= ~CDNS_I2C_CR_RW;
+ ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
+
+ /*
+ * Check for the message size against FIFO depth and set the
+ * 'hold bus' bit if it is greater than FIFO depth.
+ */
+ if (id->send_count > CDNS_I2C_FIFO_DEPTH)
+ ctrl_reg |= CDNS_I2C_CR_HOLD;
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+ /* Clear the interrupts in interrupt status register. */
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+ /*
+ * Calculate the space available in FIFO. Check the message length
+ * against the space available, and fill the FIFO accordingly.
+ * Enable the interrupts.
+ */
+ avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
+
+ while (bytes_to_send--) {
+ cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
+ }
+
+ /*
+ * Clear the bus hold flag if there is no more data
+ * and if it is the last message.
+ */
+ if (!id->bus_hold_flag && !id->send_count)
+ cdns_i2c_clear_bus_hold(id);
+ /* Set the slave address in address register - triggers operation. */
+ cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+ CDNS_I2C_ADDR_OFFSET);
+
+ cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+}
+
+/**
+ * cdns_i2c_master_reset - Reset the interface
+ * @adap: pointer to the i2c adapter driver instance
+ *
+ * This function cleanup the fifos, clear the hold bit and status
+ * and disable the interrupts.
+ */
+static void cdns_i2c_master_reset(struct i2c_adapter *adap)
+{
+ struct cdns_i2c *id = adap->algo_data;
+ u32 regval;
+
+ /* Disable the interrupts */
+ cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
+ /* Clear the hold bit and fifos */
+ regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ regval &= ~CDNS_I2C_CR_HOLD;
+ regval |= CDNS_I2C_CR_CLR_FIFO;
+ cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
+ /* Update the transfercount register to zero */
+ cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
+ /* Clear the interupt status register */
+ regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
+ /* Clear the status register */
+ regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
+ cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET);
+}
+
+static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
+ struct i2c_adapter *adap)
+{
+ unsigned long time_left, msg_timeout;
+ u32 reg;
+
+ id->p_msg = msg;
+ id->err_status = 0;
+ reinit_completion(&id->xfer_done);
+
+ /* Check for the TEN Bit mode on each msg */
+ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ if (msg->flags & I2C_M_TEN) {
+ if (reg & CDNS_I2C_CR_NEA)
+ cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
+ CDNS_I2C_CR_OFFSET);
+ } else {
+ if (!(reg & CDNS_I2C_CR_NEA))
+ cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
+ CDNS_I2C_CR_OFFSET);
+ }
+
+ /* Check for the R/W flag on each msg */
+ if (msg->flags & I2C_M_RD)
+ cdns_i2c_mrecv(id);
+ else
+ cdns_i2c_msend(id);
+
+ /* Minimal time to execute this message */
+ msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
+ /* Plus some wiggle room */
+ msg_timeout += msecs_to_jiffies(500);
+
+ if (msg_timeout < adap->timeout)
+ msg_timeout = adap->timeout;
+
+ /* Wait for the signal of completion */
+ time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
+ if (time_left == 0) {
+ cdns_i2c_master_reset(adap);
+ dev_err(id->adap.dev.parent,
+ "timeout waiting on completion\n");
+ return -ETIMEDOUT;
+ }
+
+ cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK,
+ CDNS_I2C_IDR_OFFSET);
+
+ /* If it is bus arbitration error, try again */
+ if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
+ return -EAGAIN;
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_master_xfer - The main i2c transfer function
+ * @adap: pointer to the i2c adapter driver instance
+ * @msgs: pointer to the i2c message structure
+ * @num: the number of messages to transfer
+ *
+ * Initiates the send/recv activity based on the transfer message received.
+ *
+ * Return: number of msgs processed on success, negative error otherwise
+ */
+static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int ret, count;
+ u32 reg;
+ struct cdns_i2c *id = adap->algo_data;
+ bool hold_quirk;
+
+ ret = pm_runtime_get_sync(id->dev);
+ if (ret < 0)
+ return ret;
+ /* Check if the bus is free */
+ if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
+ /*
+ * Set the flag to one when multiple messages are to be
+ * processed with a repeated start.
+ */
+ if (num > 1) {
+ /*
+ * This controller does not give completion interrupt after a
+ * master receive message if HOLD bit is set (repeated start),
+ * resulting in SW timeout. Hence, if a receive message is
+ * followed by any other message, an error is returned
+ * indicating that this sequence is not supported.
+ */
+ for (count = 0; (count < num - 1 && hold_quirk); count++) {
+ if (msgs[count].flags & I2C_M_RD) {
+ dev_warn(adap->dev.parent,
+ "Can't do repeated start after a receive message\n");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+ }
+ id->bus_hold_flag = 1;
+ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ reg |= CDNS_I2C_CR_HOLD;
+ cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
+ } else {
+ id->bus_hold_flag = 0;
+ }
+
+ /* Process the msg one by one */
+ for (count = 0; count < num; count++, msgs++) {
+ if (count == (num - 1))
+ id->bus_hold_flag = 0;
+
+ ret = cdns_i2c_process_msg(id, msgs, adap);
+ if (ret)
+ goto out;
+
+ /* Report the other error interrupts to application */
+ if (id->err_status) {
+ cdns_i2c_master_reset(adap);
+
+ if (id->err_status & CDNS_I2C_IXR_NACK) {
+ ret = -ENXIO;
+ goto out;
+ }
+ ret = -EIO;
+ goto out;
+ }
+ }
+
+ ret = num;
+out:
+ pm_runtime_mark_last_busy(id->dev);
+ pm_runtime_put_autosuspend(id->dev);
+ return ret;
+}
+
+/**
+ * cdns_i2c_func - Returns the supported features of the I2C driver
+ * @adap: pointer to the i2c adapter structure
+ *
+ * Return: 32 bit value, each bit corresponding to a feature
+ */
+static u32 cdns_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+ (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm cdns_i2c_algo = {
+ .master_xfer = cdns_i2c_master_xfer,
+ .functionality = cdns_i2c_func,
+};
+
+/**
+ * cdns_i2c_calc_divs - Calculate clock dividers
+ * @f: I2C clock frequency
+ * @input_clk: Input clock frequency
+ * @a: First divider (return value)
+ * @b: Second divider (return value)
+ *
+ * f is used as input and output variable. As input it is used as target I2C
+ * frequency. On function exit f holds the actually resulting I2C frequency.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
+ unsigned int *a, unsigned int *b)
+{
+ unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
+ unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
+ unsigned int last_error, current_error;
+
+ /* calculate (divisor_a+1) x (divisor_b+1) */
+ temp = input_clk / (22 * fscl);
+
+ /*
+ * If the calculated value is negative or 0, the fscl input is out of
+ * range. Return error.
+ */
+ if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
+ return -EINVAL;
+
+ last_error = -1;
+ for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
+ div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
+
+ if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
+ continue;
+ div_b--;
+
+ actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
+
+ if (actual_fscl > fscl)
+ continue;
+
+ current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
+ (fscl - actual_fscl));
+
+ if (last_error > current_error) {
+ calc_div_a = div_a;
+ calc_div_b = div_b;
+ best_fscl = actual_fscl;
+ last_error = current_error;
+ }
+ }
+
+ *a = calc_div_a;
+ *b = calc_div_b;
+ *f = best_fscl;
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_setclk - This function sets the serial clock rate for the I2C device
+ * @clk_in: I2C clock input frequency in Hz
+ * @id: Pointer to the I2C device structure
+ *
+ * The device must be idle rather than busy transferring data before setting
+ * these device options.
+ * The data rate is set by values in the control register.
+ * The formula for determining the correct register values is
+ * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
+ * See the hardware data sheet for a full explanation of setting the serial
+ * clock rate. The clock can not be faster than the input clock divide by 22.
+ * The two most common clock rates are 100KHz and 400KHz.
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
+{
+ unsigned int div_a, div_b;
+ unsigned int ctrl_reg;
+ int ret = 0;
+ unsigned long fscl = id->i2c_clk;
+
+ ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b);
+ if (ret)
+ return ret;
+
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+ ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
+ ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
+ (div_b << CDNS_I2C_CR_DIVB_SHIFT));
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_clk_notifier_cb - Clock rate change callback
+ * @nb: Pointer to notifier block
+ * @event: Notification reason
+ * @data: Pointer to notification data object
+ *
+ * This function is called when the cdns_i2c input clock frequency changes.
+ * The callback checks whether a valid bus frequency can be generated after the
+ * change. If so, the change is acknowledged, otherwise the change is aborted.
+ * New dividers are written to the HW in the pre- or post change notification
+ * depending on the scaling direction.
+ *
+ * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
+ * to acknowledge the change, NOTIFY_DONE if the notification is
+ * considered irrelevant.
+ */
+static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
+ event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct cdns_i2c *id = to_cdns_i2c(nb);
+
+ if (pm_runtime_suspended(id->dev))
+ return NOTIFY_OK;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ {
+ unsigned long input_clk = ndata->new_rate;
+ unsigned long fscl = id->i2c_clk;
+ unsigned int div_a, div_b;
+ int ret;
+
+ ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b);
+ if (ret) {
+ dev_warn(id->adap.dev.parent,
+ "clock rate change rejected\n");
+ return NOTIFY_STOP;
+ }
+
+ /* scale up */
+ if (ndata->new_rate > ndata->old_rate)
+ cdns_i2c_setclk(ndata->new_rate, id);
+
+ return NOTIFY_OK;
+ }
+ case POST_RATE_CHANGE:
+ id->input_clk = ndata->new_rate;
+ /* scale down */
+ if (ndata->new_rate < ndata->old_rate)
+ cdns_i2c_setclk(ndata->new_rate, id);
+ return NOTIFY_OK;
+ case ABORT_RATE_CHANGE:
+ /* scale up */
+ if (ndata->new_rate > ndata->old_rate)
+ cdns_i2c_setclk(ndata->old_rate, id);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+/**
+ * cdns_i2c_runtime_suspend - Runtime suspend method for the driver
+ * @dev: Address of the platform_device structure
+ *
+ * Put the driver into low power mode.
+ *
+ * Return: 0 always
+ */
+static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
+{
+ struct cdns_i2c *xi2c = dev_get_drvdata(dev);
+
+ clk_disable(xi2c->clk);
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_runtime_resume - Runtime resume
+ * @dev: Address of the platform_device structure
+ *
+ * Runtime resume callback.
+ *
+ * Return: 0 on success and error value on error
+ */
+static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
+{
+ struct cdns_i2c *xi2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(xi2c->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
+ cdns_i2c_runtime_resume, NULL)
+};
+
+static const struct cdns_platform_data r1p10_i2c_def = {
+ .quirks = CDNS_I2C_BROKEN_HOLD_BIT,
+};
+
+static const struct of_device_id cdns_i2c_of_match[] = {
+ { .compatible = "cdns,i2c-r1p10", .data = &r1p10_i2c_def },
+ { .compatible = "cdns,i2c-r1p14",},
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
+
+/**
+ * cdns_i2c_probe - Platform registration call
+ * @pdev: Handle to the platform device structure
+ *
+ * This function does all the memory allocation and registration for the i2c
+ * device. User can modify the address mode to 10 bit address mode using the
+ * ioctl call with option I2C_TENBIT.
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+static int cdns_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *r_mem;
+ struct cdns_i2c *id;
+ int ret;
+ const struct of_device_id *match;
+
+ id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
+ if (!id)
+ return -ENOMEM;
+
+ id->dev = &pdev->dev;
+ platform_set_drvdata(pdev, id);
+
+ match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node);
+ if (match && match->data) {
+ const struct cdns_platform_data *data = match->data;
+ id->quirks = data->quirks;
+ }
+
+ r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
+ if (IS_ERR(id->membase))
+ return PTR_ERR(id->membase);
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+ id->irq = ret;
+
+ id->adap.owner = THIS_MODULE;
+ id->adap.dev.of_node = pdev->dev.of_node;
+ id->adap.algo = &cdns_i2c_algo;
+ id->adap.timeout = CDNS_I2C_TIMEOUT;
+ id->adap.retries = 3; /* Default retry value. */
+ id->adap.algo_data = id;
+ id->adap.dev.parent = &pdev->dev;
+ init_completion(&id->xfer_done);
+ snprintf(id->adap.name, sizeof(id->adap.name),
+ "Cadence I2C at %08lx", (unsigned long)r_mem->start);
+
+ id->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(id->clk)) {
+ dev_err(&pdev->dev, "input clock not found.\n");
+ return PTR_ERR(id->clk);
+ }
+ ret = clk_prepare_enable(id->clk);
+ if (ret)
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+
+ pm_runtime_enable(id->dev);
+ pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(id->dev);
+ pm_runtime_set_active(id->dev);
+
+ id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
+ if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
+ dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
+ id->input_clk = clk_get_rate(id->clk);
+
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &id->i2c_clk);
+ if (ret || (id->i2c_clk > CDNS_I2C_SPEED_MAX))
+ id->i2c_clk = CDNS_I2C_SPEED_DEFAULT;
+
+ cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS,
+ CDNS_I2C_CR_OFFSET);
+
+ ret = cdns_i2c_setclk(id->input_clk, id);
+ if (ret) {
+ dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
+ ret = -EINVAL;
+ goto err_clk_dis;
+ }
+
+ ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
+ DRIVER_NAME, id);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+ goto err_clk_dis;
+ }
+
+ /*
+ * Cadence I2C controller has a bug wherein it generates
+ * invalid read transaction after HW timeout in master receiver mode.
+ * HW timeout is not used by this driver and the interrupt is disabled.
+ * But the feature itself cannot be disabled. Hence maximum value
+ * is written to this register to reduce the chances of error.
+ */
+ cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+
+ ret = i2c_add_adapter(&id->adap);
+ if (ret < 0)
+ goto err_clk_dis;
+
+ dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
+ id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
+
+ return 0;
+
+err_clk_dis:
+ clk_disable_unprepare(id->clk);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+/**
+ * cdns_i2c_remove - Unregister the device after releasing the resources
+ * @pdev: Handle to the platform device structure
+ *
+ * This function frees all the resources allocated to the device.
+ *
+ * Return: 0 always
+ */
+static int cdns_i2c_remove(struct platform_device *pdev)
+{
+ struct cdns_i2c *id = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&id->adap);
+ clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
+ clk_disable_unprepare(id->clk);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver cdns_i2c_drv = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = cdns_i2c_of_match,
+ .pm = &cdns_i2c_dev_pm_ops,
+ },
+ .probe = cdns_i2c_probe,
+ .remove = cdns_i2c_remove,
+};
+
+module_platform_driver(cdns_i2c_drv);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Cadence I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c
new file mode 100644
index 000000000..b4f91e489
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cbus-gpio.c
@@ -0,0 +1,303 @@
+/*
+ * CBUS I2C driver for Nokia Internet Tablets.
+ *
+ * Copyright (C) 2004-2010 Nokia Corporation
+ *
+ * Based on code written by Juha Yrjölä, David Weinehall, Mikko Ylinen and
+ * Felipe Balbi. Converted to I2C driver by Aaro Koskinen.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-cbus-gpio.h>
+
+/*
+ * Bit counts are derived from Nokia implementation. These should be checked
+ * if other CBUS implementations appear.
+ */
+#define CBUS_ADDR_BITS 3
+#define CBUS_REG_BITS 5
+
+struct cbus_host {
+ spinlock_t lock; /* host lock */
+ struct device *dev;
+ int clk_gpio;
+ int dat_gpio;
+ int sel_gpio;
+};
+
+/**
+ * cbus_send_bit - sends one bit over the bus
+ * @host: the host we're using
+ * @bit: one bit of information to send
+ */
+static void cbus_send_bit(struct cbus_host *host, unsigned bit)
+{
+ gpio_set_value(host->dat_gpio, bit ? 1 : 0);
+ gpio_set_value(host->clk_gpio, 1);
+ gpio_set_value(host->clk_gpio, 0);
+}
+
+/**
+ * cbus_send_data - sends @len amount of data over the bus
+ * @host: the host we're using
+ * @data: the data to send
+ * @len: size of the transfer
+ */
+static void cbus_send_data(struct cbus_host *host, unsigned data, unsigned len)
+{
+ int i;
+
+ for (i = len; i > 0; i--)
+ cbus_send_bit(host, data & (1 << (i - 1)));
+}
+
+/**
+ * cbus_receive_bit - receives one bit from the bus
+ * @host: the host we're using
+ */
+static int cbus_receive_bit(struct cbus_host *host)
+{
+ int ret;
+
+ gpio_set_value(host->clk_gpio, 1);
+ ret = gpio_get_value(host->dat_gpio);
+ gpio_set_value(host->clk_gpio, 0);
+ return ret;
+}
+
+/**
+ * cbus_receive_word - receives 16-bit word from the bus
+ * @host: the host we're using
+ */
+static int cbus_receive_word(struct cbus_host *host)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 16; i > 0; i--) {
+ int bit = cbus_receive_bit(host);
+
+ if (bit < 0)
+ return bit;
+
+ if (bit)
+ ret |= 1 << (i - 1);
+ }
+ return ret;
+}
+
+/**
+ * cbus_transfer - transfers data over the bus
+ * @host: the host we're using
+ * @rw: read/write flag
+ * @dev: device address
+ * @reg: register address
+ * @data: if @rw == I2C_SBUS_WRITE data to send otherwise 0
+ */
+static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
+ unsigned reg, unsigned data)
+{
+ unsigned long flags;
+ int ret;
+
+ /* We don't want interrupts disturbing our transfer */
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Reset state and start of transfer, SEL stays down during transfer */
+ gpio_set_value(host->sel_gpio, 0);
+
+ /* Set the DAT pin to output */
+ gpio_direction_output(host->dat_gpio, 1);
+
+ /* Send the device address */
+ cbus_send_data(host, dev, CBUS_ADDR_BITS);
+
+ /* Send the rw flag */
+ cbus_send_bit(host, rw == I2C_SMBUS_READ);
+
+ /* Send the register address */
+ cbus_send_data(host, reg, CBUS_REG_BITS);
+
+ if (rw == I2C_SMBUS_WRITE) {
+ cbus_send_data(host, data, 16);
+ ret = 0;
+ } else {
+ ret = gpio_direction_input(host->dat_gpio);
+ if (ret) {
+ dev_dbg(host->dev, "failed setting direction\n");
+ goto out;
+ }
+ gpio_set_value(host->clk_gpio, 1);
+
+ ret = cbus_receive_word(host);
+ if (ret < 0) {
+ dev_dbg(host->dev, "failed receiving data\n");
+ goto out;
+ }
+ }
+
+ /* Indicate end of transfer, SEL goes up until next transfer */
+ gpio_set_value(host->sel_gpio, 1);
+ gpio_set_value(host->clk_gpio, 1);
+ gpio_set_value(host->clk_gpio, 0);
+
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return ret;
+}
+
+static int cbus_i2c_smbus_xfer(struct i2c_adapter *adapter,
+ u16 addr,
+ unsigned short flags,
+ char read_write,
+ u8 command,
+ int size,
+ union i2c_smbus_data *data)
+{
+ struct cbus_host *chost = i2c_get_adapdata(adapter);
+ int ret;
+
+ if (size != I2C_SMBUS_WORD_DATA)
+ return -EINVAL;
+
+ ret = cbus_transfer(chost, read_write == I2C_SMBUS_READ, addr,
+ command, data->word);
+ if (ret < 0)
+ return ret;
+
+ if (read_write == I2C_SMBUS_READ)
+ data->word = ret;
+
+ return 0;
+}
+
+static u32 cbus_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
+}
+
+static const struct i2c_algorithm cbus_i2c_algo = {
+ .smbus_xfer = cbus_i2c_smbus_xfer,
+ .functionality = cbus_i2c_func,
+};
+
+static int cbus_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(adapter);
+
+ return 0;
+}
+
+static int cbus_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct cbus_host *chost;
+ int ret;
+
+ adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
+ GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ chost = devm_kzalloc(&pdev->dev, sizeof(*chost), GFP_KERNEL);
+ if (!chost)
+ return -ENOMEM;
+
+ if (pdev->dev.of_node) {
+ struct device_node *dnode = pdev->dev.of_node;
+ if (of_gpio_count(dnode) != 3)
+ return -ENODEV;
+ chost->clk_gpio = of_get_gpio(dnode, 0);
+ chost->dat_gpio = of_get_gpio(dnode, 1);
+ chost->sel_gpio = of_get_gpio(dnode, 2);
+ } else if (dev_get_platdata(&pdev->dev)) {
+ struct i2c_cbus_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ chost->clk_gpio = pdata->clk_gpio;
+ chost->dat_gpio = pdata->dat_gpio;
+ chost->sel_gpio = pdata->sel_gpio;
+ } else {
+ return -ENODEV;
+ }
+
+ 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;
+ strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name));
+
+ spin_lock_init(&chost->lock);
+ chost->dev = &pdev->dev;
+
+ ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio,
+ GPIOF_OUT_INIT_LOW, "CBUS clk");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN,
+ "CBUS data");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio,
+ GPIOF_OUT_INIT_HIGH, "CBUS sel");
+ if (ret)
+ return ret;
+
+ i2c_set_adapdata(adapter, chost);
+ platform_set_drvdata(pdev, adapter);
+
+ return i2c_add_numbered_adapter(adapter);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_cbus_dt_ids[] = {
+ { .compatible = "i2c-cbus-gpio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids);
+#endif
+
+static struct platform_driver cbus_i2c_driver = {
+ .probe = cbus_i2c_probe,
+ .remove = cbus_i2c_remove,
+ .driver = {
+ .name = "i2c-cbus-gpio",
+ .of_match_table = of_match_ptr(i2c_cbus_dt_ids),
+ },
+};
+module_platform_driver(cbus_i2c_driver);
+
+MODULE_ALIAS("platform:i2c-cbus-gpio");
+MODULE_DESCRIPTION("CBUS I2C driver");
+MODULE_AUTHOR("Juha Yrjölä");
+MODULE_AUTHOR("David Weinehall");
+MODULE_AUTHOR("Mikko Ylinen");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c
new file mode 100644
index 000000000..f890af67f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cht-wc.c
@@ -0,0 +1,447 @@
+/*
+ * Intel CHT Whiskey Cove PMIC I2C Master driver
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
+ * Copyright (C) 2011 - 2014 Intel Corporation. All rights reserved.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power/bq24190_charger.h>
+#include <linux/slab.h>
+
+#define CHT_WC_I2C_CTRL 0x5e24
+#define CHT_WC_I2C_CTRL_WR BIT(0)
+#define CHT_WC_I2C_CTRL_RD BIT(1)
+#define CHT_WC_I2C_CLIENT_ADDR 0x5e25
+#define CHT_WC_I2C_REG_OFFSET 0x5e26
+#define CHT_WC_I2C_WRDATA 0x5e27
+#define CHT_WC_I2C_RDDATA 0x5e28
+
+#define CHT_WC_EXTCHGRIRQ 0x6e0a
+#define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ BIT(0)
+#define CHT_WC_EXTCHGRIRQ_WRITE_IRQ BIT(1)
+#define CHT_WC_EXTCHGRIRQ_READ_IRQ BIT(2)
+#define CHT_WC_EXTCHGRIRQ_NACK_IRQ BIT(3)
+#define CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK ((u8)GENMASK(3, 1))
+#define CHT_WC_EXTCHGRIRQ_MSK 0x6e17
+
+struct cht_wc_i2c_adap {
+ struct i2c_adapter adapter;
+ wait_queue_head_t wait;
+ struct irq_chip irqchip;
+ struct mutex adap_lock;
+ struct mutex irqchip_lock;
+ struct regmap *regmap;
+ struct irq_domain *irq_domain;
+ struct i2c_client *client;
+ int client_irq;
+ u8 irq_mask;
+ u8 old_irq_mask;
+ int read_data;
+ bool io_error;
+ bool done;
+};
+
+static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data)
+{
+ struct cht_wc_i2c_adap *adap = data;
+ int ret, reg;
+
+ mutex_lock(&adap->adap_lock);
+
+ /* Read IRQs */
+ ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, &reg);
+ if (ret) {
+ dev_err(&adap->adapter.dev, "Error reading extchgrirq reg\n");
+ mutex_unlock(&adap->adap_lock);
+ return IRQ_NONE;
+ }
+
+ reg &= ~adap->irq_mask;
+
+ /* Reads must be acked after reading the received data. */
+ ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, &adap->read_data);
+ if (ret)
+ adap->io_error = true;
+
+ /*
+ * Immediately ack IRQs, so that if new IRQs arrives while we're
+ * handling the previous ones our irq will re-trigger when we're done.
+ */
+ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg);
+ if (ret)
+ dev_err(&adap->adapter.dev, "Error writing extchgrirq reg\n");
+
+ if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK) {
+ adap->io_error |= !!(reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ);
+ adap->done = true;
+ }
+
+ mutex_unlock(&adap->adap_lock);
+
+ if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK)
+ wake_up(&adap->wait);
+
+ /*
+ * Do NOT use handle_nested_irq here, the client irq handler will
+ * likely want to do i2c transfers and the i2c controller uses this
+ * interrupt handler as well, so running the client irq handler from
+ * this thread will cause things to lock up.
+ */
+ if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) {
+ /*
+ * generic_handle_irq expects local IRQs to be disabled
+ * as normally it is called from interrupt context.
+ */
+ local_irq_disable();
+ generic_handle_irq(adap->client_irq);
+ local_irq_enable();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap)
+{
+ /* This i2c adapter only supports SMBUS byte transfers */
+ return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap);
+ int ret;
+
+ mutex_lock(&adap->adap_lock);
+ adap->io_error = false;
+ adap->done = false;
+ mutex_unlock(&adap->adap_lock);
+
+ ret = regmap_write(adap->regmap, CHT_WC_I2C_CLIENT_ADDR, addr);
+ if (ret)
+ return ret;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ ret = regmap_write(adap->regmap, CHT_WC_I2C_WRDATA, data->byte);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_write(adap->regmap, CHT_WC_I2C_REG_OFFSET, command);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(adap->regmap, CHT_WC_I2C_CTRL,
+ (read_write == I2C_SMBUS_WRITE) ?
+ CHT_WC_I2C_CTRL_WR : CHT_WC_I2C_CTRL_RD);
+ if (ret)
+ return ret;
+
+ ret = wait_event_timeout(adap->wait, adap->done, msecs_to_jiffies(30));
+ if (ret == 0) {
+ /*
+ * The CHT GPIO controller serializes all IRQs, sometimes
+ * causing significant delays, check status manually.
+ */
+ cht_wc_i2c_adap_thread_handler(0, adap);
+ if (!adap->done)
+ return -ETIMEDOUT;
+ }
+
+ ret = 0;
+ mutex_lock(&adap->adap_lock);
+ if (adap->io_error)
+ ret = -EIO;
+ else if (read_write == I2C_SMBUS_READ)
+ data->byte = adap->read_data;
+ mutex_unlock(&adap->adap_lock);
+
+ return ret;
+}
+
+static const struct i2c_algorithm cht_wc_i2c_adap_algo = {
+ .functionality = cht_wc_i2c_adap_master_func,
+ .smbus_xfer = cht_wc_i2c_adap_smbus_xfer,
+};
+
+/*
+ * We are an i2c-adapter which itself is part of an i2c-client. This means that
+ * transfers done through us take adapter->bus_lock twice, once for our parent
+ * i2c-adapter and once to take our own bus_lock. Lockdep does not like this
+ * nested locking, to make lockdep happy in the case of busses with muxes, the
+ * i2c-core's i2c_adapter_lock_bus function calls:
+ * rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
+ *
+ * But i2c_adapter_depth only works when the direct parent of the adapter is
+ * another adapter, as it is only meant for muxes. In our case there is an
+ * i2c-client and MFD instantiated platform_device in the parent->child chain
+ * between the 2 devices.
+ *
+ * So we override the default i2c_lock_operations and pass a hardcoded
+ * depth of 1 to rt_mutex_lock_nested, to make lockdep happy.
+ *
+ * Note that if there were to be a mux attached to our adapter, this would
+ * break things again since the i2c-mux code expects the root-adapter to have
+ * a locking depth of 0. But we always have only 1 client directly attached
+ * in the form of the Charger IC paired with the CHT Whiskey Cove PMIC.
+ */
+static void cht_wc_i2c_adap_lock_bus(struct i2c_adapter *adapter,
+ unsigned int flags)
+{
+ rt_mutex_lock_nested(&adapter->bus_lock, 1);
+}
+
+static int cht_wc_i2c_adap_trylock_bus(struct i2c_adapter *adapter,
+ unsigned int flags)
+{
+ return rt_mutex_trylock(&adapter->bus_lock);
+}
+
+static void cht_wc_i2c_adap_unlock_bus(struct i2c_adapter *adapter,
+ unsigned int flags)
+{
+ rt_mutex_unlock(&adapter->bus_lock);
+}
+
+static const struct i2c_lock_operations cht_wc_i2c_adap_lock_ops = {
+ .lock_bus = cht_wc_i2c_adap_lock_bus,
+ .trylock_bus = cht_wc_i2c_adap_trylock_bus,
+ .unlock_bus = cht_wc_i2c_adap_unlock_bus,
+};
+
+/**** irqchip for the client connected to the extchgr i2c adapter ****/
+static void cht_wc_i2c_irq_lock(struct irq_data *data)
+{
+ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&adap->irqchip_lock);
+}
+
+static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data)
+{
+ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+ int ret;
+
+ if (adap->irq_mask != adap->old_irq_mask) {
+ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK,
+ adap->irq_mask);
+ if (ret == 0)
+ adap->old_irq_mask = adap->irq_mask;
+ else
+ dev_err(&adap->adapter.dev, "Error writing EXTCHGRIRQ_MSK\n");
+ }
+
+ mutex_unlock(&adap->irqchip_lock);
+}
+
+static void cht_wc_i2c_irq_enable(struct irq_data *data)
+{
+ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+
+ adap->irq_mask &= ~CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
+}
+
+static void cht_wc_i2c_irq_disable(struct irq_data *data)
+{
+ struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+
+ adap->irq_mask |= CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
+}
+
+static const struct irq_chip cht_wc_i2c_irq_chip = {
+ .irq_bus_lock = cht_wc_i2c_irq_lock,
+ .irq_bus_sync_unlock = cht_wc_i2c_irq_sync_unlock,
+ .irq_disable = cht_wc_i2c_irq_disable,
+ .irq_enable = cht_wc_i2c_irq_enable,
+ .name = "cht_wc_ext_chrg_irq_chip",
+};
+
+static const char * const bq24190_suppliers[] = {
+ "tcpm-source-psy-i2c-fusb302" };
+
+static const struct property_entry bq24190_props[] = {
+ PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers),
+ PROPERTY_ENTRY_BOOL("omit-battery-class"),
+ PROPERTY_ENTRY_BOOL("disable-reset"),
+ { }
+};
+
+static struct regulator_consumer_supply fusb302_consumer = {
+ .supply = "vbus",
+ /* Must match fusb302 dev_name in intel_cht_int33fe.c */
+ .dev_name = "i2c-fusb302",
+};
+
+static const struct regulator_init_data bq24190_vbus_init_data = {
+ .constraints = {
+ /* The name is used in intel_cht_int33fe.c do not change. */
+ .name = "cht_wc_usb_typec_vbus",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = &fusb302_consumer,
+ .num_consumer_supplies = 1,
+};
+
+static struct bq24190_platform_data bq24190_pdata = {
+ .regulator_init_data = &bq24190_vbus_init_data,
+};
+
+static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
+{
+ struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+ struct cht_wc_i2c_adap *adap;
+ struct i2c_board_info board_info = {
+ .type = "bq24190",
+ .addr = 0x6b,
+ .dev_name = "bq24190",
+ .properties = bq24190_props,
+ .platform_data = &bq24190_pdata,
+ };
+ int ret, reg, irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Error missing irq resource\n");
+ return -EINVAL;
+ }
+
+ adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL);
+ if (!adap)
+ return -ENOMEM;
+
+ init_waitqueue_head(&adap->wait);
+ mutex_init(&adap->adap_lock);
+ mutex_init(&adap->irqchip_lock);
+ adap->irqchip = cht_wc_i2c_irq_chip;
+ adap->regmap = pmic->regmap;
+ adap->adapter.owner = THIS_MODULE;
+ adap->adapter.class = I2C_CLASS_HWMON;
+ adap->adapter.algo = &cht_wc_i2c_adap_algo;
+ adap->adapter.lock_ops = &cht_wc_i2c_adap_lock_ops;
+ strlcpy(adap->adapter.name, "PMIC I2C Adapter",
+ sizeof(adap->adapter.name));
+ adap->adapter.dev.parent = &pdev->dev;
+
+ /* Clear and activate i2c-adapter interrupts, disable client IRQ */
+ adap->old_irq_mask = adap->irq_mask = ~CHT_WC_EXTCHGRIRQ_ADAP_IRQMASK;
+
+ ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, &reg);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, ~adap->irq_mask);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK, adap->irq_mask);
+ if (ret)
+ return ret;
+
+ /* Alloc and register client IRQ */
+ adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1,
+ &irq_domain_simple_ops, NULL);
+ if (!adap->irq_domain)
+ return -ENOMEM;
+
+ adap->client_irq = irq_create_mapping(adap->irq_domain, 0);
+ if (!adap->client_irq) {
+ ret = -ENOMEM;
+ goto remove_irq_domain;
+ }
+
+ irq_set_chip_data(adap->client_irq, adap);
+ irq_set_chip_and_handler(adap->client_irq, &adap->irqchip,
+ handle_simple_irq);
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ cht_wc_i2c_adap_thread_handler,
+ IRQF_ONESHOT, "PMIC I2C Adapter", adap);
+ if (ret)
+ goto remove_irq_domain;
+
+ i2c_set_adapdata(&adap->adapter, adap);
+ ret = i2c_add_adapter(&adap->adapter);
+ if (ret)
+ goto remove_irq_domain;
+
+ /*
+ * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger,
+ * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302
+ * USB Type-C controller connected to another i2c bus. In this setup
+ * the max17047 and fusb302 devices are enumerated through an INT33FE
+ * ACPI device. If this device is present register an i2c-client for
+ * the TI bq24292i charger.
+ */
+ if (acpi_dev_present("INT33FE", NULL, -1)) {
+ board_info.irq = adap->client_irq;
+ adap->client = i2c_new_device(&adap->adapter, &board_info);
+ if (!adap->client) {
+ ret = -ENOMEM;
+ goto del_adapter;
+ }
+ }
+
+ platform_set_drvdata(pdev, adap);
+ return 0;
+
+del_adapter:
+ i2c_del_adapter(&adap->adapter);
+remove_irq_domain:
+ irq_domain_remove(adap->irq_domain);
+ return ret;
+}
+
+static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
+{
+ struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev);
+
+ if (adap->client)
+ i2c_unregister_device(adap->client);
+ i2c_del_adapter(&adap->adapter);
+ irq_domain_remove(adap->irq_domain);
+
+ return 0;
+}
+
+static const struct platform_device_id cht_wc_i2c_adap_id_table[] = {
+ { .name = "cht_wcove_ext_chgr" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table);
+
+static struct platform_driver cht_wc_i2c_adap_driver = {
+ .probe = cht_wc_i2c_adap_i2c_probe,
+ .remove = cht_wc_i2c_adap_i2c_remove,
+ .driver = {
+ .name = "cht_wcove_ext_chgr",
+ },
+ .id_table = cht_wc_i2c_adap_id_table,
+};
+module_platform_driver(cht_wc_i2c_adap_driver);
+
+MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C Master driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
new file mode 100644
index 000000000..7eba874a9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -0,0 +1,724 @@
+/*
+ * Freescale CPM1/CPM2 I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * Parts from dbox2_i2c.c (cvs.tuxbox.org)
+ * (C) 2000-2001 Felix Domke (tmbinc@gmx.net), Gillem (htoa@gmx.net)
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ *
+ * Converted to of_platform_device. Renamed to i2c-cpm.c.
+ * (C) 2007,2008 Jochen Friedrich <jochen@scram.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+
+/* Try to define this if you have an older CPU (earlier than rev D4) */
+/* However, better use a GPIO based bitbang driver in this case :/ */
+#undef I2C_CHIP_ERRATA
+
+#define CPM_MAX_READ 513
+#define CPM_MAXBD 4
+
+#define I2C_EB (0x10) /* Big endian mode */
+#define I2C_EB_CPM2 (0x30) /* Big endian mode, memory snoop */
+
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0))
+
+/* I2C parameter RAM. */
+struct i2c_ram {
+ ushort rbase; /* Rx Buffer descriptor base address */
+ ushort tbase; /* Tx Buffer descriptor base address */
+ u_char rfcr; /* Rx function code */
+ u_char tfcr; /* Tx function code */
+ ushort mrblr; /* Max receive buffer length */
+ uint rstate; /* Internal */
+ uint rdp; /* Internal */
+ ushort rbptr; /* Rx Buffer descriptor pointer */
+ ushort rbc; /* Internal */
+ uint rxtmp; /* Internal */
+ uint tstate; /* Internal */
+ uint tdp; /* Internal */
+ ushort tbptr; /* Tx Buffer descriptor pointer */
+ ushort tbc; /* Internal */
+ uint txtmp; /* Internal */
+ char res1[4]; /* Reserved */
+ ushort rpbase; /* Relocation pointer */
+ char res2[2]; /* Reserved */
+ /* The following elements are only for CPM2 */
+ char res3[4]; /* Reserved */
+ uint sdmatmp; /* Internal */
+};
+
+#define I2COM_START 0x80
+#define I2COM_MASTER 0x01
+#define I2CER_TXE 0x10
+#define I2CER_BUSY 0x04
+#define I2CER_TXB 0x02
+#define I2CER_RXB 0x01
+#define I2MOD_EN 0x01
+
+/* I2C Registers */
+struct i2c_reg {
+ u8 i2mod;
+ u8 res1[3];
+ u8 i2add;
+ u8 res2[3];
+ u8 i2brg;
+ u8 res3[3];
+ u8 i2com;
+ u8 res4[3];
+ u8 i2cer;
+ u8 res5[3];
+ u8 i2cmr;
+};
+
+struct cpm_i2c {
+ char *base;
+ struct platform_device *ofdev;
+ struct i2c_adapter adap;
+ uint dp_addr;
+ int version; /* CPM1=1, CPM2=2 */
+ int irq;
+ int cp_command;
+ int freq;
+ struct i2c_reg __iomem *i2c_reg;
+ struct i2c_ram __iomem *i2c_ram;
+ u16 i2c_addr;
+ wait_queue_head_t i2c_wait;
+ cbd_t __iomem *tbase;
+ cbd_t __iomem *rbase;
+ u_char *txbuf[CPM_MAXBD];
+ u_char *rxbuf[CPM_MAXBD];
+ dma_addr_t txdma[CPM_MAXBD];
+ dma_addr_t rxdma[CPM_MAXBD];
+};
+
+static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
+{
+ struct cpm_i2c *cpm;
+ struct i2c_reg __iomem *i2c_reg;
+ struct i2c_adapter *adap = dev_id;
+ int i;
+
+ cpm = i2c_get_adapdata(dev_id);
+ i2c_reg = cpm->i2c_reg;
+
+ /* Clear interrupt. */
+ i = in_8(&i2c_reg->i2cer);
+ out_8(&i2c_reg->i2cer, i);
+
+ dev_dbg(&adap->dev, "Interrupt: %x\n", i);
+
+ wake_up(&cpm->i2c_wait);
+
+ return i ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void cpm_reset_i2c_params(struct cpm_i2c *cpm)
+{
+ struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+
+ /* Set up the I2C parameters in the parameter ram. */
+ out_be16(&i2c_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE);
+ out_be16(&i2c_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+ if (cpm->version == 1) {
+ out_8(&i2c_ram->tfcr, I2C_EB);
+ out_8(&i2c_ram->rfcr, I2C_EB);
+ } else {
+ out_8(&i2c_ram->tfcr, I2C_EB_CPM2);
+ out_8(&i2c_ram->rfcr, I2C_EB_CPM2);
+ }
+
+ out_be16(&i2c_ram->mrblr, CPM_MAX_READ);
+
+ out_be32(&i2c_ram->rstate, 0);
+ out_be32(&i2c_ram->rdp, 0);
+ out_be16(&i2c_ram->rbptr, 0);
+ out_be16(&i2c_ram->rbc, 0);
+ out_be32(&i2c_ram->rxtmp, 0);
+ out_be32(&i2c_ram->tstate, 0);
+ out_be32(&i2c_ram->tdp, 0);
+ out_be16(&i2c_ram->tbptr, 0);
+ out_be16(&i2c_ram->tbc, 0);
+ out_be32(&i2c_ram->txtmp, 0);
+}
+
+static void cpm_i2c_force_close(struct i2c_adapter *adap)
+{
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+ struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+
+ dev_dbg(&adap->dev, "cpm_i2c_force_close()\n");
+
+ cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD);
+
+ out_8(&i2c_reg->i2cmr, 0x00); /* Disable all interrupts */
+ out_8(&i2c_reg->i2cer, 0xff);
+}
+
+static void cpm_i2c_parse_message(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg, int num, int tx, int rx)
+{
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ u_char addr;
+ u_char *tb;
+ u_char *rb;
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+ tbdf = cpm->tbase + tx;
+ rbdf = cpm->rbase + rx;
+
+ addr = i2c_8bit_addr_from_msg(pmsg);
+
+ tb = cpm->txbuf[tx];
+ rb = cpm->rxbuf[rx];
+
+ /* Align read buffer */
+ rb = (u_char *) (((ulong) rb + 1) & ~1);
+
+ tb[0] = addr; /* Device address byte w/rw flag */
+
+ out_be16(&tbdf->cbd_datlen, pmsg->len + 1);
+ out_be16(&tbdf->cbd_sc, 0);
+
+ if (!(pmsg->flags & I2C_M_NOSTART))
+ setbits16(&tbdf->cbd_sc, BD_I2C_START);
+
+ if (tx + 1 == num)
+ setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP);
+
+ if (pmsg->flags & I2C_M_RD) {
+ /*
+ * To read, we need an empty buffer of the proper length.
+ * All that is used is the first byte for address, the remainder
+ * is just used for timing (and doesn't really have to exist).
+ */
+
+ dev_dbg(&adap->dev, "cpm_i2c_read(abyte=0x%x)\n", addr);
+
+ out_be16(&rbdf->cbd_datlen, 0);
+ out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
+
+ if (rx + 1 == CPM_MAXBD)
+ setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
+
+ eieio();
+ setbits16(&tbdf->cbd_sc, BD_SC_READY);
+ } else {
+ dev_dbg(&adap->dev, "cpm_i2c_write(abyte=0x%x)\n", addr);
+
+ memcpy(tb+1, pmsg->buf, pmsg->len);
+
+ eieio();
+ setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT);
+ }
+}
+
+static int cpm_i2c_check_message(struct i2c_adapter *adap,
+ struct i2c_msg *pmsg, int tx, int rx)
+{
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ u_char *tb;
+ u_char *rb;
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+ tbdf = cpm->tbase + tx;
+ rbdf = cpm->rbase + rx;
+
+ tb = cpm->txbuf[tx];
+ rb = cpm->rxbuf[rx];
+
+ /* Align read buffer */
+ rb = (u_char *) (((uint) rb + 1) & ~1);
+
+ eieio();
+ if (pmsg->flags & I2C_M_RD) {
+ dev_dbg(&adap->dev, "tx sc 0x%04x, rx sc 0x%04x\n",
+ in_be16(&tbdf->cbd_sc), in_be16(&rbdf->cbd_sc));
+
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+ dev_dbg(&adap->dev, "I2C read; No ack\n");
+ return -ENXIO;
+ }
+ if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) {
+ dev_err(&adap->dev,
+ "I2C read; complete but rbuf empty\n");
+ return -EREMOTEIO;
+ }
+ if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) {
+ dev_err(&adap->dev, "I2C read; Overrun\n");
+ return -EREMOTEIO;
+ }
+ memcpy(pmsg->buf, rb, pmsg->len);
+ } else {
+ dev_dbg(&adap->dev, "tx sc %d 0x%04x\n", tx,
+ in_be16(&tbdf->cbd_sc));
+
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+ dev_dbg(&adap->dev, "I2C write; No ack\n");
+ return -ENXIO;
+ }
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
+ dev_err(&adap->dev, "I2C write; Underrun\n");
+ return -EIO;
+ }
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
+ dev_err(&adap->dev, "I2C write; Collision\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+ struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+ struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+ struct i2c_msg *pmsg;
+ int ret;
+ int tptr;
+ int rptr;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+
+ /* Reset to use first buffer */
+ out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
+ out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ tptr = 0;
+ rptr = 0;
+
+ /*
+ * If there was a collision in the last i2c transaction,
+ * Set I2COM_MASTER as it was cleared during collision.
+ */
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
+ out_8(&cpm->i2c_reg->i2com, I2COM_MASTER);
+ }
+
+ while (tptr < num) {
+ pmsg = &msgs[tptr];
+ dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);
+
+ cpm_i2c_parse_message(adap, pmsg, num, tptr, rptr);
+ if (pmsg->flags & I2C_M_RD)
+ rptr++;
+ tptr++;
+ }
+ /* Start transfer now */
+ /* Enable RX/TX/Error interupts */
+ out_8(&i2c_reg->i2cmr, I2CER_TXE | I2CER_TXB | I2CER_RXB);
+ out_8(&i2c_reg->i2cer, 0xff); /* Clear interrupt status */
+ /* Chip bug, set enable here */
+ setbits8(&i2c_reg->i2mod, I2MOD_EN); /* Enable */
+ /* Begin transmission */
+ setbits8(&i2c_reg->i2com, I2COM_START);
+
+ tptr = 0;
+ rptr = 0;
+
+ while (tptr < num) {
+ /* Check for outstanding messages */
+ dev_dbg(&adap->dev, "test ready.\n");
+ pmsg = &msgs[tptr];
+ if (pmsg->flags & I2C_M_RD)
+ ret = wait_event_timeout(cpm->i2c_wait,
+ (in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) ||
+ !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY),
+ 1 * HZ);
+ else
+ ret = wait_event_timeout(cpm->i2c_wait,
+ !(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY),
+ 1 * HZ);
+ if (ret == 0) {
+ ret = -EREMOTEIO;
+ dev_err(&adap->dev, "I2C transfer: timeout\n");
+ goto out_err;
+ }
+ if (ret > 0) {
+ dev_dbg(&adap->dev, "ready.\n");
+ ret = cpm_i2c_check_message(adap, pmsg, tptr, rptr);
+ tptr++;
+ if (pmsg->flags & I2C_M_RD)
+ rptr++;
+ if (ret)
+ goto out_err;
+ }
+ }
+#ifdef I2C_CHIP_ERRATA
+ /*
+ * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+ * Disabling I2C too early may cause too short stop condition
+ */
+ udelay(4);
+ clrbits8(&i2c_reg->i2mod, I2MOD_EN);
+#endif
+ return (num);
+
+out_err:
+ cpm_i2c_force_close(adap);
+#ifdef I2C_CHIP_ERRATA
+ /*
+ * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+ */
+ clrbits8(&i2c_reg->i2mod, I2MOD_EN);
+#endif
+ return ret;
+}
+
+static u32 cpm_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm cpm_i2c_algo = {
+ .master_xfer = cpm_i2c_xfer,
+ .functionality = cpm_i2c_func,
+};
+
+/* CPM_MAX_READ is also limiting writes according to the code! */
+static const struct i2c_adapter_quirks cpm_i2c_quirks = {
+ .max_num_msgs = CPM_MAXBD,
+ .max_read_len = CPM_MAX_READ,
+ .max_write_len = CPM_MAX_READ,
+};
+
+static const struct i2c_adapter cpm_ops = {
+ .owner = THIS_MODULE,
+ .name = "i2c-cpm",
+ .algo = &cpm_i2c_algo,
+ .quirks = &cpm_i2c_quirks,
+};
+
+static int cpm_i2c_setup(struct cpm_i2c *cpm)
+{
+ struct platform_device *ofdev = cpm->ofdev;
+ const u32 *data;
+ int len, ret, i;
+ void __iomem *i2c_base;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+ unsigned char brg;
+
+ dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n");
+
+ init_waitqueue_head(&cpm->i2c_wait);
+
+ cpm->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+ if (!cpm->irq)
+ return -EINVAL;
+
+ /* Install interrupt handler. */
+ ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c",
+ &cpm->adap);
+ if (ret)
+ return ret;
+
+ /* I2C parameter RAM */
+ i2c_base = of_iomap(ofdev->dev.of_node, 1);
+ if (i2c_base == NULL) {
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm1-i2c")) {
+
+ /* Check for and use a microcode relocation patch. */
+ cpm->i2c_ram = i2c_base;
+ cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase);
+
+ /*
+ * Maybe should use cpm_muram_alloc instead of hardcoding
+ * this in micropatch.c
+ */
+ if (cpm->i2c_addr) {
+ cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+ iounmap(i2c_base);
+ }
+
+ cpm->version = 1;
+
+ } else if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm2-i2c")) {
+ cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
+ cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+ out_be16(i2c_base, cpm->i2c_addr);
+ iounmap(i2c_base);
+
+ cpm->version = 2;
+
+ } else {
+ iounmap(i2c_base);
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ /* I2C control/status registers */
+ cpm->i2c_reg = of_iomap(ofdev->dev.of_node, 0);
+ if (cpm->i2c_reg == NULL) {
+ ret = -EINVAL;
+ goto out_ram;
+ }
+
+ data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
+ if (!data || len != 4) {
+ ret = -EINVAL;
+ goto out_reg;
+ }
+ cpm->cp_command = *data;
+
+ data = of_get_property(ofdev->dev.of_node, "linux,i2c-class", &len);
+ if (data && len == 4)
+ cpm->adap.class = *data;
+
+ data = of_get_property(ofdev->dev.of_node, "clock-frequency", &len);
+ if (data && len == 4)
+ cpm->freq = *data;
+ else
+ cpm->freq = 60000; /* use 60kHz i2c clock by default */
+
+ /*
+ * Allocate space for CPM_MAXBD transmit and receive buffer
+ * descriptors in the DP ram.
+ */
+ cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
+ if (!cpm->dp_addr) {
+ ret = -ENOMEM;
+ goto out_reg;
+ }
+
+ cpm->tbase = cpm_muram_addr(cpm->dp_addr);
+ cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
+
+ /* Allocate TX and RX buffers */
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ for (i = 0; i < CPM_MAXBD; i++) {
+ cpm->rxbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
+ CPM_MAX_READ + 1,
+ &cpm->rxdma[i], GFP_KERNEL);
+ if (!cpm->rxbuf[i]) {
+ ret = -ENOMEM;
+ goto out_muram;
+ }
+ out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
+
+ cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+ if (!cpm->txbuf[i]) {
+ ret = -ENOMEM;
+ goto out_muram;
+ }
+ out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
+ }
+
+ /* Initialize Tx/Rx parameters. */
+
+ cpm_reset_i2c_params(cpm);
+
+ dev_dbg(&cpm->ofdev->dev, "i2c_ram 0x%p, i2c_addr 0x%04x, freq %d\n",
+ cpm->i2c_ram, cpm->i2c_addr, cpm->freq);
+ dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
+ (u8 __iomem *)cpm->tbase - DPRAM_BASE,
+ (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+ cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);
+
+ /*
+ * Select an invalid address. Just make sure we don't use loopback mode
+ */
+ out_8(&cpm->i2c_reg->i2add, 0x7f << 1);
+
+ /*
+ * PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the
+ * i2c baud rate generator. This is divided by 2 x (DIV + 3) to get
+ * the actual i2c bus frequency.
+ */
+ brg = get_brgfreq() / (32 * 2 * cpm->freq) - 3;
+ out_8(&cpm->i2c_reg->i2brg, brg);
+
+ out_8(&cpm->i2c_reg->i2mod, 0x00);
+ out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); /* Master mode */
+
+ /* Disable interrupts. */
+ out_8(&cpm->i2c_reg->i2cmr, 0);
+ out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+ return 0;
+
+out_muram:
+ for (i = 0; i < CPM_MAXBD; i++) {
+ if (cpm->rxbuf[i])
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->rxbuf[i], cpm->rxdma[i]);
+ if (cpm->txbuf[i])
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->txbuf[i], cpm->txdma[i]);
+ }
+ cpm_muram_free(cpm->dp_addr);
+out_reg:
+ iounmap(cpm->i2c_reg);
+out_ram:
+ if ((cpm->version == 1) && (!cpm->i2c_addr))
+ iounmap(cpm->i2c_ram);
+ if (cpm->version == 2)
+ cpm_muram_free(cpm->i2c_addr);
+out_irq:
+ free_irq(cpm->irq, &cpm->adap);
+ return ret;
+}
+
+static void cpm_i2c_shutdown(struct cpm_i2c *cpm)
+{
+ int i;
+
+ /* Shut down I2C. */
+ clrbits8(&cpm->i2c_reg->i2mod, I2MOD_EN);
+
+ /* Disable interrupts */
+ out_8(&cpm->i2c_reg->i2cmr, 0);
+ out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+ free_irq(cpm->irq, &cpm->adap);
+
+ /* Free all memory */
+ for (i = 0; i < CPM_MAXBD; i++) {
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->rxbuf[i], cpm->rxdma[i]);
+ dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+ cpm->txbuf[i], cpm->txdma[i]);
+ }
+
+ cpm_muram_free(cpm->dp_addr);
+ iounmap(cpm->i2c_reg);
+
+ if ((cpm->version == 1) && (!cpm->i2c_addr))
+ iounmap(cpm->i2c_ram);
+ if (cpm->version == 2)
+ cpm_muram_free(cpm->i2c_addr);
+}
+
+static int cpm_i2c_probe(struct platform_device *ofdev)
+{
+ int result, len;
+ struct cpm_i2c *cpm;
+ const u32 *data;
+
+ cpm = kzalloc(sizeof(struct cpm_i2c), GFP_KERNEL);
+ if (!cpm)
+ return -ENOMEM;
+
+ cpm->ofdev = ofdev;
+
+ platform_set_drvdata(ofdev, cpm);
+
+ cpm->adap = cpm_ops;
+ i2c_set_adapdata(&cpm->adap, cpm);
+ cpm->adap.dev.parent = &ofdev->dev;
+ cpm->adap.dev.of_node = of_node_get(ofdev->dev.of_node);
+
+ result = cpm_i2c_setup(cpm);
+ if (result) {
+ dev_err(&ofdev->dev, "Unable to init hardware\n");
+ goto out_free;
+ }
+
+ /* register new adapter to i2c module... */
+
+ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len);
+ cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1;
+ result = i2c_add_numbered_adapter(&cpm->adap);
+
+ if (result < 0)
+ goto out_shut;
+
+ dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
+ cpm->adap.name);
+
+ return 0;
+out_shut:
+ cpm_i2c_shutdown(cpm);
+out_free:
+ kfree(cpm);
+
+ return result;
+}
+
+static int cpm_i2c_remove(struct platform_device *ofdev)
+{
+ struct cpm_i2c *cpm = platform_get_drvdata(ofdev);
+
+ i2c_del_adapter(&cpm->adap);
+
+ cpm_i2c_shutdown(cpm);
+
+ kfree(cpm);
+
+ return 0;
+}
+
+static const struct of_device_id cpm_i2c_match[] = {
+ {
+ .compatible = "fsl,cpm1-i2c",
+ },
+ {
+ .compatible = "fsl,cpm2-i2c",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, cpm_i2c_match);
+
+static struct platform_driver cpm_i2c_driver = {
+ .probe = cpm_i2c_probe,
+ .remove = cpm_i2c_remove,
+ .driver = {
+ .name = "fsl-i2c-cpm",
+ .of_match_table = cpm_i2c_match,
+ },
+};
+
+module_platform_driver(cpm_i2c_driver);
+
+MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
new file mode 100644
index 000000000..eb76b76f4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Expose an I2C passthrough to the ChromeOS EC.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define I2C_MAX_RETRIES 3
+
+/**
+ * struct ec_i2c_device - Driver data for I2C tunnel
+ *
+ * @dev: Device node
+ * @adap: I2C adapter
+ * @ec: Pointer to EC device
+ * @remote_bus: The EC bus number we tunnel to on the other side.
+ * @request_buf: Buffer for transmitting data; we expect most transfers to fit.
+ * @response_buf: Buffer for receiving data; we expect most transfers to fit.
+ */
+
+struct ec_i2c_device {
+ struct device *dev;
+ struct i2c_adapter adap;
+ struct cros_ec_device *ec;
+
+ u16 remote_bus;
+
+ u8 request_buf[256];
+ u8 response_buf[256];
+};
+
+/**
+ * ec_i2c_count_message - Count bytes needed for ec_i2c_construct_message
+ *
+ * @i2c_msgs: The i2c messages to read
+ * @num: The number of i2c messages.
+ *
+ * Returns the number of bytes the messages will take up.
+ */
+static int ec_i2c_count_message(const struct i2c_msg i2c_msgs[], int num)
+{
+ int i;
+ int size;
+
+ size = sizeof(struct ec_params_i2c_passthru);
+ size += num * sizeof(struct ec_params_i2c_passthru_msg);
+ for (i = 0; i < num; i++)
+ if (!(i2c_msgs[i].flags & I2C_M_RD))
+ size += i2c_msgs[i].len;
+
+ return size;
+}
+
+/**
+ * ec_i2c_construct_message - construct a message to go to the EC
+ *
+ * This function effectively stuffs the standard i2c_msg format of Linux into
+ * a format that the EC understands.
+ *
+ * @buf: The buffer to fill. We assume that the buffer is big enough.
+ * @i2c_msgs: The i2c messages to read.
+ * @num: The number of i2c messages.
+ * @bus_num: The remote bus number we want to talk to.
+ *
+ * Returns 0 or a negative error number.
+ */
+static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[],
+ int num, u16 bus_num)
+{
+ struct ec_params_i2c_passthru *params;
+ u8 *out_data;
+ int i;
+
+ out_data = buf + sizeof(struct ec_params_i2c_passthru) +
+ num * sizeof(struct ec_params_i2c_passthru_msg);
+
+ params = (struct ec_params_i2c_passthru *)buf;
+ params->port = bus_num;
+ params->num_msgs = num;
+ for (i = 0; i < num; i++) {
+ const struct i2c_msg *i2c_msg = &i2c_msgs[i];
+ struct ec_params_i2c_passthru_msg *msg = &params->msg[i];
+
+ msg->len = i2c_msg->len;
+ msg->addr_flags = i2c_msg->addr;
+
+ if (i2c_msg->flags & I2C_M_TEN)
+ return -EINVAL;
+
+ if (i2c_msg->flags & I2C_M_RD) {
+ msg->addr_flags |= EC_I2C_FLAG_READ;
+ } else {
+ memcpy(out_data, i2c_msg->buf, msg->len);
+ out_data += msg->len;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response
+ *
+ * @i2c_msgs: The i2c messages to to fill up.
+ * @num: The number of i2c messages expected.
+ *
+ * Returns the number of response bytes expeced.
+ */
+static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num)
+{
+ int size;
+ int i;
+
+ size = sizeof(struct ec_response_i2c_passthru);
+ for (i = 0; i < num; i++)
+ if (i2c_msgs[i].flags & I2C_M_RD)
+ size += i2c_msgs[i].len;
+
+ return size;
+}
+
+/**
+ * ec_i2c_parse_response - Parse a response from the EC
+ *
+ * We'll take the EC's response and copy it back into msgs.
+ *
+ * @buf: The buffer to parse.
+ * @i2c_msgs: The i2c messages to to fill up.
+ * @num: The number of i2c messages; will be modified to include the actual
+ * number received.
+ *
+ * Returns 0 or a negative error number.
+ */
+static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[],
+ int *num)
+{
+ const struct ec_response_i2c_passthru *resp;
+ const u8 *in_data;
+ int i;
+
+ in_data = buf + sizeof(struct ec_response_i2c_passthru);
+
+ resp = (const struct ec_response_i2c_passthru *)buf;
+ if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT)
+ return -ETIMEDOUT;
+ else if (resp->i2c_status & EC_I2C_STATUS_NAK)
+ return -ENXIO;
+ else if (resp->i2c_status & EC_I2C_STATUS_ERROR)
+ return -EIO;
+
+ /* Other side could send us back fewer messages, but not more */
+ if (resp->num_msgs > *num)
+ return -EPROTO;
+ *num = resp->num_msgs;
+
+ for (i = 0; i < *num; i++) {
+ struct i2c_msg *i2c_msg = &i2c_msgs[i];
+
+ if (i2c_msgs[i].flags & I2C_M_RD) {
+ memcpy(i2c_msg->buf, in_data, i2c_msg->len);
+ in_data += i2c_msg->len;
+ }
+ }
+
+ return 0;
+}
+
+static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
+ int num)
+{
+ struct ec_i2c_device *bus = adap->algo_data;
+ struct device *dev = bus->dev;
+ const u16 bus_num = bus->remote_bus;
+ int request_len;
+ int response_len;
+ int alloc_size;
+ int result;
+ struct cros_ec_command *msg;
+
+ request_len = ec_i2c_count_message(i2c_msgs, num);
+ if (request_len < 0) {
+ dev_warn(dev, "Error constructing message %d\n", request_len);
+ return request_len;
+ }
+
+ response_len = ec_i2c_count_response(i2c_msgs, num);
+ if (response_len < 0) {
+ /* Unexpected; no errors should come when NULL response */
+ dev_warn(dev, "Error preparing response %d\n", response_len);
+ return response_len;
+ }
+
+ alloc_size = max(request_len, response_len);
+ msg = kmalloc(sizeof(*msg) + alloc_size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ result = ec_i2c_construct_message(msg->data, i2c_msgs, num, bus_num);
+ if (result) {
+ dev_err(dev, "Error constructing EC i2c message %d\n", result);
+ goto exit;
+ }
+
+ msg->version = 0;
+ msg->command = EC_CMD_I2C_PASSTHRU;
+ msg->outsize = request_len;
+ msg->insize = response_len;
+
+ result = cros_ec_cmd_xfer_status(bus->ec, msg);
+ if (result < 0) {
+ dev_err(dev, "Error transferring EC i2c message %d\n", result);
+ goto exit;
+ }
+
+ result = ec_i2c_parse_response(msg->data, i2c_msgs, &num);
+ if (result < 0)
+ goto exit;
+
+ /* Indicate success by saying how many messages were sent */
+ result = num;
+exit:
+ kfree(msg);
+ return result;
+}
+
+static u32 ec_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ec_i2c_algorithm = {
+ .master_xfer = ec_i2c_xfer,
+ .functionality = ec_i2c_functionality,
+};
+
+static int ec_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct ec_i2c_device *bus = NULL;
+ u32 remote_bus;
+ int err;
+
+ if (!ec->cmd_xfer) {
+ dev_err(dev, "Missing sendrecv\n");
+ return -EINVAL;
+ }
+
+ bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
+ if (bus == NULL)
+ return -ENOMEM;
+
+ err = of_property_read_u32(np, "google,remote-bus", &remote_bus);
+ if (err) {
+ dev_err(dev, "Couldn't read remote-bus property\n");
+ return err;
+ }
+ bus->remote_bus = remote_bus;
+
+ bus->ec = ec;
+ bus->dev = dev;
+
+ bus->adap.owner = THIS_MODULE;
+ strlcpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name));
+ bus->adap.algo = &ec_i2c_algorithm;
+ bus->adap.algo_data = bus;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = np;
+ bus->adap.retries = I2C_MAX_RETRIES;
+
+ err = i2c_add_adapter(&bus->adap);
+ if (err)
+ return err;
+ platform_set_drvdata(pdev, bus);
+
+ return err;
+}
+
+static int ec_i2c_remove(struct platform_device *dev)
+{
+ struct ec_i2c_device *bus = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&bus->adap);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id cros_ec_i2c_of_match[] = {
+ { .compatible = "google,cros-ec-i2c-tunnel" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
+#endif
+
+static struct platform_driver ec_i2c_tunnel_driver = {
+ .probe = ec_i2c_probe,
+ .remove = ec_i2c_remove,
+ .driver = {
+ .name = "cros-ec-i2c-tunnel",
+ .of_match_table = of_match_ptr(cros_ec_i2c_of_match),
+ },
+};
+
+module_platform_driver(ec_i2c_tunnel_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EC I2C tunnel driver");
+MODULE_ALIAS("platform:cros-ec-i2c-tunnel");
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 000000000..11caafa0e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,991 @@
+/*
+ * TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ *
+ * Updated by Vinod & Sudhakar Feb 2005
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/i2c-davinci.h>
+#include <linux/pm_runtime.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define DAVINCI_I2C_MAX_TRIES 2
+#define DAVINCI_I2C_OWN_ADDRESS 0x08
+#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_SCD | \
+ DAVINCI_I2C_IMR_ARDY | \
+ DAVINCI_I2C_IMR_NACK | \
+ DAVINCI_I2C_IMR_AL)
+
+#define DAVINCI_I2C_OAR_REG 0x00
+#define DAVINCI_I2C_IMR_REG 0x04
+#define DAVINCI_I2C_STR_REG 0x08
+#define DAVINCI_I2C_CLKL_REG 0x0c
+#define DAVINCI_I2C_CLKH_REG 0x10
+#define DAVINCI_I2C_CNT_REG 0x14
+#define DAVINCI_I2C_DRR_REG 0x18
+#define DAVINCI_I2C_SAR_REG 0x1c
+#define DAVINCI_I2C_DXR_REG 0x20
+#define DAVINCI_I2C_MDR_REG 0x24
+#define DAVINCI_I2C_IVR_REG 0x28
+#define DAVINCI_I2C_EMDR_REG 0x2c
+#define DAVINCI_I2C_PSC_REG 0x30
+#define DAVINCI_I2C_FUNC_REG 0x48
+#define DAVINCI_I2C_DIR_REG 0x4c
+#define DAVINCI_I2C_DIN_REG 0x50
+#define DAVINCI_I2C_DOUT_REG 0x54
+#define DAVINCI_I2C_DSET_REG 0x58
+#define DAVINCI_I2C_DCLR_REG 0x5c
+
+#define DAVINCI_I2C_IVR_AAS 0x07
+#define DAVINCI_I2C_IVR_SCD 0x06
+#define DAVINCI_I2C_IVR_XRDY 0x05
+#define DAVINCI_I2C_IVR_RDR 0x04
+#define DAVINCI_I2C_IVR_ARDY 0x03
+#define DAVINCI_I2C_IVR_NACK 0x02
+#define DAVINCI_I2C_IVR_AL 0x01
+
+#define DAVINCI_I2C_STR_BB BIT(12)
+#define DAVINCI_I2C_STR_RSFULL BIT(11)
+#define DAVINCI_I2C_STR_SCD BIT(5)
+#define DAVINCI_I2C_STR_ARDY BIT(2)
+#define DAVINCI_I2C_STR_NACK BIT(1)
+#define DAVINCI_I2C_STR_AL BIT(0)
+
+#define DAVINCI_I2C_MDR_NACK BIT(15)
+#define DAVINCI_I2C_MDR_STT BIT(13)
+#define DAVINCI_I2C_MDR_STP BIT(11)
+#define DAVINCI_I2C_MDR_MST BIT(10)
+#define DAVINCI_I2C_MDR_TRX BIT(9)
+#define DAVINCI_I2C_MDR_XA BIT(8)
+#define DAVINCI_I2C_MDR_RM BIT(7)
+#define DAVINCI_I2C_MDR_IRS BIT(5)
+
+#define DAVINCI_I2C_IMR_AAS BIT(6)
+#define DAVINCI_I2C_IMR_SCD BIT(5)
+#define DAVINCI_I2C_IMR_XRDY BIT(4)
+#define DAVINCI_I2C_IMR_RRDY BIT(3)
+#define DAVINCI_I2C_IMR_ARDY BIT(2)
+#define DAVINCI_I2C_IMR_NACK BIT(1)
+#define DAVINCI_I2C_IMR_AL BIT(0)
+
+/* set SDA and SCL as GPIO */
+#define DAVINCI_I2C_FUNC_PFUNC0 BIT(0)
+
+/* set SCL as output when used as GPIO*/
+#define DAVINCI_I2C_DIR_PDIR0 BIT(0)
+/* set SDA as output when used as GPIO*/
+#define DAVINCI_I2C_DIR_PDIR1 BIT(1)
+
+/* read SCL GPIO level */
+#define DAVINCI_I2C_DIN_PDIN0 BIT(0)
+/* read SDA GPIO level */
+#define DAVINCI_I2C_DIN_PDIN1 BIT(1)
+
+/*set the SCL GPIO high */
+#define DAVINCI_I2C_DSET_PDSET0 BIT(0)
+/*set the SDA GPIO high */
+#define DAVINCI_I2C_DSET_PDSET1 BIT(1)
+
+/* set the SCL GPIO low */
+#define DAVINCI_I2C_DCLR_PDCLR0 BIT(0)
+/* set the SDA GPIO low */
+#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1)
+
+/* timeout for pm runtime autosuspend */
+#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */
+
+struct davinci_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ int cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ int irq;
+ int stop;
+ u8 terminate;
+ struct i2c_adapter adapter;
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block freq_transition;
+#endif
+ struct davinci_i2c_platform_data *pdata;
+};
+
+/* default platform data to use if not supplied in the platform_device */
+static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = {
+ .bus_freq = 100,
+ .bus_delay = 0,
+};
+
+static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ writew_relaxed(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+ return readw_relaxed(i2c_dev->base + reg);
+}
+
+static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
+ int val)
+{
+ u16 w;
+
+ w = davinci_i2c_read_reg(i2c_dev, DAVINCI_I2C_MDR_REG);
+ if (!val) /* put I2C into reset */
+ w &= ~DAVINCI_I2C_MDR_IRS;
+ else /* take I2C out of reset */
+ w |= DAVINCI_I2C_MDR_IRS;
+
+ davinci_i2c_write_reg(i2c_dev, DAVINCI_I2C_MDR_REG, w);
+}
+
+static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
+{
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
+ u16 psc;
+ u32 clk;
+ u32 d;
+ u32 clkh;
+ u32 clkl;
+ u32 input_clock = clk_get_rate(dev->clk);
+ struct device_node *of_node = dev->dev->of_node;
+
+ /* NOTE: I2C Clock divider programming info
+ * As per I2C specs the following formulas provide prescaler
+ * and low/high divider values
+ * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+ * module clk
+ *
+ * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+ *
+ * Thus,
+ * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+ *
+ * where if PSC == 0, d = 7,
+ * if PSC == 1, d = 6
+ * if PSC > 1 , d = 5
+ *
+ * Note:
+ * d is always 6 on Keystone I2C controller
+ */
+
+ /*
+ * Both Davinci and current Keystone User Guides recommend a value
+ * between 7MHz and 12MHz. In reality 7MHz module clock doesn't
+ * always produce enough margin between SDA and SCL transitions.
+ * Measurements show that the higher the module clock is, the
+ * bigger is the margin, providing more reliable communication.
+ * So we better target for 12MHz.
+ */
+ psc = (input_clock / 12000000) - 1;
+ if ((input_clock / (psc + 1)) > 12000000)
+ psc++; /* better to run under spec than over */
+ d = (psc >= 2) ? 5 : 7 - psc;
+
+ if (of_node && of_device_is_compatible(of_node, "ti,keystone-i2c"))
+ d = 6;
+
+ clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000));
+ /* Avoid driving the bus too fast because of rounding errors above */
+ if (input_clock / (psc + 1) / clk > pdata->bus_freq * 1000)
+ clk++;
+ /*
+ * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at
+ * least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH
+ * to LOW ratio as 1 to 2 is more safe.
+ */
+ if (pdata->bus_freq > 100)
+ clkl = (clk << 1) / 3;
+ else
+ clkl = (clk >> 1);
+ /*
+ * It's not always possible to have 1 to 2 ratio when d=7, so fall back
+ * to minimal possible clkh in this case.
+ *
+ * Note:
+ * CLKH is not allowed to be 0, in this case I2C clock is not generated
+ * at all
+ */
+ if (clk > clkl + d) {
+ clkh = clk - clkl - d;
+ clkl -= d;
+ } else {
+ clkh = 1;
+ clkl = clk - (d << 1);
+ }
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
+
+ dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
+}
+
+/*
+ * This function configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounters any errors.
+ */
+static int i2c_davinci_init(struct davinci_i2c_dev *dev)
+{
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(dev, 0);
+
+ /* compute clock dividers */
+ i2c_davinci_calc_clk_dividers(dev);
+
+ /* Respond at reserved "SMBus Host" slave address" (and zero);
+ * we seem to have no option to not respond...
+ */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, DAVINCI_I2C_OWN_ADDRESS);
+
+ dev_dbg(dev->dev, "PSC = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
+ dev_dbg(dev->dev, "CLKL = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
+ dev_dbg(dev->dev, "CLKH = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
+ dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",
+ pdata->bus_freq, pdata->bus_delay);
+
+
+ /* Take the I2C module out of reset: */
+ davinci_i2c_reset_ctrl(dev, 1);
+
+ /* Enable interrupts */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
+
+ return 0;
+}
+
+/*
+ * This routine does i2c bus recovery by using i2c_generic_scl_recovery
+ * which is provided by I2C Bus recovery infrastructure.
+ */
+static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ /* Disable interrupts */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, 0);
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(dev, 0);
+}
+
+static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ i2c_davinci_init(dev);
+}
+
+static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .prepare_recovery = davinci_i2c_prepare_recovery,
+ .unprepare_recovery = davinci_i2c_unprepare_recovery,
+};
+
+static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ if (val)
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG,
+ DAVINCI_I2C_DSET_PDSET0);
+ else
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG,
+ DAVINCI_I2C_DCLR_PDCLR0);
+}
+
+static int davinci_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int val;
+
+ /* read the state of SCL */
+ val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
+ return val & DAVINCI_I2C_DIN_PDIN0;
+}
+
+static int davinci_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int val;
+
+ /* read the state of SDA */
+ val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
+ return val & DAVINCI_I2C_DIN_PDIN1;
+}
+
+static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ davinci_i2c_prepare_recovery(adap);
+
+ /* SCL output, SDA input */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0);
+
+ /* change to GPIO mode */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG,
+ DAVINCI_I2C_FUNC_PFUNC0);
+}
+
+static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ /* change back to I2C mode */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0);
+
+ davinci_i2c_unprepare_recovery(adap);
+}
+
+static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .set_scl = davinci_i2c_set_scl,
+ .get_scl = davinci_i2c_get_scl,
+ .get_sda = davinci_i2c_get_sda,
+ .prepare_recovery = davinci_i2c_scl_prepare_recovery,
+ .unprepare_recovery = davinci_i2c_scl_unprepare_recovery,
+};
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev)
+{
+ unsigned long timeout = jiffies + dev->adapter.timeout;
+
+ do {
+ if (!(davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) & DAVINCI_I2C_STR_BB))
+ return 0;
+ schedule_timeout_uninterruptible(1);
+ } while (time_before_eq(jiffies, timeout));
+
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ i2c_recover_bus(&dev->adapter);
+
+ /*
+ * if bus is still "busy" here, it's most probably a HW problem like
+ * short-circuit
+ */
+ if (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) & DAVINCI_I2C_STR_BB)
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ struct davinci_i2c_platform_data *pdata = dev->pdata;
+ u32 flag;
+ u16 w;
+ unsigned long time_left;
+
+ if (msg->addr == DAVINCI_I2C_OWN_ADDRESS) {
+ dev_warn(dev->dev, "transfer to own address aborted\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ /* Introduce a delay, required for some boards (e.g Davinci EVM) */
+ if (pdata->bus_delay)
+ udelay(pdata->bus_delay);
+
+ /* set the slave address */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);
+
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+ dev->stop = stop;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
+
+ reinit_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ /* Take I2C out of reset and configure it as master */
+ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST;
+
+ /* if the slave address is ten bit address, enable XA bit */
+ if (msg->flags & I2C_M_TEN)
+ flag |= DAVINCI_I2C_MDR_XA;
+ if (!(msg->flags & I2C_M_RD))
+ flag |= DAVINCI_I2C_MDR_TRX;
+ if (msg->len == 0)
+ flag |= DAVINCI_I2C_MDR_RM;
+
+ /* Enable receive or transmit interrupts */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
+ if (msg->flags & I2C_M_RD)
+ w |= DAVINCI_I2C_IMR_RRDY;
+ else
+ w |= DAVINCI_I2C_IMR_XRDY;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
+
+ dev->terminate = 0;
+
+ /*
+ * Write mode register first as needed for correct behaviour
+ * on OMAP-L138, but don't set STT yet to avoid a race with XRDY
+ * occurring before we have loaded DXR
+ */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+ /*
+ * First byte should be set here, not after interrupt,
+ * because transmit-data-ready interrupt can come before
+ * NACK-interrupt during sending of previous message and
+ * ICDXR may have wrong data
+ * It also saves us one interrupt, slightly faster
+ */
+ if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) {
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++);
+ dev->buf_len--;
+ }
+
+ /* Set STT to begin transmit now DXR is loaded */
+ flag |= DAVINCI_I2C_MDR_STT;
+ if (stop && msg->len != 0)
+ flag |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+ time_left = wait_for_completion_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (!time_left) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_recover_bus(adap);
+ dev->buf_len = 0;
+ return -ETIMEDOUT;
+ }
+ if (dev->buf_len) {
+ /* This should be 0 if all bytes were transferred
+ * or dev->cmd_err denotes an error.
+ */
+ dev_err(dev->dev, "abnormal termination buf_len=%zu\n",
+ dev->buf_len);
+ dev->terminate = 1;
+ wmb();
+ dev->buf_len = 0;
+ return -EREMOTEIO;
+ }
+
+ /* no error */
+ if (likely(!dev->cmd_err))
+ return msg->len;
+
+ /* We have an error */
+ if (dev->cmd_err & DAVINCI_I2C_STR_AL) {
+ i2c_davinci_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return msg->len;
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int ret;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+ ret = pm_runtime_get_sync(dev->dev);
+ if (ret < 0) {
+ dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret);
+ pm_runtime_put_noidle(dev->dev);
+ return ret;
+ }
+
+ ret = i2c_davinci_wait_bus_not_busy(dev);
+ if (ret < 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ goto out;
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num,
+ ret);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = num;
+
+out:
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+
+ return ret;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static void terminate_read(struct davinci_i2c_dev *dev)
+{
+ u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_NACK;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ /* Throw away data */
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG);
+ if (!dev->terminate)
+ dev_err(dev->dev, "RDR IRQ while no data requested\n");
+}
+static void terminate_write(struct davinci_i2c_dev *dev)
+{
+ u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ if (!dev->terminate)
+ dev_dbg(dev->dev, "TDR IRQ while no data to send\n");
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
+{
+ struct davinci_i2c_dev *dev = dev_id;
+ u32 stat;
+ int count = 0;
+ u16 w;
+
+ if (pm_runtime_suspended(dev->dev))
+ return IRQ_NONE;
+
+ while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
+ dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ switch (stat) {
+ case DAVINCI_I2C_IVR_AL:
+ /* Arbitration lost, must retry */
+ dev->cmd_err |= DAVINCI_I2C_STR_AL;
+ dev->buf_len = 0;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_NACK:
+ dev->cmd_err |= DAVINCI_I2C_STR_NACK;
+ dev->buf_len = 0;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_ARDY:
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);
+ if (((dev->buf_len == 0) && (dev->stop != 0)) ||
+ (dev->cmd_err & DAVINCI_I2C_STR_NACK)) {
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_MDR_REG, w);
+ }
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_RDR:
+ if (dev->buf_len) {
+ *dev->buf++ =
+ davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_DRR_REG);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG,
+ DAVINCI_I2C_IMR_RRDY);
+ } else {
+ /* signal can terminate transfer */
+ terminate_read(dev);
+ }
+ break;
+
+ case DAVINCI_I2C_IVR_XRDY:
+ if (dev->buf_len) {
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
+ *dev->buf++);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_IMR_REG);
+ w &= ~DAVINCI_I2C_IMR_XRDY;
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_IMR_REG,
+ w);
+ } else {
+ /* signal can terminate transfer */
+ terminate_write(dev);
+ }
+ break;
+
+ case DAVINCI_I2C_IVR_SCD:
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_SCD);
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_AAS:
+ dev_dbg(dev->dev, "Address as slave interrupt\n");
+ break;
+
+ default:
+ dev_warn(dev->dev, "Unrecognized irq stat %d\n", stat);
+ break;
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct davinci_i2c_dev *dev;
+
+ dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
+
+ i2c_lock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER);
+ if (val == CPUFREQ_PRECHANGE) {
+ davinci_i2c_reset_ctrl(dev, 0);
+ } else if (val == CPUFREQ_POSTCHANGE) {
+ i2c_davinci_calc_clk_dividers(dev);
+ davinci_i2c_reset_ctrl(dev, 1);
+ }
+ i2c_unlock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER);
+
+ return 0;
+}
+
+static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
+{
+ dev->freq_transition.notifier_call = i2c_davinci_cpufreq_transition;
+
+ return cpufreq_register_notifier(&dev->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
+{
+ cpufreq_unregister_notifier(&dev->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+#else
+static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
+{
+ return 0;
+}
+
+static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
+{
+}
+#endif
+
+static const struct i2c_algorithm i2c_davinci_algo = {
+ .master_xfer = i2c_davinci_xfer,
+ .functionality = i2c_davinci_func,
+};
+
+static const struct of_device_id davinci_i2c_of_match[] = {
+ {.compatible = "ti,davinci-i2c", },
+ {.compatible = "ti,keystone-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, davinci_i2c_of_match);
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem;
+ struct i2c_bus_recovery_info *rinfo;
+ int r, irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ if (!irq)
+ irq = -ENXIO;
+ if (irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "can't get irq resource ret=%d\n", irq);
+ return irq;
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev),
+ GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ init_completion(&dev->cmd_complete);
+
+ dev->dev = &pdev->dev;
+ dev->irq = irq;
+ dev->pdata = dev_get_platdata(&pdev->dev);
+ platform_set_drvdata(pdev, dev);
+
+ if (!dev->pdata && pdev->dev.of_node) {
+ u32 prop;
+
+ dev->pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct davinci_i2c_platform_data), GFP_KERNEL);
+ if (!dev->pdata)
+ return -ENOMEM;
+
+ memcpy(dev->pdata, &davinci_i2c_platform_data_default,
+ sizeof(struct davinci_i2c_platform_data));
+ if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &prop))
+ dev->pdata->bus_freq = prop / 1000;
+
+ dev->pdata->has_pfunc =
+ of_property_read_bool(pdev->dev.of_node,
+ "ti,has-pfunc");
+ } else if (!dev->pdata) {
+ dev->pdata = &davinci_i2c_platform_data_default;
+ }
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dev->base)) {
+ return PTR_ERR(dev->base);
+ }
+
+ pm_runtime_set_autosuspend_delay(dev->dev,
+ DAVINCI_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev->dev);
+
+ pm_runtime_enable(dev->dev);
+
+ r = pm_runtime_get_sync(dev->dev);
+ if (r < 0) {
+ dev_err(dev->dev, "failed to runtime_get device: %d\n", r);
+ pm_runtime_put_noidle(dev->dev);
+ return r;
+ }
+
+ i2c_davinci_init(dev);
+
+ r = devm_request_irq(&pdev->dev, dev->irq, i2c_davinci_isr, 0,
+ pdev->name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+
+ r = i2c_davinci_cpufreq_register(dev);
+ if (r) {
+ dev_err(&pdev->dev, "failed to register cpufreq\n");
+ goto err_unuse_clocks;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_DEPRECATED;
+ strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+ adap->algo = &i2c_davinci_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->timeout = DAVINCI_I2C_TIMEOUT;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ if (dev->pdata->has_pfunc)
+ adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
+ else if (dev->pdata->gpio_recovery) {
+ rinfo = &davinci_i2c_gpio_recovery_info;
+ adap->bus_recovery_info = rinfo;
+ rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl",
+ GPIOD_OUT_HIGH_OPEN_DRAIN);
+ if (IS_ERR(rinfo->scl_gpiod)) {
+ r = PTR_ERR(rinfo->scl_gpiod);
+ goto err_unuse_clocks;
+ }
+ rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
+ if (IS_ERR(rinfo->sda_gpiod)) {
+ r = PTR_ERR(rinfo->sda_gpiod);
+ goto err_unuse_clocks;
+ }
+ }
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r)
+ goto err_unuse_clocks;
+
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+
+ return 0;
+
+err_unuse_clocks:
+ pm_runtime_dont_use_autosuspend(dev->dev);
+ pm_runtime_put_sync(dev->dev);
+ pm_runtime_disable(dev->dev);
+
+ return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+ int ret;
+
+ i2c_davinci_cpufreq_deregister(dev);
+
+ i2c_del_adapter(&dev->adapter);
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&pdev->dev);
+ return ret;
+ }
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+
+ pm_runtime_dont_use_autosuspend(dev->dev);
+ pm_runtime_put_sync(dev->dev);
+ pm_runtime_disable(dev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int davinci_i2c_suspend(struct device *dev)
+{
+ struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(i2c_dev, 0);
+
+ return 0;
+}
+
+static int davinci_i2c_resume(struct device *dev)
+{
+ struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ /* take I2C out of reset */
+ davinci_i2c_reset_ctrl(i2c_dev, 1);
+
+ return 0;
+}
+
+static const struct dev_pm_ops davinci_i2c_pm = {
+ .suspend = davinci_i2c_suspend,
+ .resume = davinci_i2c_resume,
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+#define davinci_i2c_pm_ops (&davinci_i2c_pm)
+#else
+#define davinci_i2c_pm_ops NULL
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_davinci");
+
+static struct platform_driver davinci_i2c_driver = {
+ .probe = davinci_i2c_probe,
+ .remove = davinci_i2c_remove,
+ .driver = {
+ .name = "i2c_davinci",
+ .pm = davinci_i2c_pm_ops,
+ .of_match_table = davinci_i2c_of_match,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init davinci_i2c_init_driver(void)
+{
+ return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
new file mode 100644
index 000000000..a2a275cfc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel BayTrail PMIC I2C bus semaphore implementaion
+ * Copyright (c) 2014, Intel Corporation.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+
+#include <asm/iosf_mbi.h>
+
+#include "i2c-designware-core.h"
+
+#define SEMAPHORE_TIMEOUT 500
+#define PUNIT_SEMAPHORE 0x7
+#define PUNIT_SEMAPHORE_CHT 0x10e
+#define PUNIT_SEMAPHORE_BIT BIT(0)
+#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
+
+static unsigned long acquired;
+
+static u32 get_sem_addr(struct dw_i2c_dev *dev)
+{
+ if (dev->flags & MODEL_CHERRYTRAIL)
+ return PUNIT_SEMAPHORE_CHT;
+ else
+ return PUNIT_SEMAPHORE;
+}
+
+static int get_sem(struct dw_i2c_dev *dev, u32 *sem)
+{
+ u32 addr = get_sem_addr(dev);
+ u32 data;
+ int ret;
+
+ ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &data);
+ if (ret) {
+ dev_err(dev->dev, "iosf failed to read punit semaphore\n");
+ return ret;
+ }
+
+ *sem = data & PUNIT_SEMAPHORE_BIT;
+
+ return 0;
+}
+
+static void reset_semaphore(struct dw_i2c_dev *dev)
+{
+ if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, get_sem_addr(dev),
+ 0, PUNIT_SEMAPHORE_BIT))
+ dev_err(dev->dev, "iosf failed to reset punit semaphore during write\n");
+
+ pm_qos_update_request(&dev->pm_qos, PM_QOS_DEFAULT_VALUE);
+
+ iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_END,
+ NULL);
+ iosf_mbi_punit_release();
+}
+
+static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+{
+ u32 addr;
+ u32 sem = PUNIT_SEMAPHORE_ACQUIRE;
+ int ret;
+ unsigned long start, end;
+
+ might_sleep();
+
+ if (!dev || !dev->dev)
+ return -ENODEV;
+
+ if (!dev->release_lock)
+ return 0;
+
+ iosf_mbi_punit_acquire();
+ iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_BEGIN,
+ NULL);
+
+ /*
+ * Disallow the CPU to enter C6 or C7 state, entering these states
+ * requires the punit to talk to the pmic and if this happens while
+ * we're holding the semaphore, the SoC hangs.
+ */
+ pm_qos_update_request(&dev->pm_qos, 0);
+
+ addr = get_sem_addr(dev);
+
+ /* host driver writes to side band semaphore register */
+ ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem);
+ if (ret) {
+ dev_err(dev->dev, "iosf punit semaphore request failed\n");
+ goto out;
+ }
+
+ /* host driver waits for bit 0 to be set in semaphore register */
+ start = jiffies;
+ end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
+ do {
+ ret = get_sem(dev, &sem);
+ if (!ret && sem) {
+ acquired = jiffies;
+ dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
+ jiffies_to_msecs(jiffies - start));
+ return 0;
+ }
+
+ usleep_range(1000, 2000);
+ } while (time_before(jiffies, end));
+
+ dev_err(dev->dev, "punit semaphore timed out, resetting\n");
+out:
+ reset_semaphore(dev);
+
+ ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &sem);
+ if (ret)
+ dev_err(dev->dev, "iosf failed to read punit semaphore\n");
+ else
+ dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
+
+ WARN_ON(1);
+
+ return -ETIMEDOUT;
+}
+
+static void baytrail_i2c_release(struct dw_i2c_dev *dev)
+{
+ if (!dev || !dev->dev)
+ return;
+
+ if (!dev->acquire_lock)
+ return;
+
+ reset_semaphore(dev);
+ dev_dbg(dev->dev, "punit semaphore held for %ums\n",
+ jiffies_to_msecs(jiffies - acquired));
+}
+
+int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
+{
+ acpi_status status;
+ unsigned long long shared_host = 0;
+ acpi_handle handle;
+
+ if (!dev || !dev->dev)
+ return 0;
+
+ handle = ACPI_HANDLE(dev->dev);
+ if (!handle)
+ return 0;
+
+ status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ if (!shared_host)
+ return 0;
+
+ if (!iosf_mbi_available())
+ return -EPROBE_DEFER;
+
+ dev_info(dev->dev, "I2C bus managed by PUNIT\n");
+ dev->acquire_lock = baytrail_i2c_acquire;
+ dev->release_lock = baytrail_i2c_release;
+ dev->pm_disabled = true;
+
+ pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ return 0;
+}
+
+void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
+{
+ if (dev->acquire_lock)
+ pm_qos_remove_request(&dev->pm_qos);
+}
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
new file mode 100644
index 000000000..69ec4a791
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Synopsys DesignWare I2C adapter driver.
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/swab.h>
+
+#include "i2c-designware-core.h"
+
+static char *abort_sources[] = {
+ [ABRT_7B_ADDR_NOACK] =
+ "slave address not acknowledged (7bit mode)",
+ [ABRT_10ADDR1_NOACK] =
+ "first address byte not acknowledged (10bit mode)",
+ [ABRT_10ADDR2_NOACK] =
+ "second address byte not acknowledged (10bit mode)",
+ [ABRT_TXDATA_NOACK] =
+ "data not acknowledged",
+ [ABRT_GCALL_NOACK] =
+ "no acknowledgement for a general call",
+ [ABRT_GCALL_READ] =
+ "read after general call",
+ [ABRT_SBYTE_ACKDET] =
+ "start byte acknowledged",
+ [ABRT_SBYTE_NORSTRT] =
+ "trying to send start byte when restart is disabled",
+ [ABRT_10B_RD_NORSTRT] =
+ "trying to read when restart is disabled (10bit mode)",
+ [ABRT_MASTER_DIS] =
+ "trying to use disabled adapter",
+ [ARB_LOST] =
+ "lost arbitration",
+ [ABRT_SLAVE_FLUSH_TXFIFO] =
+ "read command so flush old data in the TX FIFO",
+ [ABRT_SLAVE_ARBLOST] =
+ "slave lost the bus while transmitting data to a remote master",
+ [ABRT_SLAVE_RD_INTX] =
+ "incorrect slave-transmitter mode configuration",
+};
+
+u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+{
+ u32 value;
+
+ if (dev->flags & ACCESS_16BIT)
+ value = readw_relaxed(dev->base + offset) |
+ (readw_relaxed(dev->base + offset + 2) << 16);
+ else
+ value = readl_relaxed(dev->base + offset);
+
+ if (dev->flags & ACCESS_SWAP)
+ return swab32(value);
+ else
+ return value;
+}
+
+void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+{
+ if (dev->flags & ACCESS_SWAP)
+ b = swab32(b);
+
+ if (dev->flags & ACCESS_16BIT) {
+ writew_relaxed((u16)b, dev->base + offset);
+ writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
+ } else {
+ writel_relaxed(b, dev->base + offset);
+ }
+}
+
+/**
+ * i2c_dw_set_reg_access() - Set register access flags
+ * @dev: device private data
+ *
+ * Autodetects needed register access mode and sets access flags accordingly.
+ * This must be called before doing any other register access.
+ */
+int i2c_dw_set_reg_access(struct dw_i2c_dev *dev)
+{
+ u32 reg;
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ reg = dw_readl(dev, DW_IC_COMP_TYPE);
+ i2c_dw_release_lock(dev);
+
+ if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
+ /* Configure register endianess access */
+ dev->flags |= ACCESS_SWAP;
+ } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
+ /* Configure register access mode 16bit */
+ dev->flags |= ACCESS_16BIT;
+ } else if (reg != DW_IC_COMP_TYPE_VALUE) {
+ dev_err(dev->dev,
+ "Unknown Synopsys component type: 0x%08x\n", reg);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
+{
+ /*
+ * DesignWare I2C core doesn't seem to have solid strategy to meet
+ * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
+ * will result in violation of the tHD;STA spec.
+ */
+ if (cond)
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
+ *
+ * This is based on the DW manuals, and represents an ideal
+ * configuration. The resulting I2C bus speed will be
+ * faster than any of the others.
+ *
+ * If your hardware is free from tHD;STA issue, try this one.
+ */
+ return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
+ else
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
+ *
+ * This is just experimental rule; the tHD;STA period turned
+ * out to be proportinal to (_HCNT + 3). With this setting,
+ * we could meet both tHIGH and tHD;STA timing specs.
+ *
+ * If unsure, you'd better to take this alternative.
+ *
+ * The reason why we need to take into account "tf" here,
+ * is the same as described in i2c_dw_scl_lcnt().
+ */
+ return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
+ - 3 + offset;
+}
+
+u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+{
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
+ *
+ * DW I2C core starts counting the SCL CNTs for the LOW period
+ * of the SCL clock (tLOW) as soon as it pulls the SCL line.
+ * In order to meet the tLOW timing spec, we need to take into
+ * account the fall time of SCL signal (tf). Default tf value
+ * should be 0.3 us, for safety.
+ */
+ return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
+}
+
+int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
+{
+ u32 reg;
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ /* Configure SDA Hold Time if required */
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
+ if (!dev->sda_hold_time) {
+ /* Keep previous hold time setting if no one set it */
+ dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
+ }
+
+ /*
+ * Workaround for avoiding TX arbitration lost in case I2C
+ * slave pulls SDA down "too quickly" after falling egde of
+ * SCL by enabling non-zero SDA RX hold. Specification says it
+ * extends incoming SDA low to high transition while SCL is
+ * high but it apprears to help also above issue.
+ */
+ if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
+ dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
+
+ dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
+ dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK,
+ dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT);
+ } else if (dev->sda_hold_time) {
+ dev_warn(dev->dev,
+ "Hardware too old to adjust SDA hold time.\n");
+ dev->sda_hold_time = 0;
+ }
+
+ i2c_dw_release_lock(dev);
+
+ return 0;
+}
+
+void __i2c_dw_disable(struct dw_i2c_dev *dev)
+{
+ int timeout = 100;
+
+ do {
+ __i2c_dw_disable_nowait(dev);
+ /*
+ * The enable status register may be unimplemented, but
+ * in that case this test reads zero and exits the loop.
+ */
+ if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == 0)
+ return;
+
+ /*
+ * Wait 10 times the signaling period of the highest I2C
+ * transfer supported by the driver (for 400KHz this is
+ * 25us) as described in the DesignWare I2C databook.
+ */
+ usleep_range(25, 250);
+ } while (timeout--);
+
+ dev_warn(dev->dev, "timeout in disabling adapter\n");
+}
+
+unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
+{
+ /*
+ * Clock is not necessary if we got LCNT/HCNT values directly from
+ * the platform code.
+ */
+ if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
+ return 0;
+ return dev->get_clk_rate_khz(dev);
+}
+
+int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare)
+{
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ if (prepare)
+ return clk_prepare_enable(dev->clk);
+
+ clk_disable_unprepare(dev->clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk);
+
+int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
+{
+ int ret;
+
+ if (!dev->acquire_lock)
+ return 0;
+
+ ret = dev->acquire_lock(dev);
+ if (!ret)
+ return 0;
+
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+
+ return ret;
+}
+
+void i2c_dw_release_lock(struct dw_i2c_dev *dev)
+{
+ if (dev->release_lock)
+ dev->release_lock(dev);
+}
+
+/*
+ * Waiting for bus not busy
+ */
+int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+{
+ int timeout = TIMEOUT;
+
+ while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
+ if (timeout <= 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ i2c_recover_bus(&dev->adapter);
+
+ if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY)
+ return -ETIMEDOUT;
+ return 0;
+ }
+ timeout--;
+ usleep_range(1000, 1100);
+ }
+
+ return 0;
+}
+
+int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
+{
+ unsigned long abort_source = dev->abort_source;
+ int i;
+
+ if (abort_source & DW_IC_TX_ABRT_NOACK) {
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ dev_dbg(dev->dev,
+ "%s: %s\n", __func__, abort_sources[i]);
+ return -EREMOTEIO;
+ }
+
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
+
+ if (abort_source & DW_IC_TX_ARB_LOST)
+ return -EAGAIN;
+ else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
+ return -EINVAL; /* wrong msgs[] data */
+ else
+ return -EIO;
+}
+
+u32 i2c_dw_func(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ return dev->functionality;
+}
+
+void i2c_dw_disable(struct dw_i2c_dev *dev)
+{
+ /* Disable controller */
+ __i2c_dw_disable(dev);
+
+ /* Disable all interupts */
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ dw_readl(dev, DW_IC_CLR_INTR);
+}
+
+void i2c_dw_disable_int(struct dw_i2c_dev *dev)
+{
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+}
+
+u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
+{
+ return dw_readl(dev, DW_IC_COMP_PARAM_1);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
+
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
new file mode 100644
index 000000000..e367b1af4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -0,0 +1,324 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Synopsys DesignWare I2C adapter driver.
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ */
+
+#include <linux/i2c.h>
+#include <linux/pm_qos.h>
+
+#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
+ I2C_FUNC_SMBUS_BYTE | \
+ I2C_FUNC_SMBUS_BYTE_DATA | \
+ I2C_FUNC_SMBUS_WORD_DATA | \
+ I2C_FUNC_SMBUS_BLOCK_DATA | \
+ I2C_FUNC_SMBUS_I2C_BLOCK)
+
+#define DW_IC_CON_MASTER 0x1
+#define DW_IC_CON_SPEED_STD 0x2
+#define DW_IC_CON_SPEED_FAST 0x4
+#define DW_IC_CON_SPEED_HIGH 0x6
+#define DW_IC_CON_SPEED_MASK 0x6
+#define DW_IC_CON_10BITADDR_SLAVE 0x8
+#define DW_IC_CON_10BITADDR_MASTER 0x10
+#define DW_IC_CON_RESTART_EN 0x20
+#define DW_IC_CON_SLAVE_DISABLE 0x40
+#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80
+#define DW_IC_CON_TX_EMPTY_CTRL 0x100
+#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
+
+/*
+ * Registers offset
+ */
+#define DW_IC_CON 0x0
+#define DW_IC_TAR 0x4
+#define DW_IC_SAR 0x8
+#define DW_IC_DATA_CMD 0x10
+#define DW_IC_SS_SCL_HCNT 0x14
+#define DW_IC_SS_SCL_LCNT 0x18
+#define DW_IC_FS_SCL_HCNT 0x1c
+#define DW_IC_FS_SCL_LCNT 0x20
+#define DW_IC_HS_SCL_HCNT 0x24
+#define DW_IC_HS_SCL_LCNT 0x28
+#define DW_IC_INTR_STAT 0x2c
+#define DW_IC_INTR_MASK 0x30
+#define DW_IC_RAW_INTR_STAT 0x34
+#define DW_IC_RX_TL 0x38
+#define DW_IC_TX_TL 0x3c
+#define DW_IC_CLR_INTR 0x40
+#define DW_IC_CLR_RX_UNDER 0x44
+#define DW_IC_CLR_RX_OVER 0x48
+#define DW_IC_CLR_TX_OVER 0x4c
+#define DW_IC_CLR_RD_REQ 0x50
+#define DW_IC_CLR_TX_ABRT 0x54
+#define DW_IC_CLR_RX_DONE 0x58
+#define DW_IC_CLR_ACTIVITY 0x5c
+#define DW_IC_CLR_STOP_DET 0x60
+#define DW_IC_CLR_START_DET 0x64
+#define DW_IC_CLR_GEN_CALL 0x68
+#define DW_IC_ENABLE 0x6c
+#define DW_IC_STATUS 0x70
+#define DW_IC_TXFLR 0x74
+#define DW_IC_RXFLR 0x78
+#define DW_IC_SDA_HOLD 0x7c
+#define DW_IC_TX_ABRT_SOURCE 0x80
+#define DW_IC_ENABLE_STATUS 0x9c
+#define DW_IC_CLR_RESTART_DET 0xa8
+#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_COMP_VERSION 0xf8
+#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
+#define DW_IC_COMP_TYPE 0xfc
+#define DW_IC_COMP_TYPE_VALUE 0x44570140
+
+#define DW_IC_INTR_RX_UNDER 0x001
+#define DW_IC_INTR_RX_OVER 0x002
+#define DW_IC_INTR_RX_FULL 0x004
+#define DW_IC_INTR_TX_OVER 0x008
+#define DW_IC_INTR_TX_EMPTY 0x010
+#define DW_IC_INTR_RD_REQ 0x020
+#define DW_IC_INTR_TX_ABRT 0x040
+#define DW_IC_INTR_RX_DONE 0x080
+#define DW_IC_INTR_ACTIVITY 0x100
+#define DW_IC_INTR_STOP_DET 0x200
+#define DW_IC_INTR_START_DET 0x400
+#define DW_IC_INTR_GEN_CALL 0x800
+#define DW_IC_INTR_RESTART_DET 0x1000
+
+#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
+ DW_IC_INTR_TX_ABRT | \
+ DW_IC_INTR_STOP_DET)
+#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
+ DW_IC_INTR_TX_EMPTY)
+#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \
+ DW_IC_INTR_RX_DONE | \
+ DW_IC_INTR_RX_UNDER | \
+ DW_IC_INTR_RD_REQ)
+
+#define DW_IC_STATUS_ACTIVITY 0x1
+#define DW_IC_STATUS_TFE BIT(2)
+#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
+#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
+
+#define DW_IC_SDA_HOLD_RX_SHIFT 16
+#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
+
+#define DW_IC_ERR_TX_ABRT 0x1
+
+#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
+
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE 0x0
+#define STATUS_WRITE_IN_PROGRESS 0x1
+#define STATUS_READ_IN_PROGRESS 0x2
+
+#define TIMEOUT 20 /* ms */
+
+/*
+ * operation modes
+ */
+#define DW_IC_MASTER 0
+#define DW_IC_SLAVE 1
+
+/*
+ * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * Only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK 0
+#define ABRT_10ADDR1_NOACK 1
+#define ABRT_10ADDR2_NOACK 2
+#define ABRT_TXDATA_NOACK 3
+#define ABRT_GCALL_NOACK 4
+#define ABRT_GCALL_READ 5
+#define ABRT_SBYTE_ACKDET 7
+#define ABRT_SBYTE_NORSTRT 9
+#define ABRT_10B_RD_NORSTRT 10
+#define ABRT_MASTER_DIS 11
+#define ARB_LOST 12
+#define ABRT_SLAVE_FLUSH_TXFIFO 13
+#define ABRT_SLAVE_ARBLOST 14
+#define ABRT_SLAVE_RD_INTX 15
+
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX)
+#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST)
+#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO)
+
+#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+ DW_IC_TX_ABRT_10ADDR1_NOACK | \
+ DW_IC_TX_ABRT_10ADDR2_NOACK | \
+ DW_IC_TX_ABRT_TXDATA_NOACK | \
+ DW_IC_TX_ABRT_GCALL_NOACK)
+
+
+/**
+ * struct dw_i2c_dev - private i2c-designware data
+ * @dev: driver model device node
+ * @base: IO registers pointer
+ * @cmd_complete: tx completion indicator
+ * @clk: input reference clock
+ * @slave: represent an I2C slave device
+ * @cmd_err: run time hadware error code
+ * @msgs: points to an array of messages currently being transferred
+ * @msgs_num: the number of elements in msgs
+ * @msg_write_idx: the element index of the current tx message in the msgs
+ * array
+ * @tx_buf_len: the length of the current tx buffer
+ * @tx_buf: the current tx buffer
+ * @msg_read_idx: the element index of the current rx message in the msgs
+ * array
+ * @rx_buf_len: the length of the current rx buffer
+ * @rx_buf: the current rx buffer
+ * @msg_err: error status of the current transfer
+ * @status: i2c master status, one of STATUS_*
+ * @abort_source: copy of the TX_ABRT_SOURCE register
+ * @irq: interrupt number for the i2c master
+ * @adapter: i2c subsystem adapter node
+ * @slave_cfg: configuration for the slave device
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
+ * @rx_outstanding: current master-rx elements in tx fifo
+ * @timings: bus clock frequency, SDA hold and other timings
+ * @sda_hold_time: SDA hold value
+ * @ss_hcnt: standard speed HCNT value
+ * @ss_lcnt: standard speed LCNT value
+ * @fs_hcnt: fast speed HCNT value
+ * @fs_lcnt: fast speed LCNT value
+ * @fp_hcnt: fast plus HCNT value
+ * @fp_lcnt: fast plus LCNT value
+ * @hs_hcnt: high speed HCNT value
+ * @hs_lcnt: high speed LCNT value
+ * @pm_qos: pm_qos_request used while holding a hardware lock on the bus
+ * @acquire_lock: function to acquire a hardware lock on the bus
+ * @release_lock: function to release a hardware lock on the bus
+ * @pm_disabled: true if power-management should be disabled for this i2c-bus
+ * @disable: function to disable the controller
+ * @disable_int: function to disable all interrupts
+ * @init: function to initialize the I2C hardware
+ * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
+ *
+ * HCNT and LCNT parameters can be used if the platform knows more accurate
+ * values than the one computed based only on the input clock frequency.
+ * Leave them to be %0 if not used.
+ */
+struct dw_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ struct reset_control *rst;
+ struct i2c_client *slave;
+ u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
+ struct dw_pci_controller *controller;
+ int cmd_err;
+ struct i2c_msg *msgs;
+ int msgs_num;
+ int msg_write_idx;
+ u32 tx_buf_len;
+ u8 *tx_buf;
+ int msg_read_idx;
+ u32 rx_buf_len;
+ u8 *rx_buf;
+ int msg_err;
+ unsigned int status;
+ u32 abort_source;
+ int irq;
+ u32 flags;
+ struct i2c_adapter adapter;
+ u32 functionality;
+ u32 master_cfg;
+ u32 slave_cfg;
+ unsigned int tx_fifo_depth;
+ unsigned int rx_fifo_depth;
+ int rx_outstanding;
+ struct i2c_timings timings;
+ u32 sda_hold_time;
+ u16 ss_hcnt;
+ u16 ss_lcnt;
+ u16 fs_hcnt;
+ u16 fs_lcnt;
+ u16 fp_hcnt;
+ u16 fp_lcnt;
+ u16 hs_hcnt;
+ u16 hs_lcnt;
+ struct pm_qos_request pm_qos;
+ int (*acquire_lock)(struct dw_i2c_dev *dev);
+ void (*release_lock)(struct dw_i2c_dev *dev);
+ bool pm_disabled;
+ void (*disable)(struct dw_i2c_dev *dev);
+ void (*disable_int)(struct dw_i2c_dev *dev);
+ int (*init)(struct dw_i2c_dev *dev);
+ int mode;
+ struct i2c_bus_recovery_info rinfo;
+};
+
+#define ACCESS_SWAP 0x00000001
+#define ACCESS_16BIT 0x00000002
+#define ACCESS_INTR_MASK 0x00000004
+
+#define MODEL_CHERRYTRAIL 0x00000100
+
+u32 dw_readl(struct dw_i2c_dev *dev, int offset);
+void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
+int i2c_dw_set_reg_access(struct dw_i2c_dev *dev);
+u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
+u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
+int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
+unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
+int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
+int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
+void i2c_dw_release_lock(struct dw_i2c_dev *dev);
+int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
+int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
+u32 i2c_dw_func(struct i2c_adapter *adap);
+void i2c_dw_disable(struct dw_i2c_dev *dev);
+void i2c_dw_disable_int(struct dw_i2c_dev *dev);
+
+static inline void __i2c_dw_enable(struct dw_i2c_dev *dev)
+{
+ dw_writel(dev, 1, DW_IC_ENABLE);
+}
+
+static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
+{
+ dw_writel(dev, 0, DW_IC_ENABLE);
+}
+
+void __i2c_dw_disable(struct dw_i2c_dev *dev);
+
+extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
+extern int i2c_dw_probe(struct dw_i2c_dev *dev);
+#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE)
+extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev);
+#else
+static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
+#endif
+
+#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
+extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev);
+extern void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev);
+#else
+static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; }
+static inline void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) {}
+#endif
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
new file mode 100644
index 000000000..18cc324f3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include "i2c-designware-core.h"
+
+static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
+{
+ /* Configure Tx/Rx FIFO threshold levels */
+ dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
+ dw_writel(dev, 0, DW_IC_RX_TL);
+
+ /* Configure the I2C master */
+ dw_writel(dev, dev->master_cfg, DW_IC_CON);
+}
+
+static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
+{
+ const char *mode_str, *fp_str = "";
+ u32 comp_param1;
+ u32 sda_falling_time, scl_falling_time;
+ struct i2c_timings *t = &dev->timings;
+ u32 ic_clk;
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+ comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
+ i2c_dw_release_lock(dev);
+
+ /* Set standard and fast speed dividers for high/low periods */
+ sda_falling_time = t->sda_fall_ns ?: 300; /* ns */
+ scl_falling_time = t->scl_fall_ns ?: 300; /* ns */
+
+ /* Calculate SCL timing parameters for standard mode if not set */
+ if (!dev->ss_hcnt || !dev->ss_lcnt) {
+ ic_clk = i2c_dw_clk_rate(dev);
+ dev->ss_hcnt =
+ i2c_dw_scl_hcnt(ic_clk,
+ 4000, /* tHD;STA = tHIGH = 4.0 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ dev->ss_lcnt =
+ i2c_dw_scl_lcnt(ic_clk,
+ 4700, /* tLOW = 4.7 us */
+ scl_falling_time,
+ 0); /* No offset */
+ }
+ dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n",
+ dev->ss_hcnt, dev->ss_lcnt);
+
+ /*
+ * Set SCL timing parameters for fast mode or fast mode plus. Only
+ * difference is the timing parameter values since the registers are
+ * the same.
+ */
+ if (t->bus_freq_hz == 1000000) {
+ /*
+ * Check are fast mode plus parameters available and use
+ * fast mode if not.
+ */
+ if (dev->fp_hcnt && dev->fp_lcnt) {
+ dev->fs_hcnt = dev->fp_hcnt;
+ dev->fs_lcnt = dev->fp_lcnt;
+ fp_str = " Plus";
+ }
+ }
+ /*
+ * Calculate SCL timing parameters for fast mode if not set. They are
+ * needed also in high speed mode.
+ */
+ if (!dev->fs_hcnt || !dev->fs_lcnt) {
+ ic_clk = i2c_dw_clk_rate(dev);
+ dev->fs_hcnt =
+ i2c_dw_scl_hcnt(ic_clk,
+ 600, /* tHD;STA = tHIGH = 0.6 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ dev->fs_lcnt =
+ i2c_dw_scl_lcnt(ic_clk,
+ 1300, /* tLOW = 1.3 us */
+ scl_falling_time,
+ 0); /* No offset */
+ }
+ dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n",
+ fp_str, dev->fs_hcnt, dev->fs_lcnt);
+
+ /* Check is high speed possible and fall back to fast mode if not */
+ if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==
+ DW_IC_CON_SPEED_HIGH) {
+ if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+ != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
+ dev_err(dev->dev, "High Speed not supported!\n");
+ dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+ dev->hs_hcnt = 0;
+ dev->hs_lcnt = 0;
+ } else if (dev->hs_hcnt && dev->hs_lcnt) {
+ dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n",
+ dev->hs_hcnt, dev->hs_lcnt);
+ }
+ }
+
+ ret = i2c_dw_set_sda_hold(dev);
+ if (ret)
+ goto out;
+
+ switch (dev->master_cfg & DW_IC_CON_SPEED_MASK) {
+ case DW_IC_CON_SPEED_STD:
+ mode_str = "Standard Mode";
+ break;
+ case DW_IC_CON_SPEED_HIGH:
+ mode_str = "High Speed Mode";
+ break;
+ default:
+ mode_str = "Fast Mode";
+ }
+ dev_dbg(dev->dev, "Bus speed: %s%s\n", mode_str, fp_str);
+
+out:
+ return ret;
+}
+
+/**
+ * i2c_dw_init() - Initialize the designware I2C master hardware
+ * @dev: device private data
+ *
+ * This functions configures and enables the I2C master.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+static int i2c_dw_init_master(struct dw_i2c_dev *dev)
+{
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ /* Disable the adapter */
+ __i2c_dw_disable(dev);
+
+ /* Write standard speed timing parameters */
+ dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT);
+ dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT);
+
+ /* Write fast mode/fast mode plus timing parameters */
+ dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT);
+ dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT);
+
+ /* Write high speed timing parameters if supported */
+ if (dev->hs_hcnt && dev->hs_lcnt) {
+ dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT);
+ dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT);
+ }
+
+ /* Write SDA hold time if supported */
+ if (dev->sda_hold_time)
+ dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+
+ i2c_dw_configure_fifo_master(dev);
+ i2c_dw_release_lock(dev);
+
+ return 0;
+}
+
+static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 ic_con, ic_tar = 0;
+
+ /* Disable the adapter */
+ __i2c_dw_disable(dev);
+
+ /* If the slave address is ten bit address, enable 10BITADDR */
+ ic_con = dw_readl(dev, DW_IC_CON);
+ if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
+ ic_con |= DW_IC_CON_10BITADDR_MASTER;
+ /*
+ * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing
+ * mode has to be enabled via bit 12 of IC_TAR register.
+ * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be
+ * detected from registers.
+ */
+ ic_tar = DW_IC_TAR_10BITADDR_MASTER;
+ } else {
+ ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+ }
+
+ dw_writel(dev, ic_con, DW_IC_CON);
+
+ /*
+ * Set the slave (target) address and enable 10-bit addressing mode
+ * if applicable.
+ */
+ dw_writel(dev, msgs[dev->msg_write_idx].addr | ic_tar, DW_IC_TAR);
+
+ /* Enforce disabled interrupts (due to HW issues) */
+ i2c_dw_disable_int(dev);
+
+ /* Enable the adapter */
+ __i2c_dw_enable(dev);
+
+ /* Dummy read to avoid the register getting stuck on Bay Trail */
+ dw_readl(dev, DW_IC_ENABLE_STATUS);
+
+ /* Clear and enable interrupts */
+ dw_readl(dev, DW_IC_CLR_INTR);
+ dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
+}
+
+/*
+ * Initiate (and continue) low level master read/write transaction.
+ * This function is only called from i2c_dw_isr, and pumping i2c_msg
+ * messages into the tx buffer. Even if the size of i2c_msg data is
+ * longer than the size of the tx buffer, it handles everything.
+ */
+static void
+i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 intr_mask;
+ int tx_limit, rx_limit;
+ u32 addr = msgs[dev->msg_write_idx].addr;
+ u32 buf_len = dev->tx_buf_len;
+ u8 *buf = dev->tx_buf;
+ bool need_restart = false;
+
+ intr_mask = DW_IC_INTR_MASTER_MASK;
+
+ for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
+ u32 flags = msgs[dev->msg_write_idx].flags;
+
+ /*
+ * If target address has changed, we need to
+ * reprogram the target address in the I2C
+ * adapter when we are done with this transfer.
+ */
+ if (msgs[dev->msg_write_idx].addr != addr) {
+ dev_err(dev->dev,
+ "%s: invalid target address\n", __func__);
+ dev->msg_err = -EINVAL;
+ break;
+ }
+
+ if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+ /* new i2c_msg */
+ buf = msgs[dev->msg_write_idx].buf;
+ buf_len = msgs[dev->msg_write_idx].len;
+
+ /* If both IC_EMPTYFIFO_HOLD_MASTER_EN and
+ * IC_RESTART_EN are set, we must manually
+ * set restart bit between messages.
+ */
+ if ((dev->master_cfg & DW_IC_CON_RESTART_EN) &&
+ (dev->msg_write_idx > 0))
+ need_restart = true;
+ }
+
+ tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
+ rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+
+ while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
+ u32 cmd = 0;
+
+ /*
+ * If IC_EMPTYFIFO_HOLD_MASTER_EN is set we must
+ * manually set the stop bit. However, it cannot be
+ * detected from the registers so we set it always
+ * when writing/reading the last byte.
+ */
+
+ /*
+ * i2c-core always sets the buffer length of
+ * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
+ * be adjusted when receiving the first byte.
+ * Thus we can't stop the transaction here.
+ */
+ if (dev->msg_write_idx == dev->msgs_num - 1 &&
+ buf_len == 1 && !(flags & I2C_M_RECV_LEN))
+ cmd |= BIT(9);
+
+ if (need_restart) {
+ cmd |= BIT(10);
+ need_restart = false;
+ }
+
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+
+ /* Avoid rx buffer overrun */
+ if (dev->rx_outstanding >= dev->rx_fifo_depth)
+ break;
+
+ dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
+ rx_limit--;
+ dev->rx_outstanding++;
+ } else
+ dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
+ tx_limit--; buf_len--;
+ }
+
+ dev->tx_buf = buf;
+ dev->tx_buf_len = buf_len;
+
+ /*
+ * Because we don't know the buffer length in the
+ * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
+ * the transaction here.
+ */
+ if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
+ /* more bytes to be written */
+ dev->status |= STATUS_WRITE_IN_PROGRESS;
+ break;
+ } else
+ dev->status &= ~STATUS_WRITE_IN_PROGRESS;
+ }
+
+ /*
+ * If i2c_msg index search is completed, we don't need TX_EMPTY
+ * interrupt any more.
+ */
+ if (dev->msg_write_idx == dev->msgs_num)
+ intr_mask &= ~DW_IC_INTR_TX_EMPTY;
+
+ if (dev->msg_err)
+ intr_mask = 0;
+
+ dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
+}
+
+static u8
+i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 flags = msgs[dev->msg_read_idx].flags;
+
+ /*
+ * Adjust the buffer length and mask the flag
+ * after receiving the first byte.
+ */
+ len += (flags & I2C_CLIENT_PEC) ? 2 : 1;
+ dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding);
+ msgs[dev->msg_read_idx].len = len;
+ msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
+
+ return len;
+}
+
+static void
+i2c_dw_read(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ int rx_valid;
+
+ for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
+ u32 len;
+ u8 *buf;
+
+ if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
+ continue;
+
+ if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
+ len = msgs[dev->msg_read_idx].len;
+ buf = msgs[dev->msg_read_idx].buf;
+ } else {
+ len = dev->rx_buf_len;
+ buf = dev->rx_buf;
+ }
+
+ rx_valid = dw_readl(dev, DW_IC_RXFLR);
+
+ for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
+ u32 flags = msgs[dev->msg_read_idx].flags;
+
+ *buf = dw_readl(dev, DW_IC_DATA_CMD);
+ /* Ensure length byte is a valid value */
+ if (flags & I2C_M_RECV_LEN &&
+ *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
+ len = i2c_dw_recv_len(dev, *buf);
+ }
+ buf++;
+ dev->rx_outstanding--;
+ }
+
+ if (len > 0) {
+ dev->status |= STATUS_READ_IN_PROGRESS;
+ dev->rx_buf_len = len;
+ dev->rx_buf = buf;
+ return;
+ } else
+ dev->status &= ~STATUS_READ_IN_PROGRESS;
+ }
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_dw_xfer_msg.
+ */
+static int
+i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ int ret;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+ pm_runtime_get_sync(dev->dev);
+
+ reinit_completion(&dev->cmd_complete);
+ dev->msgs = msgs;
+ dev->msgs_num = num;
+ dev->cmd_err = 0;
+ dev->msg_write_idx = 0;
+ dev->msg_read_idx = 0;
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
+ dev->rx_outstanding = 0;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ goto done_nolock;
+
+ ret = i2c_dw_wait_bus_not_busy(dev);
+ if (ret < 0)
+ goto done;
+
+ /* Start the transfers */
+ i2c_dw_xfer_init(dev);
+
+ /* Wait for tx to complete */
+ if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
+ dev_err(dev->dev, "controller timed out\n");
+ /* i2c_dw_init implicitly disables the adapter */
+ i2c_recover_bus(&dev->adapter);
+ i2c_dw_init_master(dev);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+ /*
+ * We must disable the adapter before returning and signaling the end
+ * of the current transfer. Otherwise the hardware might continue
+ * generating interrupts which in turn causes a race condition with
+ * the following transfer. Needs some more investigation if the
+ * additional interrupts are a hardware bug or this driver doesn't
+ * handle them correctly yet.
+ */
+ __i2c_dw_disable_nowait(dev);
+
+ if (dev->msg_err) {
+ ret = dev->msg_err;
+ goto done;
+ }
+
+ /* No error */
+ if (likely(!dev->cmd_err && !dev->status)) {
+ ret = num;
+ goto done;
+ }
+
+ /* We have an error */
+ if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
+ ret = i2c_dw_handle_tx_abort(dev);
+ goto done;
+ }
+
+ if (dev->status)
+ dev_err(dev->dev,
+ "transfer terminated early - interrupt latency too high?\n");
+
+ ret = -EIO;
+
+done:
+ i2c_dw_release_lock(dev);
+
+done_nolock:
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+
+ return ret;
+}
+
+static const struct i2c_algorithm i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+};
+
+static const struct i2c_adapter_quirks i2c_dw_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+{
+ u32 stat;
+
+ /*
+ * The IC_INTR_STAT register just indicates "enabled" interrupts.
+ * Ths unmasked raw version of interrupt status bits are available
+ * in the IC_RAW_INTR_STAT register.
+ *
+ * That is,
+ * stat = dw_readl(IC_INTR_STAT);
+ * equals to,
+ * stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+ *
+ * The raw version might be useful for debugging purposes.
+ */
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+
+ /*
+ * Do not use the IC_CLR_INTR register to clear interrupts, or
+ * you'll miss some interrupts, triggered during the period from
+ * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+ *
+ * Instead, use the separately-prepared IC_CLR_* registers.
+ */
+ if (stat & DW_IC_INTR_RX_UNDER)
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dw_readl(dev, DW_IC_CLR_RX_OVER);
+ if (stat & DW_IC_INTR_TX_OVER)
+ dw_readl(dev, DW_IC_CLR_TX_OVER);
+ if (stat & DW_IC_INTR_RD_REQ)
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ if (stat & DW_IC_INTR_TX_ABRT) {
+ /*
+ * The IC_TX_ABRT_SOURCE register is cleared whenever
+ * the IC_CLR_TX_ABRT is read. Preserve it beforehand.
+ */
+ dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
+ dw_readl(dev, DW_IC_CLR_TX_ABRT);
+ }
+ if (stat & DW_IC_INTR_RX_DONE)
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_STOP_DET)
+ dw_readl(dev, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+ dw_readl(dev, DW_IC_CLR_GEN_CALL);
+
+ return stat;
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C master interrupt
+ * occurs.
+ */
+static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
+{
+ u32 stat;
+
+ stat = i2c_dw_read_clear_intrbits(dev);
+ if (stat & DW_IC_INTR_TX_ABRT) {
+ dev->cmd_err |= DW_IC_ERR_TX_ABRT;
+ dev->status = STATUS_IDLE;
+
+ /*
+ * Anytime TX_ABRT is set, the contents of the tx/rx
+ * buffers are flushed. Make sure to skip them.
+ */
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ goto tx_aborted;
+ }
+
+ if (stat & DW_IC_INTR_RX_FULL)
+ i2c_dw_read(dev);
+
+ if (stat & DW_IC_INTR_TX_EMPTY)
+ i2c_dw_xfer_msg(dev);
+
+ /*
+ * No need to modify or disable the interrupt mask here.
+ * i2c_dw_xfer_msg() will take care of it according to
+ * the current transmit status.
+ */
+
+tx_aborted:
+ if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
+ complete(&dev->cmd_complete);
+ else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
+ /* Workaround to trigger pending interrupt */
+ stat = dw_readl(dev, DW_IC_INTR_MASK);
+ i2c_dw_disable_int(dev);
+ dw_writel(dev, stat, DW_IC_INTR_MASK);
+ }
+
+ return 0;
+}
+
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+ struct dw_i2c_dev *dev = dev_id;
+ u32 stat, enabled;
+
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+ dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);
+ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+ return IRQ_NONE;
+
+ i2c_dw_irq_handler_master(dev);
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_dw_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ i2c_dw_disable(dev);
+ reset_control_assert(dev->rst);
+ i2c_dw_prepare_clk(dev, false);
+}
+
+static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ i2c_dw_prepare_clk(dev, true);
+ reset_control_deassert(dev->rst);
+ i2c_dw_init_master(dev);
+}
+
+static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
+{
+ struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
+ struct i2c_adapter *adap = &dev->adapter;
+ struct gpio_desc *gpio;
+ int r;
+
+ gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio)) {
+ r = PTR_ERR(gpio);
+ if (r == -ENOENT || r == -ENOSYS)
+ return 0;
+ return r;
+ }
+ rinfo->scl_gpiod = gpio;
+
+ gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN);
+ if (IS_ERR(gpio))
+ return PTR_ERR(gpio);
+ rinfo->sda_gpiod = gpio;
+
+ rinfo->recover_bus = i2c_generic_scl_recovery;
+ rinfo->prepare_recovery = i2c_dw_prepare_recovery;
+ rinfo->unprepare_recovery = i2c_dw_unprepare_recovery;
+ adap->bus_recovery_info = rinfo;
+
+ dev_info(dev->dev, "running with gpio recovery mode! scl%s",
+ rinfo->sda_gpiod ? ",sda" : "");
+
+ return 0;
+}
+
+int i2c_dw_probe(struct dw_i2c_dev *dev)
+{
+ struct i2c_adapter *adap = &dev->adapter;
+ unsigned long irq_flags;
+ int ret;
+
+ init_completion(&dev->cmd_complete);
+
+ dev->init = i2c_dw_init_master;
+ dev->disable = i2c_dw_disable;
+ dev->disable_int = i2c_dw_disable_int;
+
+ ret = i2c_dw_set_reg_access(dev);
+ if (ret)
+ return ret;
+
+ ret = i2c_dw_set_timings_master(dev);
+ if (ret)
+ return ret;
+
+ ret = dev->init(dev);
+ if (ret)
+ return ret;
+
+ snprintf(adap->name, sizeof(adap->name),
+ "Synopsys DesignWare I2C adapter");
+ adap->retries = 3;
+ adap->algo = &i2c_dw_algo;
+ adap->quirks = &i2c_dw_quirks;
+ adap->dev.parent = dev->dev;
+ i2c_set_adapdata(adap, dev);
+
+ if (dev->pm_disabled) {
+ irq_flags = IRQF_NO_SUSPEND;
+ } else {
+ irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
+ }
+
+ i2c_dw_disable_int(dev);
+ ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
+ dev_name(dev->dev), dev);
+ if (ret) {
+ dev_err(dev->dev, "failure requesting irq %i: %d\n",
+ dev->irq, ret);
+ return ret;
+ }
+
+ ret = i2c_dw_init_recovery_info(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Increment PM usage count during adapter registration in order to
+ * avoid possible spurious runtime suspend when adapter device is
+ * registered to the device core and immediate resume in case bus has
+ * registered I2C slaves that do I2C transfers in their probe.
+ */
+ pm_runtime_get_noresume(dev->dev);
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret)
+ dev_err(dev->dev, "failure adding adapter: %d\n", ret);
+ pm_runtime_put_noidle(dev->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_probe);
+
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
new file mode 100644
index 000000000..4e6b3fb01
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ * Copyright (C) 2011, 2015, 2016 Intel Corporation.
+ */
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "i2c-designware-core.h"
+
+#define DRIVER_NAME "i2c-designware-pci"
+
+enum dw_pci_ctl_id_t {
+ medfield,
+ merrifield,
+ baytrail,
+ cherrytrail,
+ haswell,
+};
+
+struct dw_scl_sda_cfg {
+ u16 ss_hcnt;
+ u16 fs_hcnt;
+ u16 ss_lcnt;
+ u16 fs_lcnt;
+ u32 sda_hold;
+};
+
+struct dw_pci_controller {
+ u32 bus_num;
+ u32 bus_cfg;
+ u32 tx_fifo_depth;
+ u32 rx_fifo_depth;
+ u32 clk_khz;
+ u32 functionality;
+ u32 flags;
+ struct dw_scl_sda_cfg *scl_sda_cfg;
+ int (*setup)(struct pci_dev *pdev, struct dw_pci_controller *c);
+};
+
+#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
+ DW_IC_CON_SLAVE_DISABLE | \
+ DW_IC_CON_RESTART_EN)
+
+/* Merrifield HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg mrfld_config = {
+ .ss_hcnt = 0x2f8,
+ .fs_hcnt = 0x87,
+ .ss_lcnt = 0x37b,
+ .fs_lcnt = 0x10a,
+};
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+ .ss_hcnt = 0x200,
+ .fs_hcnt = 0x55,
+ .ss_lcnt = 0x200,
+ .fs_lcnt = 0x99,
+ .sda_hold = 0x6,
+};
+
+/* Haswell HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg hsw_config = {
+ .ss_hcnt = 0x01b0,
+ .fs_hcnt = 0x48,
+ .ss_lcnt = 0x01fb,
+ .fs_lcnt = 0xa0,
+ .sda_hold = 0x9,
+};
+
+static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
+{
+ switch (pdev->device) {
+ case 0x0817:
+ c->bus_cfg &= ~DW_IC_CON_SPEED_MASK;
+ c->bus_cfg |= DW_IC_CON_SPEED_STD;
+ /* fall through */
+ case 0x0818:
+ case 0x0819:
+ c->bus_num = pdev->device - 0x817 + 3;
+ return 0;
+ case 0x082C:
+ case 0x082D:
+ case 0x082E:
+ c->bus_num = pdev->device - 0x82C + 0;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
+{
+ /*
+ * On Intel Merrifield the user visible i2c busses are enumerated
+ * [1..7]. So, we add 1 to shift the default range. Besides that the
+ * first PCI slot provides 4 functions, that's why we have to add 0 to
+ * the first slot and 4 to the next one.
+ */
+ switch (PCI_SLOT(pdev->devfn)) {
+ case 8:
+ c->bus_num = PCI_FUNC(pdev->devfn) + 0 + 1;
+ return 0;
+ case 9:
+ c->bus_num = PCI_FUNC(pdev->devfn) + 4 + 1;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static struct dw_pci_controller dw_pci_controllers[] = {
+ [medfield] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .clk_khz = 25000,
+ .setup = mfld_setup,
+ },
+ [merrifield] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 64,
+ .rx_fifo_depth = 64,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .scl_sda_cfg = &mrfld_config,
+ .setup = mrfld_setup,
+ },
+ [baytrail] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .scl_sda_cfg = &byt_config,
+ },
+ [haswell] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .scl_sda_cfg = &hsw_config,
+ },
+ [cherrytrail] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .functionality = I2C_FUNC_10BIT_ADDR,
+ .flags = MODEL_CHERRYTRAIL,
+ .scl_sda_cfg = &byt_config,
+ },
+};
+
+#ifdef CONFIG_PM
+static int i2c_dw_pci_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dw_i2c_dev *i_dev = pci_get_drvdata(pdev);
+
+ i_dev->disable(i_dev);
+
+ return 0;
+}
+
+static int i2c_dw_pci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dw_i2c_dev *i_dev = pci_get_drvdata(pdev);
+
+ return i_dev->init(i_dev);
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend,
+ i2c_dw_pci_resume, NULL);
+
+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return dev->controller->clk_khz;
+}
+
+static int i2c_dw_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct dw_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ int r;
+ struct dw_pci_controller *controller;
+ struct dw_scl_sda_cfg *cfg;
+
+ if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+ dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
+ id->driver_data);
+ return -EINVAL;
+ }
+
+ controller = &dw_pci_controllers[id->driver_data];
+
+ r = pcim_enable_device(pdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
+ r);
+ return r;
+ }
+
+ r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
+ if (r) {
+ dev_err(&pdev->dev, "I/O memory remapping failed\n");
+ return r;
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->clk = NULL;
+ dev->controller = controller;
+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+ dev->base = pcim_iomap_table(pdev)[0];
+ dev->dev = &pdev->dev;
+ dev->irq = pdev->irq;
+ dev->flags |= controller->flags;
+
+ if (controller->setup) {
+ r = controller->setup(pdev, controller);
+ if (r)
+ return r;
+ }
+
+ dev->functionality = controller->functionality |
+ DW_IC_DEFAULT_FUNCTIONALITY;
+
+ dev->master_cfg = controller->bus_cfg;
+ if (controller->scl_sda_cfg) {
+ cfg = controller->scl_sda_cfg;
+ dev->ss_hcnt = cfg->ss_hcnt;
+ dev->fs_hcnt = cfg->fs_hcnt;
+ dev->ss_lcnt = cfg->ss_lcnt;
+ dev->fs_lcnt = cfg->fs_lcnt;
+ dev->sda_hold_time = cfg->sda_hold;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ dev->tx_fifo_depth = controller->tx_fifo_depth;
+ dev->rx_fifo_depth = controller->rx_fifo_depth;
+
+ adap = &dev->adapter;
+ adap->owner = THIS_MODULE;
+ adap->class = 0;
+ ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+ adap->nr = controller->bus_num;
+
+ r = i2c_dw_probe(dev);
+ if (r)
+ return r;
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
+ return 0;
+}
+
+static void i2c_dw_pci_remove(struct pci_dev *pdev)
+{
+ struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
+
+ dev->disable(dev);
+ pm_runtime_forbid(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+
+ i2c_del_adapter(&dev->adapter);
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("i2c_designware-pci");
+
+static const struct pci_device_id i2_designware_pci_ids[] = {
+ /* Medfield */
+ { PCI_VDEVICE(INTEL, 0x0817), medfield },
+ { PCI_VDEVICE(INTEL, 0x0818), medfield },
+ { PCI_VDEVICE(INTEL, 0x0819), medfield },
+ { PCI_VDEVICE(INTEL, 0x082C), medfield },
+ { PCI_VDEVICE(INTEL, 0x082D), medfield },
+ { PCI_VDEVICE(INTEL, 0x082E), medfield },
+ /* Merrifield */
+ { PCI_VDEVICE(INTEL, 0x1195), merrifield },
+ { PCI_VDEVICE(INTEL, 0x1196), merrifield },
+ /* Baytrail */
+ { PCI_VDEVICE(INTEL, 0x0F41), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F42), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F43), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F44), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F45), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F46), baytrail },
+ { PCI_VDEVICE(INTEL, 0x0F47), baytrail },
+ /* Haswell */
+ { PCI_VDEVICE(INTEL, 0x9c61), haswell },
+ { PCI_VDEVICE(INTEL, 0x9c62), haswell },
+ /* Braswell / Cherrytrail */
+ { PCI_VDEVICE(INTEL, 0x22C1), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C2), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C3), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C4), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C5), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C6), cherrytrail },
+ { PCI_VDEVICE(INTEL, 0x22C7), cherrytrail },
+ { 0,}
+};
+MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
+
+static struct pci_driver dw_i2c_driver = {
+ .name = DRIVER_NAME,
+ .id_table = i2_designware_pci_ids,
+ .probe = i2c_dw_pci_probe,
+ .remove = i2c_dw_pci_remove,
+ .driver = {
+ .pm = &i2c_dw_pm_ops,
+ },
+};
+
+module_pci_driver(dw_i2c_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
new file mode 100644
index 000000000..b5750fd85
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Synopsys DesignWare I2C adapter driver.
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ */
+#include <linux/acpi.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/i2c-designware.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+
+#include "i2c-designware-core.h"
+
+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return clk_get_rate(dev->clk)/1000;
+}
+
+#ifdef CONFIG_ACPI
+/*
+ * The HCNT/LCNT information coming from ACPI should be the most accurate
+ * for given platform. However, some systems get it wrong. On such systems
+ * we get better results by calculating those based on the input clock.
+ */
+static const struct dmi_system_id dw_i2c_no_acpi_params[] = {
+ {
+ .ident = "Dell Inspiron 7348",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7348"),
+ },
+ },
+ { }
+};
+
+static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
+ u16 *hcnt, u16 *lcnt, u32 *sda_hold)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+ union acpi_object *obj;
+
+ if (dmi_check_system(dw_i2c_no_acpi_params))
+ return;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
+ return;
+
+ obj = (union acpi_object *)buf.pointer;
+ if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
+ const union acpi_object *objs = obj->package.elements;
+
+ *hcnt = (u16)objs[0].integer.value;
+ *lcnt = (u16)objs[1].integer.value;
+ *sda_hold = (u32)objs[2].integer.value;
+ }
+
+ kfree(buf.pointer);
+}
+
+static int dw_i2c_acpi_configure(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct i2c_timings *t = &dev->timings;
+ u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
+ acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+ const struct acpi_device_id *id;
+ struct acpi_device *adev;
+ const char *uid;
+
+ dev->adapter.nr = -1;
+ dev->tx_fifo_depth = 32;
+ dev->rx_fifo_depth = 32;
+
+ /*
+ * Try to get SDA hold time and *CNT values from an ACPI method for
+ * selected speed modes.
+ */
+ dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht);
+ dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, &fp_ht);
+ dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht);
+ dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht);
+
+ switch (t->bus_freq_hz) {
+ case 100000:
+ dev->sda_hold_time = ss_ht;
+ break;
+ case 1000000:
+ dev->sda_hold_time = fp_ht;
+ break;
+ case 3400000:
+ dev->sda_hold_time = hs_ht;
+ break;
+ case 400000:
+ default:
+ dev->sda_hold_time = fs_ht;
+ break;
+ }
+
+ id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
+ if (id && id->driver_data)
+ dev->flags |= (u32)id->driver_data;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return -ENODEV;
+
+ /*
+ * Cherrytrail I2C7 gets used for the PMIC which gets accessed
+ * through ACPI opregions during late suspend / early resume
+ * disable pm for it.
+ */
+ uid = adev->pnp.unique_id;
+ if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7"))
+ dev->pm_disabled = true;
+
+ return 0;
+}
+
+static const struct acpi_device_id dw_i2c_acpi_match[] = {
+ { "INT33C2", 0 },
+ { "INT33C3", 0 },
+ { "INT3432", 0 },
+ { "INT3433", 0 },
+ { "80860F41", 0 },
+ { "808622C1", MODEL_CHERRYTRAIL },
+ { "AMD0010", ACCESS_INTR_MASK },
+ { "AMDI0010", ACCESS_INTR_MASK },
+ { "AMDI0510", 0 },
+ { "APMC0D0F", 0 },
+ { "HISI02A1", 0 },
+ { "HISI02A2", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
+#else
+static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif
+
+static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
+{
+ struct i2c_timings *t = &dev->timings;
+
+ dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
+
+ dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN;
+
+ dev->mode = DW_IC_MASTER;
+
+ switch (t->bus_freq_hz) {
+ case 100000:
+ dev->master_cfg |= DW_IC_CON_SPEED_STD;
+ break;
+ case 3400000:
+ dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
+ break;
+ default:
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+ }
+}
+
+static void i2c_dw_configure_slave(struct dw_i2c_dev *dev)
+{
+ dev->functionality = I2C_FUNC_SLAVE | DW_IC_DEFAULT_FUNCTIONALITY;
+
+ dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
+ DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
+
+ dev->mode = DW_IC_SLAVE;
+}
+
+static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
+{
+ u32 param, tx_fifo_depth, rx_fifo_depth;
+
+ /*
+ * Try to detect the FIFO depth if not set by interface driver,
+ * the depth could be from 2 to 256 from HW spec.
+ */
+ param = i2c_dw_read_comp_param(dev);
+ tx_fifo_depth = ((param >> 16) & 0xff) + 1;
+ rx_fifo_depth = ((param >> 8) & 0xff) + 1;
+ if (!dev->tx_fifo_depth) {
+ dev->tx_fifo_depth = tx_fifo_depth;
+ dev->rx_fifo_depth = rx_fifo_depth;
+ dev->adapter.nr = id;
+ } else if (tx_fifo_depth >= 2) {
+ dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth,
+ tx_fifo_depth);
+ dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
+ rx_fifo_depth);
+ }
+}
+
+static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
+{
+ pm_runtime_disable(dev->dev);
+
+ if (dev->pm_disabled)
+ pm_runtime_put_noidle(dev->dev);
+}
+
+static int dw_i2c_plat_probe(struct platform_device *pdev)
+{
+ struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct i2c_adapter *adap;
+ struct dw_i2c_dev *dev;
+ struct i2c_timings *t;
+ u32 acpi_speed;
+ struct resource *mem;
+ int i, irq, ret;
+ static const int supported_speeds[] = {
+ 0, 100000, 400000, 1000000, 3400000
+ };
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
+
+ dev->dev = &pdev->dev;
+ dev->irq = irq;
+ platform_set_drvdata(pdev, dev);
+
+ dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(dev->rst)) {
+ if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ } else {
+ reset_control_deassert(dev->rst);
+ }
+
+ t = &dev->timings;
+ if (pdata)
+ t->bus_freq_hz = pdata->i2c_scl_freq;
+ else
+ i2c_parse_fw_timings(&pdev->dev, t, false);
+
+ acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
+ /*
+ * Some DSTDs use a non standard speed, round down to the lowest
+ * standard speed.
+ */
+ for (i = 1; i < ARRAY_SIZE(supported_speeds); i++) {
+ if (acpi_speed < supported_speeds[i])
+ break;
+ }
+ acpi_speed = supported_speeds[i - 1];
+
+ /*
+ * Find bus speed from the "clock-frequency" device property, ACPI
+ * or by using fast mode if neither is set.
+ */
+ if (acpi_speed && t->bus_freq_hz)
+ t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed);
+ else if (acpi_speed || t->bus_freq_hz)
+ t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
+ else
+ t->bus_freq_hz = 400000;
+
+ if (has_acpi_companion(&pdev->dev))
+ dw_i2c_acpi_configure(pdev);
+
+ /*
+ * Only standard mode at 100kHz, fast mode at 400kHz,
+ * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
+ */
+ if (t->bus_freq_hz != 100000 && t->bus_freq_hz != 400000 &&
+ t->bus_freq_hz != 1000000 && t->bus_freq_hz != 3400000) {
+ dev_err(&pdev->dev,
+ "%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n",
+ t->bus_freq_hz);
+ ret = -EINVAL;
+ goto exit_reset;
+ }
+
+ ret = i2c_dw_probe_lock_support(dev);
+ if (ret)
+ goto exit_reset;
+
+ if (i2c_detect_slave_mode(&pdev->dev))
+ i2c_dw_configure_slave(dev);
+ else
+ i2c_dw_configure_master(dev);
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (!i2c_dw_prepare_clk(dev, true)) {
+ u64 clk_khz;
+
+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+ clk_khz = dev->get_clk_rate_khz(dev);
+
+ if (!dev->sda_hold_time && t->sda_hold_ns)
+ dev->sda_hold_time =
+ div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000);
+ }
+
+ dw_i2c_set_fifo_size(dev, pdev->id);
+
+ adap = &dev->adapter;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_DEPRECATED;
+ ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+ adap->dev.of_node = pdev->dev.of_node;
+
+ dev_pm_set_driver_flags(&pdev->dev,
+ DPM_FLAG_SMART_PREPARE |
+ DPM_FLAG_SMART_SUSPEND |
+ DPM_FLAG_LEAVE_SUSPENDED);
+
+ /* The code below assumes runtime PM to be disabled. */
+ WARN_ON(pm_runtime_enabled(&pdev->dev));
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+
+ if (dev->pm_disabled)
+ pm_runtime_get_noresume(&pdev->dev);
+
+ pm_runtime_enable(&pdev->dev);
+
+ if (dev->mode == DW_IC_SLAVE)
+ ret = i2c_dw_probe_slave(dev);
+ else
+ ret = i2c_dw_probe(dev);
+
+ if (ret)
+ goto exit_probe;
+
+ return ret;
+
+exit_probe:
+ dw_i2c_plat_pm_cleanup(dev);
+exit_reset:
+ if (!IS_ERR_OR_NULL(dev->rst))
+ reset_control_assert(dev->rst);
+ return ret;
+}
+
+static int dw_i2c_plat_remove(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ i2c_del_adapter(&dev->adapter);
+
+ dev->disable(dev);
+
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
+ dw_i2c_plat_pm_cleanup(dev);
+
+ if (!IS_ERR_OR_NULL(dev->rst))
+ reset_control_assert(dev->rst);
+
+ i2c_dw_remove_lock_support(dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dw_i2c_of_match[] = {
+ { .compatible = "snps,designware-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int dw_i2c_plat_prepare(struct device *dev)
+{
+ /*
+ * If the ACPI companion device object is present for this device, it
+ * may be accessed during suspend and resume of other devices via I2C
+ * operation regions, so tell the PM core and middle layers to avoid
+ * skipping system suspend/resume callbacks for it in that case.
+ */
+ return !has_acpi_companion(dev);
+}
+
+static void dw_i2c_plat_complete(struct device *dev)
+{
+ /*
+ * The device can only be in runtime suspend at this point if it has not
+ * been resumed throughout the ending system suspend/resume cycle, so if
+ * the platform firmware might mess up with it, request the runtime PM
+ * framework to resume it.
+ */
+ if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
+ pm_request_resume(dev);
+}
+#else
+#define dw_i2c_plat_prepare NULL
+#define dw_i2c_plat_complete NULL
+#endif
+
+#ifdef CONFIG_PM
+static int dw_i2c_plat_suspend(struct device *dev)
+{
+ struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
+
+ if (i_dev->pm_disabled)
+ return 0;
+
+ i_dev->disable(i_dev);
+ i2c_dw_prepare_clk(i_dev, false);
+
+ return 0;
+}
+
+static int dw_i2c_plat_resume(struct device *dev)
+{
+ struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
+
+ if (!i_dev->pm_disabled)
+ i2c_dw_prepare_clk(i_dev, true);
+
+ i_dev->init(i_dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
+ .prepare = dw_i2c_plat_prepare,
+ .complete = dw_i2c_plat_complete,
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
+ SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
+};
+
+#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
+#else
+#define DW_I2C_DEV_PMOPS NULL
+#endif
+
+/* Work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_designware");
+
+static struct platform_driver dw_i2c_driver = {
+ .probe = dw_i2c_plat_probe,
+ .remove = dw_i2c_plat_remove,
+ .driver = {
+ .name = "i2c_designware",
+ .of_match_table = of_match_ptr(dw_i2c_of_match),
+ .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
+ .pm = DW_I2C_DEV_PMOPS,
+ },
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+ return platform_driver_register(&dw_i2c_driver);
+}
+subsys_initcall(dw_i2c_init_driver);
+
+static void __exit dw_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&dw_i2c_driver);
+}
+module_exit(dw_i2c_exit_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
new file mode 100644
index 000000000..f5f001738
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Synopsys DesignWare I2C adapter driver (slave only).
+ *
+ * Based on the Synopsys DesignWare I2C adapter driver (master).
+ *
+ * Copyright (C) 2016 Synopsys Inc.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include "i2c-designware-core.h"
+
+static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
+{
+ /* Configure Tx/Rx FIFO threshold levels. */
+ dw_writel(dev, 0, DW_IC_TX_TL);
+ dw_writel(dev, 0, DW_IC_RX_TL);
+
+ /* Configure the I2C slave. */
+ dw_writel(dev, dev->slave_cfg, DW_IC_CON);
+ dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
+}
+
+/**
+ * i2c_dw_init_slave() - Initialize the designware i2c slave hardware
+ * @dev: device private data
+ *
+ * This function configures and enables the I2C in slave mode.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
+{
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ /* Disable the adapter. */
+ __i2c_dw_disable(dev);
+
+ /* Write SDA hold time if supported */
+ if (dev->sda_hold_time)
+ dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+
+ i2c_dw_configure_fifo_slave(dev);
+ i2c_dw_release_lock(dev);
+
+ return 0;
+}
+
+static int i2c_dw_reg_slave(struct i2c_client *slave)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
+
+ if (dev->slave)
+ return -EBUSY;
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+ pm_runtime_get_sync(dev->dev);
+
+ /*
+ * Set slave address in the IC_SAR register,
+ * the address to which the DW_apb_i2c responds.
+ */
+ __i2c_dw_disable_nowait(dev);
+ dw_writel(dev, slave->addr, DW_IC_SAR);
+ dev->slave = slave;
+
+ __i2c_dw_enable(dev);
+
+ dev->cmd_err = 0;
+ dev->msg_write_idx = 0;
+ dev->msg_read_idx = 0;
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
+ dev->rx_outstanding = 0;
+
+ return 0;
+}
+
+static int i2c_dw_unreg_slave(struct i2c_client *slave)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
+
+ dev->disable_int(dev);
+ dev->disable(dev);
+ synchronize_irq(dev->irq);
+ dev->slave = NULL;
+ pm_runtime_put(dev->dev);
+
+ return 0;
+}
+
+static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
+{
+ u32 stat;
+
+ /*
+ * The IC_INTR_STAT register just indicates "enabled" interrupts.
+ * Ths unmasked raw version of interrupt status bits are available
+ * in the IC_RAW_INTR_STAT register.
+ *
+ * That is,
+ * stat = dw_readl(IC_INTR_STAT);
+ * equals to,
+ * stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+ *
+ * The raw version might be useful for debugging purposes.
+ */
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+
+ /*
+ * Do not use the IC_CLR_INTR register to clear interrupts, or
+ * you'll miss some interrupts, triggered during the period from
+ * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+ *
+ * Instead, use the separately-prepared IC_CLR_* registers.
+ */
+ if (stat & DW_IC_INTR_TX_ABRT)
+ dw_readl(dev, DW_IC_CLR_TX_ABRT);
+ if (stat & DW_IC_INTR_RX_UNDER)
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dw_readl(dev, DW_IC_CLR_RX_OVER);
+ if (stat & DW_IC_INTR_TX_OVER)
+ dw_readl(dev, DW_IC_CLR_TX_OVER);
+ if (stat & DW_IC_INTR_RX_DONE)
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_STOP_DET)
+ dw_readl(dev, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+ dw_readl(dev, DW_IC_CLR_GEN_CALL);
+
+ return stat;
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C slave interrupt
+ * occurs.
+ */
+
+static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
+{
+ u32 raw_stat, stat, enabled;
+ u8 val, slave_activity;
+
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+ slave_activity = ((dw_readl(dev, DW_IC_STATUS) &
+ DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
+
+ if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
+ return 0;
+
+ dev_dbg(dev->dev,
+ "%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
+ enabled, slave_activity, raw_stat, stat);
+
+ if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
+ i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
+
+ if (stat & DW_IC_INTR_RD_REQ) {
+ if (slave_activity) {
+ if (stat & DW_IC_INTR_RX_FULL) {
+ val = dw_readl(dev, DW_IC_DATA_CMD);
+
+ if (!i2c_slave_event(dev->slave,
+ I2C_SLAVE_WRITE_RECEIVED,
+ &val)) {
+ dev_vdbg(dev->dev, "Byte %X acked!",
+ val);
+ }
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ } else {
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ }
+ if (!i2c_slave_event(dev->slave,
+ I2C_SLAVE_READ_REQUESTED,
+ &val))
+ dw_writel(dev, val, DW_IC_DATA_CMD);
+ }
+ }
+
+ if (stat & DW_IC_INTR_RX_DONE) {
+ if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
+ &val))
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+
+ i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ return 1;
+ }
+
+ if (stat & DW_IC_INTR_RX_FULL) {
+ val = dw_readl(dev, DW_IC_DATA_CMD);
+ if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
+ &val))
+ dev_vdbg(dev->dev, "Byte %X acked!", val);
+ } else {
+ i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ }
+
+ return 1;
+}
+
+static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
+{
+ struct dw_i2c_dev *dev = dev_id;
+ int ret;
+
+ i2c_dw_read_clear_intrbits_slave(dev);
+ ret = i2c_dw_irq_handler_slave(dev);
+ if (ret > 0)
+ complete(&dev->cmd_complete);
+
+ return IRQ_RETVAL(ret);
+}
+
+static const struct i2c_algorithm i2c_dw_algo = {
+ .functionality = i2c_dw_func,
+ .reg_slave = i2c_dw_reg_slave,
+ .unreg_slave = i2c_dw_unreg_slave,
+};
+
+int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
+{
+ struct i2c_adapter *adap = &dev->adapter;
+ int ret;
+
+ init_completion(&dev->cmd_complete);
+
+ dev->init = i2c_dw_init_slave;
+ dev->disable = i2c_dw_disable;
+ dev->disable_int = i2c_dw_disable_int;
+
+ ret = i2c_dw_set_reg_access(dev);
+ if (ret)
+ return ret;
+
+ ret = i2c_dw_set_sda_hold(dev);
+ if (ret)
+ return ret;
+
+ ret = dev->init(dev);
+ if (ret)
+ return ret;
+
+ snprintf(adap->name, sizeof(adap->name),
+ "Synopsys DesignWare I2C Slave adapter");
+ adap->retries = 3;
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = dev->dev;
+ i2c_set_adapdata(adap, dev);
+
+ ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
+ IRQF_SHARED, dev_name(dev->dev), dev);
+ if (ret) {
+ dev_err(dev->dev, "failure requesting irq %i: %d\n",
+ dev->irq, ret);
+ return ret;
+ }
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret)
+ dev_err(dev->dev, "failure adding adapter: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_probe_slave);
+
+MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
new file mode 100644
index 000000000..50813a24c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-digicolor.c
@@ -0,0 +1,385 @@
+/*
+ * I2C bus driver for Conexant Digicolor SoCs
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2015 Paradox Innovation Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_FREQ 100000
+#define TIMEOUT_MS 100
+
+#define II_CONTROL 0x0
+#define II_CONTROL_LOCAL_RESET BIT(0)
+
+#define II_CLOCKTIME 0x1
+
+#define II_COMMAND 0x2
+#define II_CMD_START 1
+#define II_CMD_RESTART 2
+#define II_CMD_SEND_ACK 3
+#define II_CMD_GET_ACK 6
+#define II_CMD_GET_NOACK 7
+#define II_CMD_STOP 10
+#define II_COMMAND_GO BIT(7)
+#define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3)
+#define II_CMD_STATUS_NORMAL 0
+#define II_CMD_STATUS_ACK_GOOD 1
+#define II_CMD_STATUS_ACK_BAD 2
+#define II_CMD_STATUS_ABORT 3
+
+#define II_DATA 0x3
+#define II_INTFLAG_CLEAR 0x8
+#define II_INTENABLE 0xa
+
+struct dc_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+ unsigned int frequency;
+
+ struct i2c_msg *msg;
+ unsigned int msgbuf_ptr;
+ int last;
+ spinlock_t lock;
+ struct completion done;
+ int state;
+ int error;
+};
+
+enum {
+ STATE_IDLE,
+ STATE_START,
+ STATE_ADDR,
+ STATE_WRITE,
+ STATE_READ,
+ STATE_STOP,
+};
+
+static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd)
+{
+ writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND);
+}
+
+static u8 dc_i2c_addr_cmd(struct i2c_msg *msg)
+{
+ u8 addr = (msg->addr & 0x7f) << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ return addr;
+}
+
+static void dc_i2c_data(struct dc_i2c *i2c, u8 data)
+{
+ writeb_relaxed(data, i2c->regs + II_DATA);
+}
+
+static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte)
+{
+ dc_i2c_data(i2c, byte);
+ dc_i2c_cmd(i2c, II_CMD_SEND_ACK);
+}
+
+static void dc_i2c_write_buf(struct dc_i2c *i2c)
+{
+ dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]);
+}
+
+static void dc_i2c_next_read(struct dc_i2c *i2c)
+{
+ bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len);
+
+ dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK);
+}
+
+static void dc_i2c_stop(struct dc_i2c *i2c)
+{
+ i2c->state = STATE_STOP;
+ if (i2c->last)
+ dc_i2c_cmd(i2c, II_CMD_STOP);
+ else
+ complete(&i2c->done);
+}
+
+static u8 dc_i2c_read_byte(struct dc_i2c *i2c)
+{
+ return readb_relaxed(i2c->regs + II_DATA);
+}
+
+static void dc_i2c_read_buf(struct dc_i2c *i2c)
+{
+ i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c);
+ dc_i2c_next_read(i2c);
+}
+
+static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable)
+{
+ if (enable)
+ writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
+ writeb_relaxed(!!enable, i2c->regs + II_INTENABLE);
+}
+
+static int dc_i2c_cmd_status(struct dc_i2c *i2c)
+{
+ u8 cmd = readb_relaxed(i2c->regs + II_COMMAND);
+
+ return II_COMMAND_COMPLETION_STATUS(cmd);
+}
+
+static void dc_i2c_start_msg(struct dc_i2c *i2c, int first)
+{
+ struct i2c_msg *msg = i2c->msg;
+
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ i2c->state = STATE_START;
+ dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART);
+ } else if (msg->flags & I2C_M_RD) {
+ i2c->state = STATE_READ;
+ dc_i2c_next_read(i2c);
+ } else {
+ i2c->state = STATE_WRITE;
+ dc_i2c_write_buf(i2c);
+ }
+}
+
+static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
+{
+ struct dc_i2c *i2c = dev_id;
+ int cmd_status = dc_i2c_cmd_status(i2c);
+ unsigned long flags;
+ u8 addr_cmd;
+
+ writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ if (cmd_status == II_CMD_STATUS_ACK_BAD
+ || cmd_status == II_CMD_STATUS_ABORT) {
+ i2c->error = -EIO;
+ complete(&i2c->done);
+ goto out;
+ }
+
+ switch (i2c->state) {
+ case STATE_START:
+ addr_cmd = dc_i2c_addr_cmd(i2c->msg);
+ dc_i2c_write_byte(i2c, addr_cmd);
+ i2c->state = STATE_ADDR;
+ break;
+ case STATE_ADDR:
+ if (i2c->msg->flags & I2C_M_RD) {
+ dc_i2c_next_read(i2c);
+ i2c->state = STATE_READ;
+ break;
+ }
+ i2c->state = STATE_WRITE;
+ /* fall through */
+ case STATE_WRITE:
+ if (i2c->msgbuf_ptr < i2c->msg->len)
+ dc_i2c_write_buf(i2c);
+ else
+ dc_i2c_stop(i2c);
+ break;
+ case STATE_READ:
+ if (i2c->msgbuf_ptr < i2c->msg->len)
+ dc_i2c_read_buf(i2c);
+ else
+ dc_i2c_stop(i2c);
+ break;
+ case STATE_STOP:
+ i2c->state = STATE_IDLE;
+ complete(&i2c->done);
+ break;
+ }
+
+out:
+ spin_unlock_irqrestore(&i2c->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
+ int last)
+{
+ unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS);
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ i2c->msg = msg;
+ i2c->msgbuf_ptr = 0;
+ i2c->last = last;
+ i2c->error = 0;
+
+ reinit_completion(&i2c->done);
+ dc_i2c_set_irq(i2c, 1);
+ dc_i2c_start_msg(i2c, first);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ timeout = wait_for_completion_timeout(&i2c->done, timeout);
+ dc_i2c_set_irq(i2c, 0);
+ if (timeout == 0) {
+ i2c->state = STATE_IDLE;
+ return -ETIMEDOUT;
+ }
+
+ if (i2c->error)
+ return i2c->error;
+
+ return 0;
+}
+
+static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct dc_i2c *i2c = adap->algo_data;
+ int i, ret;
+
+ for (i = 0; i < num; i++) {
+ ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static int dc_i2c_init_hw(struct dc_i2c *i2c)
+{
+ unsigned long clk_rate = clk_get_rate(i2c->clk);
+ unsigned int clocktime;
+
+ writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL);
+ udelay(100);
+ writeb_relaxed(0, i2c->regs + II_CONTROL);
+ udelay(100);
+
+ clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency);
+ if (clocktime < 1 || clocktime > 0xff) {
+ dev_err(i2c->dev, "can't set bus speed of %u Hz\n",
+ i2c->frequency);
+ return -EINVAL;
+ }
+ writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME);
+
+ return 0;
+}
+
+static u32 dc_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm dc_i2c_algorithm = {
+ .master_xfer = dc_i2c_xfer,
+ .functionality = dc_i2c_func,
+};
+
+static int dc_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct dc_i2c *i2c;
+ struct resource *r;
+ int ret = 0, irq;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->frequency))
+ i2c->frequency = DEFAULT_FREQ;
+
+ i2c->dev = &pdev->dev;
+ platform_set_drvdata(pdev, i2c);
+
+ spin_lock_init(&i2c->lock);
+ init_completion(&i2c->done);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk))
+ return PTR_ERR(i2c->clk);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0,
+ dev_name(&pdev->dev), i2c);
+ if (ret < 0)
+ return ret;
+
+ strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter",
+ sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &dc_i2c_algorithm;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = np;
+ i2c->adap.algo_data = i2c;
+
+ ret = dc_i2c_init_hw(i2c);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0) {
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dc_i2c_remove(struct platform_device *pdev)
+{
+ struct dc_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static const struct of_device_id dc_i2c_match[] = {
+ { .compatible = "cnxt,cx92755-i2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, dc_i2c_match);
+
+static struct platform_driver dc_i2c_driver = {
+ .probe = dc_i2c_probe,
+ .remove = dc_i2c_remove,
+ .driver = {
+ .name = "digicolor-i2c",
+ .of_match_table = dc_i2c_match,
+ },
+};
+module_platform_driver(dc_i2c_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Conexant Digicolor I2C master driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c
new file mode 100644
index 000000000..3f28317cd
--- /dev/null
+++ b/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -0,0 +1,523 @@
+/*
+ * Driver for the Diolan u2c-12 USB-I2C adapter
+ *
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * Derived from:
+ * i2c-tiny-usb.c
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#define DRIVER_NAME "i2c-diolan-u2c"
+
+#define USB_VENDOR_ID_DIOLAN 0x0abf
+#define USB_DEVICE_ID_DIOLAN_U2C 0x3370
+
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_I2C_READ 0x01
+#define CMD_I2C_WRITE 0x02
+#define CMD_I2C_SCAN 0x03 /* Returns list of detected devices */
+#define CMD_I2C_RELEASE_SDA 0x04
+#define CMD_I2C_RELEASE_SCL 0x05
+#define CMD_I2C_DROP_SDA 0x06
+#define CMD_I2C_DROP_SCL 0x07
+#define CMD_I2C_READ_SDA 0x08
+#define CMD_I2C_READ_SCL 0x09
+#define CMD_GET_FW_VERSION 0x0a
+#define CMD_GET_SERIAL 0x0b
+#define CMD_I2C_START 0x0c
+#define CMD_I2C_STOP 0x0d
+#define CMD_I2C_REPEATED_START 0x0e
+#define CMD_I2C_PUT_BYTE 0x0f
+#define CMD_I2C_GET_BYTE 0x10
+#define CMD_I2C_PUT_ACK 0x11
+#define CMD_I2C_GET_ACK 0x12
+#define CMD_I2C_PUT_BYTE_ACK 0x13
+#define CMD_I2C_GET_BYTE_ACK 0x14
+#define CMD_I2C_SET_SPEED 0x1b
+#define CMD_I2C_GET_SPEED 0x1c
+#define CMD_I2C_SET_CLK_SYNC 0x24
+#define CMD_I2C_GET_CLK_SYNC 0x25
+#define CMD_I2C_SET_CLK_SYNC_TO 0x26
+#define CMD_I2C_GET_CLK_SYNC_TO 0x27
+
+#define RESP_OK 0x00
+#define RESP_FAILED 0x01
+#define RESP_BAD_MEMADDR 0x04
+#define RESP_DATA_ERR 0x05
+#define RESP_NOT_IMPLEMENTED 0x06
+#define RESP_NACK 0x07
+#define RESP_TIMEOUT 0x09
+
+#define U2C_I2C_SPEED_FAST 0 /* 400 kHz */
+#define U2C_I2C_SPEED_STD 1 /* 100 kHz */
+#define U2C_I2C_SPEED_2KHZ 242 /* 2 kHz, minimum speed */
+#define U2C_I2C_SPEED(f) ((DIV_ROUND_UP(1000000, (f)) - 10) / 2 + 1)
+
+#define U2C_I2C_FREQ_FAST 400000
+#define U2C_I2C_FREQ_STD 100000
+#define U2C_I2C_FREQ(s) (1000000 / (2 * (s - 1) + 10))
+
+#define DIOLAN_USB_TIMEOUT 100 /* in ms */
+#define DIOLAN_SYNC_TIMEOUT 20 /* in ms */
+
+#define DIOLAN_OUTBUF_LEN 128
+#define DIOLAN_FLUSH_LEN (DIOLAN_OUTBUF_LEN - 4)
+#define DIOLAN_INBUF_LEN 256 /* Maximum supported receive length */
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_diolan_u2c {
+ u8 obuffer[DIOLAN_OUTBUF_LEN]; /* output buffer */
+ u8 ibuffer[DIOLAN_INBUF_LEN]; /* input buffer */
+ int ep_in, ep_out; /* Endpoints */
+ struct usb_device *usb_dev; /* the usb device for this device */
+ struct usb_interface *interface;/* the interface for this device */
+ struct i2c_adapter adapter; /* i2c related things */
+ int olen; /* Output buffer length */
+ int ocount; /* Number of enqueued messages */
+};
+
+static uint frequency = U2C_I2C_FREQ_STD; /* I2C clock frequency in Hz */
+
+module_param(frequency, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");
+
+/* usb layer */
+
+/* Send command to device, and get response. */
+static int diolan_usb_transfer(struct i2c_diolan_u2c *dev)
+{
+ int ret = 0;
+ int actual;
+ int i;
+
+ if (!dev->olen || !dev->ocount)
+ return -EINVAL;
+
+ ret = usb_bulk_msg(dev->usb_dev,
+ usb_sndbulkpipe(dev->usb_dev, dev->ep_out),
+ dev->obuffer, dev->olen, &actual,
+ DIOLAN_USB_TIMEOUT);
+ if (!ret) {
+ for (i = 0; i < dev->ocount; i++) {
+ int tmpret;
+
+ tmpret = usb_bulk_msg(dev->usb_dev,
+ usb_rcvbulkpipe(dev->usb_dev,
+ dev->ep_in),
+ dev->ibuffer,
+ sizeof(dev->ibuffer), &actual,
+ DIOLAN_USB_TIMEOUT);
+ /*
+ * Stop command processing if a previous command
+ * returned an error.
+ * Note that we still need to retrieve all messages.
+ */
+ if (ret < 0)
+ continue;
+ ret = tmpret;
+ if (ret == 0 && actual > 0) {
+ switch (dev->ibuffer[actual - 1]) {
+ case RESP_NACK:
+ /*
+ * Return ENXIO if NACK was received as
+ * response to the address phase,
+ * EIO otherwise
+ */
+ ret = i == 1 ? -ENXIO : -EIO;
+ break;
+ case RESP_TIMEOUT:
+ ret = -ETIMEDOUT;
+ break;
+ case RESP_OK:
+ /* strip off return code */
+ ret = actual - 1;
+ break;
+ default:
+ ret = -EIO;
+ break;
+ }
+ }
+ }
+ }
+ dev->olen = 0;
+ dev->ocount = 0;
+ return ret;
+}
+
+static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush)
+{
+ if (flush || dev->olen >= DIOLAN_FLUSH_LEN)
+ return diolan_usb_transfer(dev);
+ return 0;
+}
+
+/* Send command (no data) */
+static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush)
+{
+ dev->obuffer[dev->olen++] = command;
+ dev->ocount++;
+ return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with one byte of data */
+static int diolan_usb_cmd_data(struct i2c_diolan_u2c *dev, u8 command, u8 data,
+ bool flush)
+{
+ dev->obuffer[dev->olen++] = command;
+ dev->obuffer[dev->olen++] = data;
+ dev->ocount++;
+ return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with two bytes of data */
+static int diolan_usb_cmd_data2(struct i2c_diolan_u2c *dev, u8 command, u8 d1,
+ u8 d2, bool flush)
+{
+ dev->obuffer[dev->olen++] = command;
+ dev->obuffer[dev->olen++] = d1;
+ dev->obuffer[dev->olen++] = d2;
+ dev->ocount++;
+ return diolan_write_cmd(dev, flush);
+}
+
+/*
+ * Flush input queue.
+ * If we don't do this at startup and the controller has queued up
+ * messages which were not retrieved, it will stop responding
+ * at some point.
+ */
+static void diolan_flush_input(struct i2c_diolan_u2c *dev)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ int actual = 0;
+ int ret;
+
+ ret = usb_bulk_msg(dev->usb_dev,
+ usb_rcvbulkpipe(dev->usb_dev, dev->ep_in),
+ dev->ibuffer, sizeof(dev->ibuffer), &actual,
+ DIOLAN_USB_TIMEOUT);
+ if (ret < 0 || actual == 0)
+ break;
+ }
+ if (i == 10)
+ dev_err(&dev->interface->dev, "Failed to flush input buffer\n");
+}
+
+static int diolan_i2c_start(struct i2c_diolan_u2c *dev)
+{
+ return diolan_usb_cmd(dev, CMD_I2C_START, false);
+}
+
+static int diolan_i2c_repeated_start(struct i2c_diolan_u2c *dev)
+{
+ return diolan_usb_cmd(dev, CMD_I2C_REPEATED_START, false);
+}
+
+static int diolan_i2c_stop(struct i2c_diolan_u2c *dev)
+{
+ return diolan_usb_cmd(dev, CMD_I2C_STOP, true);
+}
+
+static int diolan_i2c_get_byte_ack(struct i2c_diolan_u2c *dev, bool ack,
+ u8 *byte)
+{
+ int ret;
+
+ ret = diolan_usb_cmd_data(dev, CMD_I2C_GET_BYTE_ACK, ack, true);
+ if (ret > 0)
+ *byte = dev->ibuffer[0];
+ else if (ret == 0)
+ ret = -EIO;
+
+ return ret;
+}
+
+static int diolan_i2c_put_byte_ack(struct i2c_diolan_u2c *dev, u8 byte)
+{
+ return diolan_usb_cmd_data(dev, CMD_I2C_PUT_BYTE_ACK, byte, false);
+}
+
+static int diolan_set_speed(struct i2c_diolan_u2c *dev, u8 speed)
+{
+ return diolan_usb_cmd_data(dev, CMD_I2C_SET_SPEED, speed, true);
+}
+
+/* Enable or disable clock synchronization (stretching) */
+static int diolan_set_clock_synch(struct i2c_diolan_u2c *dev, bool enable)
+{
+ return diolan_usb_cmd_data(dev, CMD_I2C_SET_CLK_SYNC, enable, true);
+}
+
+/* Set clock synchronization timeout in ms */
+static int diolan_set_clock_synch_timeout(struct i2c_diolan_u2c *dev, int ms)
+{
+ int to_val = ms * 10;
+
+ return diolan_usb_cmd_data2(dev, CMD_I2C_SET_CLK_SYNC_TO,
+ to_val & 0xff, (to_val >> 8) & 0xff, true);
+}
+
+static void diolan_fw_version(struct i2c_diolan_u2c *dev)
+{
+ int ret;
+
+ ret = diolan_usb_cmd(dev, CMD_GET_FW_VERSION, true);
+ if (ret >= 2)
+ dev_info(&dev->interface->dev,
+ "Diolan U2C firmware version %u.%u\n",
+ (unsigned int)dev->ibuffer[0],
+ (unsigned int)dev->ibuffer[1]);
+}
+
+static void diolan_get_serial(struct i2c_diolan_u2c *dev)
+{
+ int ret;
+ u32 serial;
+
+ ret = diolan_usb_cmd(dev, CMD_GET_SERIAL, true);
+ if (ret >= 4) {
+ serial = le32_to_cpu(*(u32 *)dev->ibuffer);
+ dev_info(&dev->interface->dev,
+ "Diolan U2C serial number %u\n", serial);
+ }
+}
+
+static int diolan_init(struct i2c_diolan_u2c *dev)
+{
+ int speed, ret;
+
+ if (frequency >= 200000) {
+ speed = U2C_I2C_SPEED_FAST;
+ frequency = U2C_I2C_FREQ_FAST;
+ } else if (frequency >= 100000 || frequency == 0) {
+ speed = U2C_I2C_SPEED_STD;
+ frequency = U2C_I2C_FREQ_STD;
+ } else {
+ speed = U2C_I2C_SPEED(frequency);
+ if (speed > U2C_I2C_SPEED_2KHZ)
+ speed = U2C_I2C_SPEED_2KHZ;
+ frequency = U2C_I2C_FREQ(speed);
+ }
+
+ dev_info(&dev->interface->dev,
+ "Diolan U2C at USB bus %03d address %03d speed %d Hz\n",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency);
+
+ diolan_flush_input(dev);
+ diolan_fw_version(dev);
+ diolan_get_serial(dev);
+
+ /* Set I2C speed */
+ ret = diolan_set_speed(dev, speed);
+ if (ret < 0)
+ return ret;
+
+ /* Configure I2C clock synchronization */
+ ret = diolan_set_clock_synch(dev, speed != U2C_I2C_SPEED_FAST);
+ if (ret < 0)
+ return ret;
+
+ if (speed != U2C_I2C_SPEED_FAST)
+ ret = diolan_set_clock_synch_timeout(dev, DIOLAN_SYNC_TIMEOUT);
+
+ return ret;
+}
+
+/* i2c layer */
+
+static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_diolan_u2c *dev = i2c_get_adapdata(adapter);
+ struct i2c_msg *pmsg;
+ int i, j;
+ int ret, sret;
+
+ ret = diolan_i2c_start(dev);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ if (i) {
+ ret = diolan_i2c_repeated_start(dev);
+ if (ret < 0)
+ goto abort;
+ }
+ ret = diolan_i2c_put_byte_ack(dev,
+ i2c_8bit_addr_from_msg(pmsg));
+ if (ret < 0)
+ goto abort;
+ if (pmsg->flags & I2C_M_RD) {
+ for (j = 0; j < pmsg->len; j++) {
+ u8 byte;
+ bool ack = j < pmsg->len - 1;
+
+ /*
+ * Don't send NACK if this is the first byte
+ * of a SMBUS_BLOCK message.
+ */
+ if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN))
+ ack = true;
+
+ ret = diolan_i2c_get_byte_ack(dev, ack, &byte);
+ if (ret < 0)
+ goto abort;
+ /*
+ * Adjust count if first received byte is length
+ */
+ if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) {
+ if (byte == 0
+ || byte > I2C_SMBUS_BLOCK_MAX) {
+ ret = -EPROTO;
+ goto abort;
+ }
+ pmsg->len += byte;
+ }
+ pmsg->buf[j] = byte;
+ }
+ } else {
+ for (j = 0; j < pmsg->len; j++) {
+ ret = diolan_i2c_put_byte_ack(dev,
+ pmsg->buf[j]);
+ if (ret < 0)
+ goto abort;
+ }
+ }
+ }
+ ret = num;
+abort:
+ sret = diolan_i2c_stop(dev);
+ if (sret < 0 && ret >= 0)
+ ret = sret;
+ return ret;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 diolan_usb_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm diolan_usb_algorithm = {
+ .master_xfer = diolan_usb_xfer,
+ .functionality = diolan_usb_func,
+};
+
+/* device layer */
+
+static const struct usb_device_id diolan_u2c_table[] = {
+ { USB_DEVICE(USB_VENDOR_ID_DIOLAN, USB_DEVICE_ID_DIOLAN_U2C) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, diolan_u2c_table);
+
+static void diolan_u2c_free(struct i2c_diolan_u2c *dev)
+{
+ usb_put_dev(dev->usb_dev);
+ kfree(dev);
+}
+
+static int diolan_u2c_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *hostif = interface->cur_altsetting;
+ struct i2c_diolan_u2c *dev;
+ int ret;
+
+ if (hostif->desc.bInterfaceNumber != 0
+ || hostif->desc.bNumEndpoints < 2)
+ return -ENODEV;
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ dev->ep_out = hostif->endpoint[0].desc.bEndpointAddress;
+ dev->ep_in = hostif->endpoint[1].desc.bEndpointAddress;
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ /* setup i2c adapter description */
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &diolan_usb_algorithm;
+ i2c_set_adapdata(&dev->adapter, dev);
+ snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+ DRIVER_NAME " at bus %03d device %03d",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ dev->adapter.dev.parent = &dev->interface->dev;
+
+ /* initialize diolan i2c interface */
+ ret = diolan_init(dev);
+ if (ret < 0) {
+ dev_err(&interface->dev, "failed to initialize adapter\n");
+ goto error_free;
+ }
+
+ /* and finally attach to i2c layer */
+ ret = i2c_add_adapter(&dev->adapter);
+ if (ret < 0)
+ goto error_free;
+
+ dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n");
+
+ return 0;
+
+error_free:
+ usb_set_intfdata(interface, NULL);
+ diolan_u2c_free(dev);
+error:
+ return ret;
+}
+
+static void diolan_u2c_disconnect(struct usb_interface *interface)
+{
+ struct i2c_diolan_u2c *dev = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&dev->adapter);
+ usb_set_intfdata(interface, NULL);
+ diolan_u2c_free(dev);
+
+ dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver diolan_u2c_driver = {
+ .name = DRIVER_NAME,
+ .probe = diolan_u2c_probe,
+ .disconnect = diolan_u2c_disconnect,
+ .id_table = diolan_u2c_table,
+};
+
+module_usb_driver(diolan_u2c_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION(DRIVER_NAME " driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
new file mode 100644
index 000000000..69075a320
--- /dev/null
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -0,0 +1,263 @@
+/*
+ * Driver for the Diolan DLN-2 USB-I2C adapter
+ *
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Derived from:
+ * i2c-diolan-u2c.c
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/dln2.h>
+#include <linux/acpi.h>
+
+#define DLN2_I2C_MODULE_ID 0x03
+#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID)
+
+/* I2C commands */
+#define DLN2_I2C_GET_PORT_COUNT DLN2_I2C_CMD(0x00)
+#define DLN2_I2C_ENABLE DLN2_I2C_CMD(0x01)
+#define DLN2_I2C_DISABLE DLN2_I2C_CMD(0x02)
+#define DLN2_I2C_IS_ENABLED DLN2_I2C_CMD(0x03)
+#define DLN2_I2C_WRITE DLN2_I2C_CMD(0x06)
+#define DLN2_I2C_READ DLN2_I2C_CMD(0x07)
+#define DLN2_I2C_SCAN_DEVICES DLN2_I2C_CMD(0x08)
+#define DLN2_I2C_PULLUP_ENABLE DLN2_I2C_CMD(0x09)
+#define DLN2_I2C_PULLUP_DISABLE DLN2_I2C_CMD(0x0A)
+#define DLN2_I2C_PULLUP_IS_ENABLED DLN2_I2C_CMD(0x0B)
+#define DLN2_I2C_TRANSFER DLN2_I2C_CMD(0x0C)
+#define DLN2_I2C_SET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0D)
+#define DLN2_I2C_GET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0E)
+
+#define DLN2_I2C_MAX_XFER_SIZE 256
+#define DLN2_I2C_BUF_SIZE (DLN2_I2C_MAX_XFER_SIZE + 16)
+
+struct dln2_i2c {
+ struct platform_device *pdev;
+ struct i2c_adapter adapter;
+ u8 port;
+ /*
+ * Buffer to hold the packet for read or write transfers. One is enough
+ * since we can't have multiple transfers in parallel on the i2c bus.
+ */
+ void *buf;
+};
+
+static int dln2_i2c_enable(struct dln2_i2c *dln2, bool enable)
+{
+ u16 cmd;
+ struct {
+ u8 port;
+ } tx;
+
+ tx.port = dln2->port;
+
+ if (enable)
+ cmd = DLN2_I2C_ENABLE;
+ else
+ cmd = DLN2_I2C_DISABLE;
+
+ return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx));
+}
+
+static int dln2_i2c_write(struct dln2_i2c *dln2, u8 addr,
+ u8 *data, u16 data_len)
+{
+ int ret;
+ struct {
+ u8 port;
+ u8 addr;
+ u8 mem_addr_len;
+ __le32 mem_addr;
+ __le16 buf_len;
+ u8 buf[DLN2_I2C_MAX_XFER_SIZE];
+ } __packed *tx = dln2->buf;
+ unsigned len;
+
+ BUILD_BUG_ON(sizeof(*tx) > DLN2_I2C_BUF_SIZE);
+
+ tx->port = dln2->port;
+ tx->addr = addr;
+ tx->mem_addr_len = 0;
+ tx->mem_addr = 0;
+ tx->buf_len = cpu_to_le16(data_len);
+ memcpy(tx->buf, data, data_len);
+
+ len = sizeof(*tx) + data_len - DLN2_I2C_MAX_XFER_SIZE;
+ ret = dln2_transfer_tx(dln2->pdev, DLN2_I2C_WRITE, tx, len);
+ if (ret < 0)
+ return ret;
+
+ return data_len;
+}
+
+static int dln2_i2c_read(struct dln2_i2c *dln2, u16 addr, u8 *data,
+ u16 data_len)
+{
+ int ret;
+ struct {
+ u8 port;
+ u8 addr;
+ u8 mem_addr_len;
+ __le32 mem_addr;
+ __le16 buf_len;
+ } __packed tx;
+ struct {
+ __le16 buf_len;
+ u8 buf[DLN2_I2C_MAX_XFER_SIZE];
+ } __packed *rx = dln2->buf;
+ unsigned rx_len = sizeof(*rx);
+
+ BUILD_BUG_ON(sizeof(*rx) > DLN2_I2C_BUF_SIZE);
+
+ tx.port = dln2->port;
+ tx.addr = addr;
+ tx.mem_addr_len = 0;
+ tx.mem_addr = 0;
+ tx.buf_len = cpu_to_le16(data_len);
+
+ ret = dln2_transfer(dln2->pdev, DLN2_I2C_READ, &tx, sizeof(tx),
+ rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx->buf_len) + data_len)
+ return -EPROTO;
+ if (le16_to_cpu(rx->buf_len) != data_len)
+ return -EPROTO;
+
+ memcpy(data, rx->buf, data_len);
+
+ return data_len;
+}
+
+static int dln2_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
+ struct i2c_msg *pmsg;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ int ret;
+
+ pmsg = &msgs[i];
+
+ if (pmsg->flags & I2C_M_RD) {
+ ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ if (ret < 0)
+ return ret;
+
+ pmsg->len = ret;
+ } else {
+ ret = dln2_i2c_write(dln2, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ if (ret != pmsg->len)
+ return -EPROTO;
+ }
+ }
+
+ return num;
+}
+
+static u32 dln2_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
+ .master_xfer = dln2_i2c_xfer,
+ .functionality = dln2_i2c_func,
+};
+
+static const struct i2c_adapter_quirks dln2_i2c_quirks = {
+ .max_read_len = DLN2_I2C_MAX_XFER_SIZE,
+ .max_write_len = DLN2_I2C_MAX_XFER_SIZE,
+};
+
+static int dln2_i2c_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct dln2_i2c *dln2;
+ struct device *dev = &pdev->dev;
+ struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ dln2 = devm_kzalloc(dev, sizeof(*dln2), GFP_KERNEL);
+ if (!dln2)
+ return -ENOMEM;
+
+ dln2->buf = devm_kmalloc(dev, DLN2_I2C_BUF_SIZE, GFP_KERNEL);
+ if (!dln2->buf)
+ return -ENOMEM;
+
+ dln2->pdev = pdev;
+ dln2->port = pdata->port;
+
+ /* setup i2c adapter description */
+ dln2->adapter.owner = THIS_MODULE;
+ dln2->adapter.class = I2C_CLASS_HWMON;
+ dln2->adapter.algo = &dln2_i2c_usb_algorithm;
+ dln2->adapter.quirks = &dln2_i2c_quirks;
+ dln2->adapter.dev.parent = dev;
+ ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev));
+ dln2->adapter.dev.of_node = dev->of_node;
+ i2c_set_adapdata(&dln2->adapter, dln2);
+ snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
+ "dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
+
+ platform_set_drvdata(pdev, dln2);
+
+ /* initialize the i2c interface */
+ ret = dln2_i2c_enable(dln2, true);
+ if (ret < 0) {
+ dev_err(dev, "failed to initialize adapter: %d\n", ret);
+ return ret;
+ }
+
+ /* and finally attach to i2c layer */
+ ret = i2c_add_adapter(&dln2->adapter);
+ if (ret < 0)
+ goto out_disable;
+
+ return 0;
+
+out_disable:
+ dln2_i2c_enable(dln2, false);
+
+ return ret;
+}
+
+static int dln2_i2c_remove(struct platform_device *pdev)
+{
+ struct dln2_i2c *dln2 = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dln2->adapter);
+ dln2_i2c_enable(dln2, false);
+
+ return 0;
+}
+
+static struct platform_driver dln2_i2c_driver = {
+ .driver.name = "dln2-i2c",
+ .probe = dln2_i2c_probe,
+ .remove = dln2_i2c_remove,
+};
+
+module_platform_driver(dln2_i2c_driver);
+
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 I2C master interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dln2-i2c");
diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c
new file mode 100644
index 000000000..5f2bab878
--- /dev/null
+++ b/drivers/i2c/busses/i2c-efm32.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix
+ *
+ * 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/io.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "efm32-i2c"
+
+#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask)
+
+#define REG_CTRL 0x00
+#define REG_CTRL_EN 0x00001
+#define REG_CTRL_SLAVE 0x00002
+#define REG_CTRL_AUTOACK 0x00004
+#define REG_CTRL_AUTOSE 0x00008
+#define REG_CTRL_AUTOSN 0x00010
+#define REG_CTRL_ARBDIS 0x00020
+#define REG_CTRL_GCAMEN 0x00040
+#define REG_CTRL_CLHR__MASK 0x00300
+#define REG_CTRL_BITO__MASK 0x03000
+#define REG_CTRL_BITO_OFF 0x00000
+#define REG_CTRL_BITO_40PCC 0x01000
+#define REG_CTRL_BITO_80PCC 0x02000
+#define REG_CTRL_BITO_160PCC 0x03000
+#define REG_CTRL_GIBITO 0x08000
+#define REG_CTRL_CLTO__MASK 0x70000
+#define REG_CTRL_CLTO_OFF 0x00000
+
+#define REG_CMD 0x04
+#define REG_CMD_START 0x00001
+#define REG_CMD_STOP 0x00002
+#define REG_CMD_ACK 0x00004
+#define REG_CMD_NACK 0x00008
+#define REG_CMD_CONT 0x00010
+#define REG_CMD_ABORT 0x00020
+#define REG_CMD_CLEARTX 0x00040
+#define REG_CMD_CLEARPC 0x00080
+
+#define REG_STATE 0x08
+#define REG_STATE_BUSY 0x00001
+#define REG_STATE_MASTER 0x00002
+#define REG_STATE_TRANSMITTER 0x00004
+#define REG_STATE_NACKED 0x00008
+#define REG_STATE_BUSHOLD 0x00010
+#define REG_STATE_STATE__MASK 0x000e0
+#define REG_STATE_STATE_IDLE 0x00000
+#define REG_STATE_STATE_WAIT 0x00020
+#define REG_STATE_STATE_START 0x00040
+#define REG_STATE_STATE_ADDR 0x00060
+#define REG_STATE_STATE_ADDRACK 0x00080
+#define REG_STATE_STATE_DATA 0x000a0
+#define REG_STATE_STATE_DATAACK 0x000c0
+
+#define REG_STATUS 0x0c
+#define REG_STATUS_PSTART 0x00001
+#define REG_STATUS_PSTOP 0x00002
+#define REG_STATUS_PACK 0x00004
+#define REG_STATUS_PNACK 0x00008
+#define REG_STATUS_PCONT 0x00010
+#define REG_STATUS_PABORT 0x00020
+#define REG_STATUS_TXC 0x00040
+#define REG_STATUS_TXBL 0x00080
+#define REG_STATUS_RXDATAV 0x00100
+
+#define REG_CLKDIV 0x10
+#define REG_CLKDIV_DIV__MASK 0x001ff
+#define REG_CLKDIV_DIV(div) MASK_VAL(REG_CLKDIV_DIV__MASK, (div))
+
+#define REG_SADDR 0x14
+#define REG_SADDRMASK 0x18
+#define REG_RXDATA 0x1c
+#define REG_RXDATAP 0x20
+#define REG_TXDATA 0x24
+#define REG_IF 0x28
+#define REG_IF_START 0x00001
+#define REG_IF_RSTART 0x00002
+#define REG_IF_ADDR 0x00004
+#define REG_IF_TXC 0x00008
+#define REG_IF_TXBL 0x00010
+#define REG_IF_RXDATAV 0x00020
+#define REG_IF_ACK 0x00040
+#define REG_IF_NACK 0x00080
+#define REG_IF_MSTOP 0x00100
+#define REG_IF_ARBLOST 0x00200
+#define REG_IF_BUSERR 0x00400
+#define REG_IF_BUSHOLD 0x00800
+#define REG_IF_TXOF 0x01000
+#define REG_IF_RXUF 0x02000
+#define REG_IF_BITO 0x04000
+#define REG_IF_CLTO 0x08000
+#define REG_IF_SSTOP 0x10000
+
+#define REG_IFS 0x2c
+#define REG_IFC 0x30
+#define REG_IFC__MASK 0x1ffcf
+
+#define REG_IEN 0x34
+
+#define REG_ROUTE 0x38
+#define REG_ROUTE_SDAPEN 0x00001
+#define REG_ROUTE_SCLPEN 0x00002
+#define REG_ROUTE_LOCATION__MASK 0x00700
+#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
+
+struct efm32_i2c_ddata {
+ struct i2c_adapter adapter;
+
+ struct clk *clk;
+ void __iomem *base;
+ unsigned int irq;
+ u8 location;
+ unsigned long frequency;
+
+ /* transfer data */
+ struct completion done;
+ struct i2c_msg *msgs;
+ size_t num_msgs;
+ size_t current_word, current_msg;
+ int retval;
+};
+
+static u32 efm32_i2c_read32(struct efm32_i2c_ddata *ddata, unsigned offset)
+{
+ return readl(ddata->base + offset);
+}
+
+static void efm32_i2c_write32(struct efm32_i2c_ddata *ddata,
+ unsigned offset, u32 value)
+{
+ writel(value, ddata->base + offset);
+}
+
+static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata)
+{
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START);
+ efm32_i2c_write32(ddata, REG_TXDATA, i2c_8bit_addr_from_msg(cur_msg));
+}
+
+static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata)
+{
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+ if (ddata->current_word >= cur_msg->len) {
+ /* cur_msg completely transferred */
+ ddata->current_word = 0;
+ ddata->current_msg += 1;
+
+ if (ddata->current_msg >= ddata->num_msgs) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ complete(&ddata->done);
+ } else {
+ efm32_i2c_send_next_msg(ddata);
+ }
+ } else {
+ efm32_i2c_write32(ddata, REG_TXDATA,
+ cur_msg->buf[ddata->current_word++]);
+ }
+}
+
+static void efm32_i2c_recv_next_byte(struct efm32_i2c_ddata *ddata)
+{
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+ cur_msg->buf[ddata->current_word] = efm32_i2c_read32(ddata, REG_RXDATA);
+ ddata->current_word += 1;
+ if (ddata->current_word >= cur_msg->len) {
+ /* cur_msg completely transferred */
+ ddata->current_word = 0;
+ ddata->current_msg += 1;
+
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_NACK);
+
+ if (ddata->current_msg >= ddata->num_msgs) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ complete(&ddata->done);
+ } else {
+ efm32_i2c_send_next_msg(ddata);
+ }
+ } else {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ACK);
+ }
+}
+
+static irqreturn_t efm32_i2c_irq(int irq, void *dev_id)
+{
+ struct efm32_i2c_ddata *ddata = dev_id;
+ struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+ u32 irqflag = efm32_i2c_read32(ddata, REG_IF);
+ u32 state = efm32_i2c_read32(ddata, REG_STATE);
+
+ efm32_i2c_write32(ddata, REG_IFC, irqflag & REG_IFC__MASK);
+
+ switch (state & REG_STATE_STATE__MASK) {
+ case REG_STATE_STATE_IDLE:
+ /* arbitration lost? */
+ ddata->retval = -EAGAIN;
+ complete(&ddata->done);
+ break;
+ case REG_STATE_STATE_WAIT:
+ /*
+ * huh, this shouldn't happen.
+ * Reset hardware state and get out
+ */
+ ddata->retval = -EIO;
+ efm32_i2c_write32(ddata, REG_CMD,
+ REG_CMD_STOP | REG_CMD_ABORT |
+ REG_CMD_CLEARTX | REG_CMD_CLEARPC);
+ complete(&ddata->done);
+ break;
+ case REG_STATE_STATE_START:
+ /* "caller" is expected to send an address */
+ break;
+ case REG_STATE_STATE_ADDR:
+ /* wait for Ack or NAck of slave */
+ break;
+ case REG_STATE_STATE_ADDRACK:
+ if (state & REG_STATE_NACKED) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ ddata->retval = -ENXIO;
+ complete(&ddata->done);
+ } else if (cur_msg->flags & I2C_M_RD) {
+ /* wait for slave to send first data byte */
+ } else {
+ efm32_i2c_send_next_byte(ddata);
+ }
+ break;
+ case REG_STATE_STATE_DATA:
+ if (cur_msg->flags & I2C_M_RD) {
+ efm32_i2c_recv_next_byte(ddata);
+ } else {
+ /* wait for Ack or Nack of slave */
+ }
+ break;
+ case REG_STATE_STATE_DATAACK:
+ if (state & REG_STATE_NACKED) {
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+ complete(&ddata->done);
+ } else {
+ efm32_i2c_send_next_byte(ddata);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int efm32_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct efm32_i2c_ddata *ddata = i2c_get_adapdata(adap);
+ int ret;
+
+ if (ddata->msgs)
+ return -EBUSY;
+
+ ddata->msgs = msgs;
+ ddata->num_msgs = num;
+ ddata->current_word = 0;
+ ddata->current_msg = 0;
+ ddata->retval = -EIO;
+
+ reinit_completion(&ddata->done);
+
+ dev_dbg(&ddata->adapter.dev, "state: %08x, status: %08x\n",
+ efm32_i2c_read32(ddata, REG_STATE),
+ efm32_i2c_read32(ddata, REG_STATUS));
+
+ efm32_i2c_send_next_msg(ddata);
+
+ wait_for_completion(&ddata->done);
+
+ if (ddata->current_msg >= ddata->num_msgs)
+ ret = ddata->num_msgs;
+ else
+ ret = ddata->retval;
+
+ return ret;
+}
+
+static u32 efm32_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm efm32_i2c_algo = {
+ .master_xfer = efm32_i2c_master_xfer,
+ .functionality = efm32_i2c_functionality,
+};
+
+static u32 efm32_i2c_get_configured_location(struct efm32_i2c_ddata *ddata)
+{
+ u32 reg = efm32_i2c_read32(ddata, REG_ROUTE);
+
+ return (reg & REG_ROUTE_LOCATION__MASK) >>
+ __ffs(REG_ROUTE_LOCATION__MASK);
+}
+
+static int efm32_i2c_probe(struct platform_device *pdev)
+{
+ struct efm32_i2c_ddata *ddata;
+ struct resource *res;
+ unsigned long rate;
+ struct device_node *np = pdev->dev.of_node;
+ u32 location, frequency;
+ int ret;
+ u32 clkdiv;
+
+ if (!np)
+ return -EINVAL;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, ddata);
+
+ init_completion(&ddata->done);
+ strlcpy(ddata->adapter.name, pdev->name, sizeof(ddata->adapter.name));
+ ddata->adapter.owner = THIS_MODULE;
+ ddata->adapter.algo = &efm32_i2c_algo;
+ ddata->adapter.dev.parent = &pdev->dev;
+ ddata->adapter.dev.of_node = pdev->dev.of_node;
+ i2c_set_adapdata(&ddata->adapter, ddata);
+
+ ddata->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ddata->clk)) {
+ ret = PTR_ERR(ddata->clk);
+ dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to determine base address\n");
+ return -ENODEV;
+ }
+
+ if (resource_size(res) < 0x42) {
+ dev_err(&pdev->dev, "memory resource too small\n");
+ return -EINVAL;
+ }
+
+ ddata->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ddata->base))
+ return PTR_ERR(ddata->base);
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "failed to get irq (%d)\n", ret);
+ if (!ret)
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ddata->irq = ret;
+
+ ret = clk_prepare_enable(ddata->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
+ return ret;
+ }
+
+
+ ret = of_property_read_u32(np, "energymicro,location", &location);
+
+ if (ret)
+ /* fall back to wrongly namespaced property */
+ ret = of_property_read_u32(np, "efm32,location", &location);
+
+ if (!ret) {
+ dev_dbg(&pdev->dev, "using location %u\n", location);
+ } else {
+ /* default to location configured in hardware */
+ location = efm32_i2c_get_configured_location(ddata);
+
+ dev_info(&pdev->dev, "fall back to location %u\n", location);
+ }
+
+ ddata->location = location;
+
+ ret = of_property_read_u32(np, "clock-frequency", &frequency);
+ if (!ret) {
+ dev_dbg(&pdev->dev, "using frequency %u\n", frequency);
+ } else {
+ frequency = 100000;
+ dev_info(&pdev->dev, "defaulting to 100 kHz\n");
+ }
+ ddata->frequency = frequency;
+
+ rate = clk_get_rate(ddata->clk);
+ if (!rate) {
+ dev_err(&pdev->dev, "there is no input clock available\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
+ clkdiv = DIV_ROUND_UP(rate, 8 * ddata->frequency) - 1;
+ if (clkdiv >= 0x200) {
+ dev_err(&pdev->dev,
+ "input clock too fast (%lu) to divide down to bus freq (%lu)",
+ rate, ddata->frequency);
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
+
+ dev_dbg(&pdev->dev, "input clock = %lu, bus freq = %lu, clkdiv = %lu\n",
+ rate, ddata->frequency, (unsigned long)clkdiv);
+ efm32_i2c_write32(ddata, REG_CLKDIV, REG_CLKDIV_DIV(clkdiv));
+
+ efm32_i2c_write32(ddata, REG_ROUTE, REG_ROUTE_SDAPEN |
+ REG_ROUTE_SCLPEN |
+ REG_ROUTE_LOCATION(ddata->location));
+
+ efm32_i2c_write32(ddata, REG_CTRL, REG_CTRL_EN |
+ REG_CTRL_BITO_160PCC | 0 * REG_CTRL_GIBITO);
+
+ efm32_i2c_write32(ddata, REG_IFC, REG_IFC__MASK);
+ efm32_i2c_write32(ddata, REG_IEN, REG_IF_TXC | REG_IF_ACK | REG_IF_NACK
+ | REG_IF_ARBLOST | REG_IF_BUSERR | REG_IF_RXDATAV);
+
+ /* to make bus idle */
+ efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ABORT);
+
+ ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
+ goto err_disable_clk;
+ }
+
+ ret = i2c_add_adapter(&ddata->adapter);
+ if (ret) {
+ free_irq(ddata->irq, ddata);
+
+err_disable_clk:
+ clk_disable_unprepare(ddata->clk);
+ }
+ return ret;
+}
+
+static int efm32_i2c_remove(struct platform_device *pdev)
+{
+ struct efm32_i2c_ddata *ddata = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&ddata->adapter);
+ free_irq(ddata->irq, ddata);
+ clk_disable_unprepare(ddata->clk);
+
+ return 0;
+}
+
+static const struct of_device_id efm32_i2c_dt_ids[] = {
+ {
+ .compatible = "energymicro,efm32-i2c",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, efm32_i2c_dt_ids);
+
+static struct platform_driver efm32_i2c_driver = {
+ .probe = efm32_i2c_probe,
+ .remove = efm32_i2c_remove,
+
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = efm32_i2c_dt_ids,
+ },
+};
+module_platform_driver(efm32_i2c_driver);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 i2c driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
new file mode 100644
index 000000000..44025507b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -0,0 +1,939 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * 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 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+
+#define PCH_EVENT_SET 0 /* I2C Interrupt Event Set Status */
+#define PCH_EVENT_NONE 1 /* I2C Interrupt Event Clear Status */
+#define PCH_MAX_CLK 100000 /* Maximum Clock speed in MHz */
+#define PCH_BUFFER_MODE_ENABLE 0x0002 /* flag for Buffer mode enable */
+#define PCH_EEPROM_SW_RST_MODE_ENABLE 0x0008 /* EEPROM SW RST enable flag */
+
+#define PCH_I2CSADR 0x00 /* I2C slave address register */
+#define PCH_I2CCTL 0x04 /* I2C control register */
+#define PCH_I2CSR 0x08 /* I2C status register */
+#define PCH_I2CDR 0x0C /* I2C data register */
+#define PCH_I2CMON 0x10 /* I2C bus monitor register */
+#define PCH_I2CBC 0x14 /* I2C bus transfer rate setup counter */
+#define PCH_I2CMOD 0x18 /* I2C mode register */
+#define PCH_I2CBUFSLV 0x1C /* I2C buffer mode slave address register */
+#define PCH_I2CBUFSUB 0x20 /* I2C buffer mode subaddress register */
+#define PCH_I2CBUFFOR 0x24 /* I2C buffer mode format register */
+#define PCH_I2CBUFCTL 0x28 /* I2C buffer mode control register */
+#define PCH_I2CBUFMSK 0x2C /* I2C buffer mode interrupt mask register */
+#define PCH_I2CBUFSTA 0x30 /* I2C buffer mode status register */
+#define PCH_I2CBUFLEV 0x34 /* I2C buffer mode level register */
+#define PCH_I2CESRFOR 0x38 /* EEPROM software reset mode format register */
+#define PCH_I2CESRCTL 0x3C /* EEPROM software reset mode ctrl register */
+#define PCH_I2CESRMSK 0x40 /* EEPROM software reset mode */
+#define PCH_I2CESRSTA 0x44 /* EEPROM software reset mode status register */
+#define PCH_I2CTMR 0x48 /* I2C timer register */
+#define PCH_I2CSRST 0xFC /* I2C reset register */
+#define PCH_I2CNF 0xF8 /* I2C noise filter register */
+
+#define BUS_IDLE_TIMEOUT 20
+#define PCH_I2CCTL_I2CMEN 0x0080
+#define TEN_BIT_ADDR_DEFAULT 0xF000
+#define TEN_BIT_ADDR_MASK 0xF0
+#define PCH_START 0x0020
+#define PCH_RESTART 0x0004
+#define PCH_ESR_START 0x0001
+#define PCH_BUFF_START 0x1
+#define PCH_REPSTART 0x0004
+#define PCH_ACK 0x0008
+#define PCH_GETACK 0x0001
+#define CLR_REG 0x0
+#define I2C_RD 0x1
+#define I2CMCF_BIT 0x0080
+#define I2CMIF_BIT 0x0002
+#define I2CMAL_BIT 0x0010
+#define I2CBMFI_BIT 0x0001
+#define I2CBMAL_BIT 0x0002
+#define I2CBMNA_BIT 0x0004
+#define I2CBMTO_BIT 0x0008
+#define I2CBMIS_BIT 0x0010
+#define I2CESRFI_BIT 0X0001
+#define I2CESRTO_BIT 0x0002
+#define I2CESRFIIE_BIT 0x1
+#define I2CESRTOIE_BIT 0x2
+#define I2CBMDZ_BIT 0x0040
+#define I2CBMAG_BIT 0x0020
+#define I2CMBB_BIT 0x0020
+#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
+ I2CBMTO_BIT | I2CBMIS_BIT)
+#define I2C_ADDR_MSK 0xFF
+#define I2C_MSB_2B_MSK 0x300
+#define FAST_MODE_CLK 400
+#define FAST_MODE_EN 0x0001
+#define SUB_ADDR_LEN_MAX 4
+#define BUF_LEN_MAX 32
+#define PCH_BUFFER_MODE 0x1
+#define EEPROM_SW_RST_MODE 0x0002
+#define NORMAL_INTR_ENBL 0x0300
+#define EEPROM_RST_INTR_ENBL (I2CESRFIIE_BIT | I2CESRTOIE_BIT)
+#define EEPROM_RST_INTR_DISBL 0x0
+#define BUFFER_MODE_INTR_ENBL 0x001F
+#define BUFFER_MODE_INTR_DISBL 0x0
+#define NORMAL_MODE 0x0
+#define BUFFER_MODE 0x1
+#define EEPROM_SR_MODE 0x2
+#define I2C_TX_MODE 0x0010
+#define PCH_BUF_TX 0xFFF7
+#define PCH_BUF_RD 0x0008
+#define I2C_ERROR_MASK (I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \
+ I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT)
+#define I2CMAL_EVENT 0x0001
+#define I2CMCF_EVENT 0x0002
+#define I2CBMFI_EVENT 0x0004
+#define I2CBMAL_EVENT 0x0008
+#define I2CBMNA_EVENT 0x0010
+#define I2CBMTO_EVENT 0x0020
+#define I2CBMIS_EVENT 0x0040
+#define I2CESRFI_EVENT 0x0080
+#define I2CESRTO_EVENT 0x0100
+#define PCI_DEVICE_ID_PCH_I2C 0x8817
+
+#define pch_dbg(adap, fmt, arg...) \
+ dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_err(adap, fmt, arg...) \
+ dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_err(pdev, fmt, arg...) \
+ dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_dbg(pdev, fmt, arg...) \
+ dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+/*
+Set the number of I2C instance max
+Intel EG20T PCH : 1ch
+LAPIS Semiconductor ML7213 IOH : 2ch
+LAPIS Semiconductor ML7831 IOH : 1ch
+*/
+#define PCH_I2C_MAX_DEV 2
+
+/**
+ * struct i2c_algo_pch_data - for I2C driver functionalities
+ * @pch_adapter: stores the reference to i2c_adapter structure
+ * @p_adapter_info: stores the reference to adapter_info structure
+ * @pch_base_address: specifies the remapped base address
+ * @pch_buff_mode_en: specifies if buffer mode is enabled
+ * @pch_event_flag: specifies occurrence of interrupt events
+ * @pch_i2c_xfer_in_progress: specifies whether the transfer is completed
+ */
+struct i2c_algo_pch_data {
+ struct i2c_adapter pch_adapter;
+ struct adapter_info *p_adapter_info;
+ void __iomem *pch_base_address;
+ int pch_buff_mode_en;
+ u32 pch_event_flag;
+ bool pch_i2c_xfer_in_progress;
+};
+
+/**
+ * struct adapter_info - This structure holds the adapter information for the
+ PCH i2c controller
+ * @pch_data: stores a list of i2c_algo_pch_data
+ * @pch_i2c_suspended: specifies whether the system is suspended or not
+ * perhaps with more lines and words.
+ * @ch_num: specifies the number of i2c instance
+ *
+ * pch_data has as many elements as maximum I2C channels
+ */
+struct adapter_info {
+ struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
+ bool pch_i2c_suspended;
+ int ch_num;
+};
+
+
+static int pch_i2c_speed = 100; /* I2C bus speed in Kbps */
+static int pch_clk = 50000; /* specifies I2C clock speed in KHz */
+static wait_queue_head_t pch_event;
+static DEFINE_MUTEX(pch_mutex);
+
+/* Definition for ML7213 by LAPIS Semiconductor */
+#define PCI_DEVICE_ID_ML7213_I2C 0x802D
+#define PCI_DEVICE_ID_ML7223_I2C 0x8010
+#define PCI_DEVICE_ID_ML7831_I2C 0x8817
+
+static const struct pci_device_id pch_pcidev_id[] = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
+ {0,}
+};
+MODULE_DEVICE_TABLE(pci, pch_pcidev_id);
+
+static irqreturn_t pch_i2c_handler(int irq, void *pData);
+
+static inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+ u32 val;
+ val = ioread32(addr + offset);
+ val |= bitmask;
+ iowrite32(val, addr + offset);
+}
+
+static inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+ u32 val;
+ val = ioread32(addr + offset);
+ val &= (~bitmask);
+ iowrite32(val, addr + offset);
+}
+
+/**
+ * pch_i2c_init() - hardware initialization of I2C module
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_init(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ u32 pch_i2cbc;
+ u32 pch_i2ctmr;
+ u32 reg_value;
+
+ /* reset I2C controller */
+ iowrite32(0x01, p + PCH_I2CSRST);
+ msleep(20);
+ iowrite32(0x0, p + PCH_I2CSRST);
+
+ /* Initialize I2C registers */
+ iowrite32(0x21, p + PCH_I2CNF);
+
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);
+
+ if (pch_i2c_speed != 400)
+ pch_i2c_speed = 100;
+
+ reg_value = PCH_I2CCTL_I2CMEN;
+ if (pch_i2c_speed == FAST_MODE_CLK) {
+ reg_value |= FAST_MODE_EN;
+ pch_dbg(adap, "Fast mode enabled\n");
+ }
+
+ if (pch_clk > PCH_MAX_CLK)
+ pch_clk = 62500;
+
+ pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8);
+ /* Set transfer speed in I2CBC */
+ iowrite32(pch_i2cbc, p + PCH_I2CBC);
+
+ pch_i2ctmr = (pch_clk) / 8;
+ iowrite32(pch_i2ctmr, p + PCH_I2CTMR);
+
+ reg_value |= NORMAL_INTR_ENBL; /* Enable interrupts in normal mode */
+ iowrite32(reg_value, p + PCH_I2CCTL);
+
+ pch_dbg(adap,
+ "I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts\n",
+ ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr);
+
+ init_waitqueue_head(&pch_event);
+}
+
+/**
+ * pch_i2c_wait_for_bus_idle() - check the status of bus.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ * @timeout: waiting time counter (ms).
+ */
+static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
+ s32 timeout)
+{
+ void __iomem *p = adap->pch_base_address;
+ int schedule = 0;
+ unsigned long end = jiffies + msecs_to_jiffies(timeout);
+
+ while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) {
+ if (time_after(jiffies, end)) {
+ pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+ pch_err(adap, "%s: Timeout Error.return%d\n",
+ __func__, -ETIME);
+ pch_i2c_init(adap);
+
+ return -ETIME;
+ }
+
+ if (!schedule)
+ /* Retry after some usecs */
+ udelay(5);
+ else
+ /* Wait a bit more without consuming CPU */
+ usleep_range(20, 1000);
+
+ schedule = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_i2c_start() - Generate I2C start condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1.
+ */
+static void pch_i2c_start(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_stop() - generate stop condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_stop(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ /* clear the start bit */
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+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));
+ if (!ret) {
+ pch_err(adap, "%s:wait-event timeout\n", __func__);
+ adap->pch_event_flag = 0;
+ pch_i2c_stop(adap);
+ pch_i2c_init(adap);
+ return -ETIMEDOUT;
+ }
+
+ if (adap->pch_event_flag & I2C_ERROR_MASK) {
+ pch_err(adap, "Lost Arbitration\n");
+ adap->pch_event_flag = 0;
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
+ pch_i2c_init(adap);
+ return -EAGAIN;
+ }
+
+ adap->pch_event_flag = 0;
+
+ if (ioread32(p + PCH_I2CSR) & PCH_GETACK) {
+ pch_dbg(adap, "Receive NACK for slave address setting\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+/**
+ * pch_i2c_repstart() - generate repeated start condition in normal mode
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_repstart(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART);
+}
+
+/**
+ * pch_i2c_writebytes() - write data to I2C bus in normal mode
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @last: specifies whether last message or not.
+ * In the case of compound mode it will be 1 for last message,
+ * otherwise 0.
+ * @first: specifies whether first message or not.
+ * 1 for first message otherwise 0.
+ */
+static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, u32 last, u32 first)
+{
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+ u8 *buf;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ u32 addr_8_lsb;
+ s32 wrcount;
+ s32 rtn;
+ void __iomem *p = adap->pch_base_address;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master tx */
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+ pch_dbg(adap, "I2CCTL = %x msgs->len = %d\n", ioread32(p + PCH_I2CCTL),
+ length);
+
+ if (first) {
+ if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+ return -ETIME;
+ }
+
+ if (msgs->flags & I2C_M_TEN) {
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ addr_8_lsb = (addr & I2C_ADDR_MSK);
+ iowrite32(addr_8_lsb, p + PCH_I2CDR);
+ } else {
+ /* set 7 bit slave address and R/W bit as 0 */
+ iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+ }
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ for (wrcount = 0; wrcount < length; ++wrcount) {
+ /* write buffer value to I2C data register */
+ iowrite32(buf[wrcount], p + PCH_I2CDR);
+ pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]);
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMCF_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
+ }
+
+ /* check if this is the last message */
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+
+ pch_dbg(adap, "return=%d\n", wrcount);
+
+ return wrcount;
+}
+
+/**
+ * pch_i2c_sendack() - send ACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendack(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_sendnack() - send NACK
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_restart() - Generate I2C restart condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA.
+ */
+static void pch_i2c_restart(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART);
+}
+
+/**
+ * pch_i2c_readbytes() - read data from I2C bus in normal mode.
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @msgs: Pointer to i2c_msg structure.
+ * @last: specifies whether last message or not.
+ * @first: specifies whether first message or not.
+ */
+static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ u32 last, u32 first)
+{
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+ u8 *buf;
+ u32 count;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ u32 addr_8_lsb;
+ void __iomem *p = adap->pch_base_address;
+ s32 rtn;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master reception */
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+ if (first) {
+ if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+ return -ETIME;
+ }
+
+ if (msgs->flags & I2C_M_TEN) {
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ addr_8_lsb = (addr & I2C_ADDR_MSK);
+ iowrite32(addr_8_lsb, p + PCH_I2CDR);
+
+ pch_i2c_restart(adap);
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ addr_2_msb |= I2C_RD;
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ } else {
+ /* 7 address bits + R/W bit */
+ iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
+ }
+
+ /* check if it is the first message */
+ if (first)
+ pch_i2c_start(adap);
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ if (length == 0) {
+ pch_i2c_stop(adap);
+ ioread32(p + PCH_I2CDR); /* Dummy read needs */
+
+ count = length;
+ } else {
+ int read_index;
+ int loop;
+ pch_i2c_sendack(adap);
+
+ /* Dummy read */
+ for (loop = 1, read_index = 0; loop < length; loop++) {
+ buf[read_index] = ioread32(p + PCH_I2CDR);
+
+ if (loop != 1)
+ read_index++;
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+ } /* end for */
+
+ pch_i2c_sendnack(adap);
+
+ buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */
+
+ if (length != 1)
+ read_index++;
+
+ rtn = pch_i2c_wait_for_check_xfer(adap);
+ if (rtn)
+ return rtn;
+
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+
+ buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */
+ count = read_index;
+ }
+
+ return count;
+}
+
+/**
+ * pch_i2c_cb() - Interrupt handler Call back function
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
+{
+ u32 sts;
+ void __iomem *p = adap->pch_base_address;
+
+ sts = ioread32(p + PCH_I2CSR);
+ sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT);
+ if (sts & I2CMAL_BIT)
+ adap->pch_event_flag |= I2CMAL_EVENT;
+
+ if (sts & I2CMCF_BIT)
+ adap->pch_event_flag |= I2CMCF_EVENT;
+
+ /* clear the applicable bits */
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts);
+
+ pch_dbg(adap, "PCH_I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+
+ wake_up(&pch_event);
+}
+
+/**
+ * pch_i2c_handler() - interrupt handler for the PCH I2C controller
+ * @irq: irq number.
+ * @pData: cookie passed back to the handler function.
+ */
+static irqreturn_t pch_i2c_handler(int irq, void *pData)
+{
+ u32 reg_val;
+ int flag;
+ int i;
+ struct adapter_info *adap_info = pData;
+ void __iomem *p;
+ u32 mode;
+
+ for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
+ p = adap_info->pch_data[i].pch_base_address;
+ mode = ioread32(p + PCH_I2CMOD);
+ mode &= BUFFER_MODE | EEPROM_SR_MODE;
+ if (mode != NORMAL_MODE) {
+ pch_err(adap_info->pch_data,
+ "I2C-%d mode(%d) is not supported\n", mode, i);
+ continue;
+ }
+ reg_val = ioread32(p + PCH_I2CSR);
+ if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
+ pch_i2c_cb(&adap_info->pch_data[i]);
+ flag = 1;
+ }
+ }
+
+ return flag ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * pch_i2c_xfer() - Reading adnd writing data through I2C bus
+ * @i2c_adap: Pointer to the struct i2c_adapter.
+ * @msgs: Pointer to i2c_msg structure.
+ * @num: number of messages.
+ */
+static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, s32 num)
+{
+ struct i2c_msg *pmsg;
+ u32 i = 0;
+ u32 status;
+ s32 ret;
+
+ struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+ ret = mutex_lock_interruptible(&pch_mutex);
+ if (ret)
+ return ret;
+
+ if (adap->p_adapter_info->pch_i2c_suspended) {
+ mutex_unlock(&pch_mutex);
+ return -EBUSY;
+ }
+
+ pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d\n",
+ adap->p_adapter_info->pch_i2c_suspended);
+ /* transfer not completed */
+ adap->pch_i2c_xfer_in_progress = true;
+
+ for (i = 0; i < num && ret >= 0; i++) {
+ pmsg = &msgs[i];
+ pmsg->flags |= adap->pch_buff_mode_en;
+ status = pmsg->flags;
+ pch_dbg(adap,
+ "After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
+
+ if ((status & (I2C_M_RD)) != false) {
+ ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ } else {
+ ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ }
+ }
+
+ adap->pch_i2c_xfer_in_progress = false; /* transfer completed */
+
+ mutex_unlock(&pch_mutex);
+
+ return (ret < 0) ? ret : num;
+}
+
+/**
+ * pch_i2c_func() - return the functionality of the I2C driver
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static u32 pch_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm pch_algorithm = {
+ .master_xfer = pch_i2c_xfer,
+ .functionality = pch_i2c_func
+};
+
+/**
+ * pch_i2c_disbl_int() - Disable PCH I2C interrupts
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+
+ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL);
+
+ iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK);
+
+ iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK);
+}
+
+static int pch_i2c_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *base_addr;
+ int ret;
+ int i, j;
+ struct adapter_info *adap_info;
+ struct i2c_adapter *pch_adap;
+
+ pch_pci_dbg(pdev, "Entered.\n");
+
+ adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
+ if (adap_info == NULL)
+ return -ENOMEM;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ pch_pci_err(pdev, "pci_enable_device FAILED\n");
+ goto err_pci_enable;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ pch_pci_err(pdev, "pci_request_regions FAILED\n");
+ goto err_pci_req;
+ }
+
+ base_addr = pci_iomap(pdev, 1, 0);
+
+ if (base_addr == NULL) {
+ pch_pci_err(pdev, "pci_iomap FAILED\n");
+ ret = -ENOMEM;
+ goto err_pci_iomap;
+ }
+
+ /* Set the number of I2C channel instance */
+ adap_info->ch_num = id->driver_data;
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ pch_adap = &adap_info->pch_data[i].pch_adapter;
+ adap_info->pch_i2c_suspended = false;
+
+ adap_info->pch_data[i].p_adapter_info = adap_info;
+
+ pch_adap->owner = THIS_MODULE;
+ pch_adap->class = I2C_CLASS_HWMON;
+ strlcpy(pch_adap->name, KBUILD_MODNAME, sizeof(pch_adap->name));
+ pch_adap->algo = &pch_algorithm;
+ pch_adap->algo_data = &adap_info->pch_data[i];
+
+ /* base_addr + offset; */
+ adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
+
+ pch_adap->dev.of_node = pdev->dev.of_node;
+ pch_adap->dev.parent = &pdev->dev;
+ }
+
+ ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+ KBUILD_MODNAME, adap_info);
+ if (ret) {
+ pch_pci_err(pdev, "request_irq FAILED\n");
+ goto err_request_irq;
+ }
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ pch_adap = &adap_info->pch_data[i].pch_adapter;
+
+ pch_i2c_init(&adap_info->pch_data[i]);
+
+ pch_adap->nr = i;
+ ret = i2c_add_numbered_adapter(pch_adap);
+ if (ret) {
+ pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
+ goto err_add_adapter;
+ }
+ }
+
+ pci_set_drvdata(pdev, adap_info);
+ pch_pci_dbg(pdev, "returns %d.\n", ret);
+ return 0;
+
+err_add_adapter:
+ for (j = 0; j < i; j++)
+ i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
+ free_irq(pdev->irq, adap_info);
+err_request_irq:
+ pci_iounmap(pdev, base_addr);
+err_pci_iomap:
+ pci_release_regions(pdev);
+err_pci_req:
+ pci_disable_device(pdev);
+err_pci_enable:
+ kfree(adap_info);
+ return ret;
+}
+
+static void pch_i2c_remove(struct pci_dev *pdev)
+{
+ int i;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ free_irq(pdev->irq, adap_info);
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ pch_i2c_disbl_int(&adap_info->pch_data[i]);
+ i2c_del_adapter(&adap_info->pch_data[i].pch_adapter);
+ }
+
+ if (adap_info->pch_data[0].pch_base_address)
+ pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
+
+ for (i = 0; i < adap_info->ch_num; i++)
+ adap_info->pch_data[i].pch_base_address = NULL;
+
+ pci_release_regions(pdev);
+
+ pci_disable_device(pdev);
+ kfree(adap_info);
+}
+
+#ifdef CONFIG_PM
+static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int ret;
+ int i;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+ void __iomem *p = adap_info->pch_data[0].pch_base_address;
+
+ adap_info->pch_i2c_suspended = true;
+
+ for (i = 0; i < adap_info->ch_num; i++) {
+ while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
+ /* Wait until all channel transfers are completed */
+ msleep(20);
+ }
+ }
+
+ /* Disable the i2c interrupts */
+ for (i = 0; i < adap_info->ch_num; i++)
+ pch_i2c_disbl_int(&adap_info->pch_data[i]);
+
+ pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
+ "invoked function pch_i2c_disbl_int successfully\n",
+ ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
+ ioread32(p + PCH_I2CESRSTA));
+
+ ret = pci_save_state(pdev);
+
+ if (ret) {
+ pch_pci_err(pdev, "pci_save_state\n");
+ return ret;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int pch_i2c_resume(struct pci_dev *pdev)
+{
+ int i;
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (pci_enable_device(pdev) < 0) {
+ pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED\n");
+ return -EIO;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ for (i = 0; i < adap_info->ch_num; i++)
+ pch_i2c_init(&adap_info->pch_data[i]);
+
+ adap_info->pch_i2c_suspended = false;
+
+ return 0;
+}
+#else
+#define pch_i2c_suspend NULL
+#define pch_i2c_resume NULL
+#endif
+
+static struct pci_driver pch_pcidriver = {
+ .name = KBUILD_MODNAME,
+ .id_table = pch_pcidev_id,
+ .probe = pch_i2c_probe,
+ .remove = pch_i2c_remove,
+ .suspend = pch_i2c_suspend,
+ .resume = pch_i2c_resume
+};
+
+module_pci_driver(pch_pcidriver);
+
+MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomoya MORINAGA. <tomoya.rohm@gmail.com>");
+module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
+module_param(pch_clk, int, (S_IRUSR | S_IWUSR));
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
new file mode 100644
index 000000000..5416003e0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -0,0 +1,331 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-97 Simon G. Vogl
+ 1998-99 Hans Berglund
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+ Frodo Looijaard <frodol@dds.nl> */
+
+/* Partially rewriten by Oleg I. Vdovikin for mmapped support of
+ for Alpha Processor Inc. UP-2000(+) boards */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+
+#include <linux/isa.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include "../algos/i2c-algo-pcf.h"
+
+#define DEFAULT_BASE 0x330
+
+static int base;
+static u8 __iomem *base_iomem;
+
+static int irq;
+static int clock = 0x1c;
+static int own = 0x55;
+static int mmapped;
+
+/* vdovikin: removed static struct i2c_pcf_isa gpi; code -
+ this module in real supports only one device, due to missing arguments
+ in some functions, called from the algo-pcf module. Sometimes it's
+ need to be rewriten - but for now just remove this for simpler reading */
+
+static wait_queue_head_t pcf_wait;
+static int pcf_pending;
+static spinlock_t lock;
+
+static struct i2c_adapter pcf_isa_ops;
+
+/* ----- local functions ---------------------------------------------- */
+
+static void pcf_isa_setbyte(void *data, int ctl, int val)
+{
+ u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
+
+ /* enable irq if any specified for serial operation */
+ if (ctl && irq && (val & I2C_PCF_ESO)) {
+ val |= I2C_PCF_ENI;
+ }
+
+ pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val);
+ iowrite8(val, address);
+#ifdef __alpha__
+ /* API UP2000 needs some hardware fudging to make the write stick */
+ iowrite8(val, address);
+#endif
+}
+
+static int pcf_isa_getbyte(void *data, int ctl)
+{
+ u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
+ int val = ioread8(address);
+
+ pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val);
+ return (val);
+}
+
+static int pcf_isa_getown(void *data)
+{
+ return (own);
+}
+
+
+static int pcf_isa_getclock(void *data)
+{
+ return (clock);
+}
+
+static void pcf_isa_waitforpin(void *data)
+{
+ DEFINE_WAIT(wait);
+ int timeout = 2;
+ unsigned long flags;
+
+ if (irq > 0) {
+ spin_lock_irqsave(&lock, flags);
+ if (pcf_pending == 0) {
+ spin_unlock_irqrestore(&lock, flags);
+ prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
+ if (schedule_timeout(timeout*HZ)) {
+ spin_lock_irqsave(&lock, flags);
+ if (pcf_pending == 1) {
+ pcf_pending = 0;
+ }
+ spin_unlock_irqrestore(&lock, flags);
+ }
+ finish_wait(&pcf_wait, &wait);
+ } else {
+ pcf_pending = 0;
+ spin_unlock_irqrestore(&lock, flags);
+ }
+ } else {
+ udelay(100);
+ }
+}
+
+
+static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
+ spin_lock(&lock);
+ pcf_pending = 1;
+ spin_unlock(&lock);
+ wake_up_interruptible(&pcf_wait);
+ return IRQ_HANDLED;
+}
+
+
+static int pcf_isa_init(void)
+{
+ spin_lock_init(&lock);
+ if (!mmapped) {
+ if (!request_region(base, 2, pcf_isa_ops.name)) {
+ printk(KERN_ERR "%s: requested I/O region (%#x:2) is "
+ "in use\n", pcf_isa_ops.name, base);
+ return -ENODEV;
+ }
+ base_iomem = ioport_map(base, 2);
+ if (!base_iomem) {
+ printk(KERN_ERR "%s: remap of I/O region %#x failed\n",
+ pcf_isa_ops.name, base);
+ release_region(base, 2);
+ return -ENODEV;
+ }
+ } else {
+ if (!request_mem_region(base, 2, pcf_isa_ops.name)) {
+ printk(KERN_ERR "%s: requested memory region (%#x:2) "
+ "is in use\n", pcf_isa_ops.name, base);
+ return -ENODEV;
+ }
+ base_iomem = ioremap(base, 2);
+ if (base_iomem == NULL) {
+ printk(KERN_ERR "%s: remap of memory region %#x "
+ "failed\n", pcf_isa_ops.name, base);
+ release_mem_region(base, 2);
+ return -ENODEV;
+ }
+ }
+ pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base,
+ base_iomem);
+
+ if (irq > 0) {
+ if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name,
+ NULL) < 0) {
+ printk(KERN_ERR "%s: Request irq%d failed\n",
+ pcf_isa_ops.name, irq);
+ irq = 0;
+ } else
+ enable_irq(irq);
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+static struct i2c_algo_pcf_data pcf_isa_data = {
+ .setpcf = pcf_isa_setbyte,
+ .getpcf = pcf_isa_getbyte,
+ .getown = pcf_isa_getown,
+ .getclock = pcf_isa_getclock,
+ .waitforpin = pcf_isa_waitforpin,
+};
+
+static struct i2c_adapter pcf_isa_ops = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo_data = &pcf_isa_data,
+ .name = "i2c-elektor",
+};
+
+static int elektor_match(struct device *dev, unsigned int id)
+{
+#ifdef __alpha__
+ /* check to see we have memory mapped PCF8584 connected to the
+ Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
+ if (base == 0) {
+ struct pci_dev *cy693_dev;
+
+ cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
+ PCI_DEVICE_ID_CONTAQ_82C693, NULL);
+ if (cy693_dev) {
+ unsigned char config;
+ /* yeap, we've found cypress, let's check config */
+ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
+
+ dev_dbg(dev, "found cy82c693, config "
+ "register 0x47 = 0x%02x\n", config);
+
+ /* UP2000 board has this register set to 0xe1,
+ but the most significant bit as seems can be
+ reset during the proper initialisation
+ sequence if guys from API decides to do that
+ (so, we can even enable Tsunami Pchip
+ window for the upper 1 Gb) */
+
+ /* so just check for ROMCS at 0xe0000,
+ ROMCS enabled for writes
+ and external XD Bus buffer in use. */
+ if ((config & 0x7f) == 0x61) {
+ /* seems to be UP2000 like board */
+ base = 0xe0000;
+ mmapped = 1;
+ /* UP2000 drives ISA with
+ 8.25 MHz (PCI/4) clock
+ (this can be read from cypress) */
+ clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
+ dev_info(dev, "found API UP2000 like "
+ "board, will probe PCF8584 "
+ "later\n");
+ }
+ }
+ pci_dev_put(cy693_dev);
+ }
+ }
+#endif
+
+ /* sanity checks for mmapped I/O */
+ if (mmapped && base < 0xc8000) {
+ dev_err(dev, "incorrect base address (%#x) specified "
+ "for mmapped I/O\n", base);
+ return 0;
+ }
+
+ if (base == 0) {
+ base = DEFAULT_BASE;
+ }
+ return 1;
+}
+
+static int elektor_probe(struct device *dev, unsigned int id)
+{
+ init_waitqueue_head(&pcf_wait);
+ if (pcf_isa_init())
+ return -ENODEV;
+ pcf_isa_ops.dev.parent = dev;
+ if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+ goto fail;
+
+ dev_info(dev, "found device at %#x\n", base);
+
+ return 0;
+
+ fail:
+ if (irq > 0) {
+ disable_irq(irq);
+ free_irq(irq, NULL);
+ }
+
+ if (!mmapped) {
+ ioport_unmap(base_iomem);
+ release_region(base, 2);
+ } else {
+ iounmap(base_iomem);
+ release_mem_region(base, 2);
+ }
+ return -ENODEV;
+}
+
+static int elektor_remove(struct device *dev, unsigned int id)
+{
+ i2c_del_adapter(&pcf_isa_ops);
+
+ if (irq > 0) {
+ disable_irq(irq);
+ free_irq(irq, NULL);
+ }
+
+ if (!mmapped) {
+ ioport_unmap(base_iomem);
+ release_region(base, 2);
+ } else {
+ iounmap(base_iomem);
+ release_mem_region(base, 2);
+ }
+
+ return 0;
+}
+
+static struct isa_driver i2c_elektor_driver = {
+ .match = elektor_match,
+ .probe = elektor_probe,
+ .remove = elektor_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-elektor",
+ },
+};
+
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
+MODULE_LICENSE("GPL");
+
+module_param_hw(base, int, ioport_or_iomem, 0);
+module_param_hw(irq, int, irq, 0);
+module_param(clock, int, 0);
+module_param(own, int, 0);
+module_param_hw(mmapped, int, other, 0);
+module_isa_driver(i2c_elektor_driver, 1);
diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c
new file mode 100644
index 000000000..0230a13a6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-emev2.c
@@ -0,0 +1,452 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * I2C driver for the Renesas EMEV2 SoC
+ *
+ * Copyright (C) 2015 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright 2013 Codethink Ltd.
+ * Copyright 2010-2015 Renesas Electronics Corporation
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+
+/* I2C Registers */
+#define I2C_OFS_IICACT0 0x00 /* start */
+#define I2C_OFS_IIC0 0x04 /* shift */
+#define I2C_OFS_IICC0 0x08 /* control */
+#define I2C_OFS_SVA0 0x0c /* slave address */
+#define I2C_OFS_IICCL0 0x10 /* clock select */
+#define I2C_OFS_IICX0 0x14 /* extension */
+#define I2C_OFS_IICS0 0x18 /* status */
+#define I2C_OFS_IICSE0 0x1c /* status For emulation */
+#define I2C_OFS_IICF0 0x20 /* IIC flag */
+
+/* I2C IICACT0 Masks */
+#define I2C_BIT_IICE0 0x0001
+
+/* I2C IICC0 Masks */
+#define I2C_BIT_LREL0 0x0040
+#define I2C_BIT_WREL0 0x0020
+#define I2C_BIT_SPIE0 0x0010
+#define I2C_BIT_WTIM0 0x0008
+#define I2C_BIT_ACKE0 0x0004
+#define I2C_BIT_STT0 0x0002
+#define I2C_BIT_SPT0 0x0001
+
+/* I2C IICCL0 Masks */
+#define I2C_BIT_SMC0 0x0008
+#define I2C_BIT_DFC0 0x0004
+
+/* I2C IICSE0 Masks */
+#define I2C_BIT_MSTS0 0x0080
+#define I2C_BIT_ALD0 0x0040
+#define I2C_BIT_EXC0 0x0020
+#define I2C_BIT_COI0 0x0010
+#define I2C_BIT_TRC0 0x0008
+#define I2C_BIT_ACKD0 0x0004
+#define I2C_BIT_STD0 0x0002
+#define I2C_BIT_SPD0 0x0001
+
+/* I2C IICF0 Masks */
+#define I2C_BIT_STCF 0x0080
+#define I2C_BIT_IICBSY 0x0040
+#define I2C_BIT_STCEN 0x0002
+#define I2C_BIT_IICRSV 0x0001
+
+struct em_i2c_device {
+ void __iomem *base;
+ struct i2c_adapter adap;
+ struct completion msg_done;
+ struct clk *sclk;
+ struct i2c_client *slave;
+ int irq;
+};
+
+static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
+{
+ writeb((readb(priv->base + reg) & ~clear) | set, priv->base + reg);
+}
+
+static int em_i2c_wait_for_event(struct em_i2c_device *priv)
+{
+ unsigned long time_left;
+ int status;
+
+ reinit_completion(&priv->msg_done);
+
+ time_left = wait_for_completion_timeout(&priv->msg_done, priv->adap.timeout);
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ status = readb(priv->base + I2C_OFS_IICSE0);
+ return status & I2C_BIT_ALD0 ? -EAGAIN : status;
+}
+
+static void em_i2c_stop(struct em_i2c_device *priv)
+{
+ /* Send Stop condition */
+ em_clear_set_bit(priv, 0, I2C_BIT_SPT0 | I2C_BIT_SPIE0, I2C_OFS_IICC0);
+
+ /* Wait for stop condition */
+ em_i2c_wait_for_event(priv);
+}
+
+static void em_i2c_reset(struct i2c_adapter *adap)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(adap);
+ int retr;
+
+ /* If I2C active */
+ if (readb(priv->base + I2C_OFS_IICACT0) & I2C_BIT_IICE0) {
+ /* Disable I2C operation */
+ writeb(0, priv->base + I2C_OFS_IICACT0);
+
+ retr = 1000;
+ while (readb(priv->base + I2C_OFS_IICACT0) == 1 && retr)
+ retr--;
+ WARN_ON(retr == 0);
+ }
+
+ /* Transfer mode set */
+ writeb(I2C_BIT_DFC0, priv->base + I2C_OFS_IICCL0);
+
+ /* Can Issue start without detecting a stop, Reservation disabled. */
+ writeb(I2C_BIT_STCEN | I2C_BIT_IICRSV, priv->base + I2C_OFS_IICF0);
+
+ /* I2C enable, 9 bit interrupt mode */
+ writeb(I2C_BIT_WTIM0, priv->base + I2C_OFS_IICC0);
+
+ /* Enable I2C operation */
+ writeb(I2C_BIT_IICE0, priv->base + I2C_OFS_IICACT0);
+
+ retr = 1000;
+ while (readb(priv->base + I2C_OFS_IICACT0) == 0 && retr)
+ retr--;
+ WARN_ON(retr == 0);
+}
+
+static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int stop)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(adap);
+ int count, status, read = !!(msg->flags & I2C_M_RD);
+
+ /* Send start condition */
+ em_clear_set_bit(priv, 0, I2C_BIT_ACKE0 | I2C_BIT_WTIM0, I2C_OFS_IICC0);
+ em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0);
+
+ /* Send slave address and R/W type */
+ writeb(i2c_8bit_addr_from_msg(msg), priv->base + I2C_OFS_IIC0);
+
+ /* Wait for transaction */
+ status = em_i2c_wait_for_event(priv);
+ if (status < 0)
+ goto out_reset;
+
+ /* Received NACK (result of setting slave address and R/W) */
+ if (!(status & I2C_BIT_ACKD0)) {
+ em_i2c_stop(priv);
+ goto out;
+ }
+
+ /* Extra setup for read transactions */
+ if (read) {
+ /* 8 bit interrupt mode */
+ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0, I2C_OFS_IICC0);
+ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0, I2C_OFS_IICC0);
+
+ /* Wait for transaction */
+ status = em_i2c_wait_for_event(priv);
+ if (status < 0)
+ goto out_reset;
+ }
+
+ /* Send / receive data */
+ for (count = 0; count < msg->len; count++) {
+ if (read) { /* Read transaction */
+ msg->buf[count] = readb(priv->base + I2C_OFS_IIC0);
+ em_clear_set_bit(priv, 0, I2C_BIT_WREL0, I2C_OFS_IICC0);
+
+ } else { /* Write transaction */
+ /* Received NACK */
+ if (!(status & I2C_BIT_ACKD0)) {
+ em_i2c_stop(priv);
+ goto out;
+ }
+
+ /* Write data */
+ writeb(msg->buf[count], priv->base + I2C_OFS_IIC0);
+ }
+
+ /* Wait for R/W transaction */
+ status = em_i2c_wait_for_event(priv);
+ if (status < 0)
+ goto out_reset;
+ }
+
+ if (stop)
+ em_i2c_stop(priv);
+
+ return count;
+
+out_reset:
+ em_i2c_reset(adap);
+out:
+ return status < 0 ? status : -ENXIO;
+}
+
+static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(adap);
+ int ret, i;
+
+ if (readb(priv->base + I2C_OFS_IICF0) & I2C_BIT_IICBSY)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ ret = __em_i2c_xfer(adap, &msgs[i], (i == (num - 1)));
+ if (ret < 0)
+ return ret;
+ }
+
+ /* I2C transfer completed */
+ return num;
+}
+
+static bool em_i2c_slave_irq(struct em_i2c_device *priv)
+{
+ u8 status, value;
+ enum i2c_slave_event event;
+ int ret;
+
+ if (!priv->slave)
+ return false;
+
+ status = readb(priv->base + I2C_OFS_IICSE0);
+
+ /* Extension code, do not participate */
+ if (status & I2C_BIT_EXC0) {
+ em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+ return true;
+ }
+
+ /* Stop detected, we don't know if it's for slave or master */
+ if (status & I2C_BIT_SPD0) {
+ /* Notify slave device */
+ i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
+ /* Pretend we did not handle the interrupt */
+ return false;
+ }
+
+ /* Only handle interrupts addressed to us */
+ if (!(status & I2C_BIT_COI0))
+ return false;
+
+ /* Enable stop interrupts */
+ em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0);
+
+ /* Transmission or Reception */
+ if (status & I2C_BIT_TRC0) {
+ if (status & I2C_BIT_ACKD0) {
+ /* 9 bit interrupt mode */
+ em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0);
+
+ /* Send data */
+ event = status & I2C_BIT_STD0 ?
+ I2C_SLAVE_READ_REQUESTED :
+ I2C_SLAVE_READ_PROCESSED;
+ i2c_slave_event(priv->slave, event, &value);
+ writeb(value, priv->base + I2C_OFS_IIC0);
+ } else {
+ /* NACK, stop transmitting */
+ em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
+ }
+ } else {
+ /* 8 bit interrupt mode */
+ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0,
+ I2C_OFS_IICC0);
+ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0,
+ I2C_OFS_IICC0);
+
+ if (status & I2C_BIT_STD0) {
+ i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED,
+ &value);
+ } else {
+ /* Recv data */
+ value = readb(priv->base + I2C_OFS_IIC0);
+ ret = i2c_slave_event(priv->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &value);
+ if (ret < 0)
+ em_clear_set_bit(priv, I2C_BIT_ACKE0, 0,
+ I2C_OFS_IICC0);
+ }
+ }
+
+ return true;
+}
+
+static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id)
+{
+ struct em_i2c_device *priv = dev_id;
+
+ if (em_i2c_slave_irq(priv))
+ return IRQ_HANDLED;
+
+ complete(&priv->msg_done);
+
+ return IRQ_HANDLED;
+}
+
+static u32 em_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
+}
+
+static int em_i2c_reg_slave(struct i2c_client *slave)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+ if (priv->slave)
+ return -EBUSY;
+
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ priv->slave = slave;
+
+ /* Set slave address */
+ writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0);
+
+ return 0;
+}
+
+static int em_i2c_unreg_slave(struct i2c_client *slave)
+{
+ struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
+
+ WARN_ON(!priv->slave);
+
+ writeb(0, priv->base + I2C_OFS_SVA0);
+
+ /*
+ * Wait for interrupt to finish. New slave irqs cannot happen because we
+ * cleared the slave address and, thus, only extension codes will be
+ * detected which do not use the slave ptr.
+ */
+ synchronize_irq(priv->irq);
+ priv->slave = NULL;
+
+ return 0;
+}
+
+static const struct i2c_algorithm em_i2c_algo = {
+ .master_xfer = em_i2c_xfer,
+ .functionality = em_i2c_func,
+ .reg_slave = em_i2c_reg_slave,
+ .unreg_slave = em_i2c_unreg_slave,
+};
+
+static int em_i2c_probe(struct platform_device *pdev)
+{
+ struct em_i2c_device *priv;
+ struct resource *r;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ strlcpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name));
+
+ priv->sclk = devm_clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(priv->sclk))
+ return PTR_ERR(priv->sclk);
+
+ ret = clk_prepare_enable(priv->sclk);
+ if (ret)
+ return ret;
+
+ priv->adap.timeout = msecs_to_jiffies(100);
+ priv->adap.retries = 5;
+ priv->adap.dev.parent = &pdev->dev;
+ priv->adap.algo = &em_i2c_algo;
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.dev.of_node = pdev->dev.of_node;
+
+ init_completion(&priv->msg_done);
+
+ platform_set_drvdata(pdev, priv);
+ i2c_set_adapdata(&priv->adap, priv);
+
+ em_i2c_reset(&priv->adap);
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto err_clk;
+ priv->irq = ret;
+ ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0,
+ "em_i2c", priv);
+ if (ret)
+ goto err_clk;
+
+ ret = i2c_add_adapter(&priv->adap);
+
+ if (ret)
+ goto err_clk;
+
+ dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr,
+ priv->irq);
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(priv->sclk);
+ return ret;
+}
+
+static int em_i2c_remove(struct platform_device *dev)
+{
+ struct em_i2c_device *priv = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&priv->adap);
+ clk_disable_unprepare(priv->sclk);
+
+ return 0;
+}
+
+static const struct of_device_id em_i2c_ids[] = {
+ { .compatible = "renesas,iic-emev2", },
+ { }
+};
+
+static struct platform_driver em_i2c_driver = {
+ .probe = em_i2c_probe,
+ .remove = em_i2c_remove,
+ .driver = {
+ .name = "em-i2c",
+ .of_match_table = em_i2c_ids,
+ }
+};
+module_platform_driver(em_i2c_driver);
+
+MODULE_DESCRIPTION("EMEV2 I2C bus driver");
+MODULE_AUTHOR("Ian Molton and Wolfram Sang <wsa@sang-engineering.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, em_i2c_ids);
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
new file mode 100644
index 000000000..c1ce2299a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -0,0 +1,900 @@
+/**
+ * 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/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_device.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)
+
+/* 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)
+
+/* 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)
+
+#define HSI2C_INT_TRANS_DONE (1u << 7)
+#define HSI2C_INT_TRANS_ABORT (1u << 8)
+#define HSI2C_INT_NO_DEV_ACK (1u << 9)
+#define HSI2C_INT_NO_DEV (1u << 10)
+#define HSI2C_INT_TIMEOUT (1u << 11)
+#define HSI2C_INT_I2C_TRANS (HSI2C_INT_TRANS_DONE | \
+ HSI2C_INT_TRANS_ABORT | \
+ HSI2C_INT_NO_DEV_ACK | \
+ HSI2C_INT_NO_DEV | \
+ HSI2C_INT_TIMEOUT)
+
+/* 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_MANUAL_CMD register bits */
+#define HSI2C_CMD_READ_DATA (1u << 4)
+#define HSI2C_CMD_SEND_STOP (1u << 2)
+
+/* I2C_TRANS_STATUS register bits */
+#define HSI2C_MASTER_BUSY (1u << 17)
+#define HSI2C_SLAVE_BUSY (1u << 16)
+
+/* I2C_TRANS_STATUS register bits for Exynos5 variant */
+#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_TRANS_STATUS register bits for Exynos7 variant */
+#define HSI2C_MASTER_ST_MASK 0xf
+#define HSI2C_MASTER_ST_IDLE 0x0
+#define HSI2C_MASTER_ST_START 0x1
+#define HSI2C_MASTER_ST_RESTART 0x2
+#define HSI2C_MASTER_ST_STOP 0x3
+#define HSI2C_MASTER_ST_MASTER_ID 0x4
+#define HSI2C_MASTER_ST_ADDR0 0x5
+#define HSI2C_MASTER_ST_ADDR1 0x6
+#define HSI2C_MASTER_ST_ADDR2 0x7
+#define HSI2C_MASTER_ST_ADDR_SR 0x8
+#define HSI2C_MASTER_ST_READ 0x9
+#define HSI2C_MASTER_ST_WRITE 0xa
+#define HSI2C_MASTER_ST_NO_ACK 0xb
+#define HSI2C_MASTER_ST_LOSE 0xc
+#define HSI2C_MASTER_ST_WAIT 0xd
+#define HSI2C_MASTER_ST_WAIT_CMD 0xe
+
+/* 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 EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100))
+
+enum i2c_type_exynos {
+ I2C_TYPE_EXYNOS5,
+ I2C_TYPE_EXYNOS7,
+};
+
+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 op_clock;
+
+ /* Version of HS-I2C Hardware */
+ const struct exynos_hsi2c_variant *variant;
+};
+
+/**
+ * struct exynos_hsi2c_variant - platform specific HSI2C driver data
+ * @fifo_depth: the fifo depth supported by the HSI2C module
+ * @hw: the hardware variant of Exynos I2C controller
+ *
+ * Specifies platform specific configuration of HSI2C module.
+ * Note: A structure for driver specific platform data is used for future
+ * expansion of its usage.
+ */
+struct exynos_hsi2c_variant {
+ unsigned int fifo_depth;
+ enum i2c_type_exynos hw;
+};
+
+static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {
+ .fifo_depth = 64,
+ .hw = I2C_TYPE_EXYNOS5,
+};
+
+static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {
+ .fifo_depth = 16,
+ .hw = I2C_TYPE_EXYNOS5,
+};
+
+static const struct exynos_hsi2c_variant exynos7_hsi2c_data = {
+ .fifo_depth = 16,
+ .hw = I2C_TYPE_EXYNOS7,
+};
+
+static const struct of_device_id exynos5_i2c_match[] = {
+ {
+ .compatible = "samsung,exynos5-hsi2c",
+ .data = &exynos5250_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos5250-hsi2c",
+ .data = &exynos5250_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos5260-hsi2c",
+ .data = &exynos5260_hsi2c_data
+ }, {
+ .compatible = "samsung,exynos7-hsi2c",
+ .data = &exynos7_hsi2c_data
+ }, {},
+};
+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, bool hs_timings)
+{
+ 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 op_clk = hs_timings ? i2c->op_clock :
+ (i2c->op_clock >= HSI2C_HS_TX_CLOCK) ? HSI2C_FS_TX_CLOCK :
+ i2c->op_clock;
+ int div, clk_cycle, temp;
+
+ /*
+ * In case of HSI2C controller in Exynos5 series
+ * FPCLK / FI2C =
+ * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
+ *
+ * In case of HSI2C controllers in Exynos7 series
+ * FPCLK / FI2C =
+ * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE
+ *
+ * clk_cycle := TSCLK_L + TSCLK_H
+ * temp := (CLK_DIV + 1) * (clk_cycle + 2)
+ *
+ * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510
+ *
+ */
+ t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
+ temp = clkin / op_clk - 8 - t_ftl_cycle;
+ if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
+ temp -= t_ftl_cycle;
+ div = temp / 512;
+ clk_cycle = temp / (div + 1) - 2;
+ if (temp < 4 || div >= 256 || clk_cycle < 2) {
+ dev_err(i2c->dev, "%s clock set-up failed\n",
+ hs_timings ? "HS" : "FS");
+ 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 (hs_timings) {
+ 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)
+{
+ /* always set Fast Speed timings */
+ int ret = exynos5_i2c_set_timing(i2c, false);
+
+ if (ret < 0 || i2c->op_clock < HSI2C_HS_TX_CLOCK)
+ return ret;
+
+ return exynos5_i2c_set_timing(i2c, true);
+}
+
+/*
+ * 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->op_clock >= HSI2C_HS_TX_CLOCK) {
+ 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);
+
+ /* handle interrupt related to the transfer status */
+ if (i2c->variant->hw == I2C_TYPE_EXYNOS7) {
+ if (int_status & HSI2C_INT_TRANS_DONE) {
+ i2c->trans_done = 1;
+ i2c->state = 0;
+ } else if (int_status & HSI2C_INT_TRANS_ABORT) {
+ dev_dbg(i2c->dev, "Deal with arbitration lose\n");
+ i2c->state = -EAGAIN;
+ goto stop;
+ } else if (int_status & HSI2C_INT_NO_DEV_ACK) {
+ dev_dbg(i2c->dev, "No ACK from device\n");
+ i2c->state = -ENXIO;
+ goto stop;
+ } else if (int_status & HSI2C_INT_NO_DEV) {
+ dev_dbg(i2c->dev, "No device\n");
+ i2c->state = -ENXIO;
+ goto stop;
+ } else if (int_status & HSI2C_INT_TIMEOUT) {
+ dev_dbg(i2c->dev, "Accessing device timed out\n");
+ i2c->state = -ETIMEDOUT;
+ goto stop;
+ }
+ } else 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 = -ETIMEDOUT;
+ 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 = i2c->variant->fifo_depth - fifo_level;
+ if (len > (i2c->msg->len - i2c->msg_ptr)) {
+ u32 int_en = readl(i2c->regs + HSI2C_INT_ENABLE);
+
+ int_en &= ~HSI2C_INT_TX_ALMOSTEMPTY_EN;
+ writel(int_en, i2c->regs + HSI2C_INT_ENABLE);
+ 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;
+}
+
+static void exynos5_i2c_bus_recover(struct exynos5_i2c *i2c)
+{
+ u32 val;
+
+ val = readl(i2c->regs + HSI2C_CTL) | HSI2C_RXCHON;
+ writel(val, i2c->regs + HSI2C_CTL);
+ val = readl(i2c->regs + HSI2C_CONF) & ~HSI2C_AUTO_MODE;
+ writel(val, i2c->regs + HSI2C_CONF);
+
+ /*
+ * Specification says master should send nine clock pulses. It can be
+ * emulated by sending manual read command (nine pulses for read eight
+ * bits + one pulse for NACK).
+ */
+ writel(HSI2C_CMD_READ_DATA, i2c->regs + HSI2C_MANUAL_CMD);
+ exynos5_i2c_wait_bus_idle(i2c);
+ writel(HSI2C_CMD_SEND_STOP, i2c->regs + HSI2C_MANUAL_CMD);
+ exynos5_i2c_wait_bus_idle(i2c);
+
+ val = readl(i2c->regs + HSI2C_CTL) & ~HSI2C_RXCHON;
+ writel(val, i2c->regs + HSI2C_CTL);
+ val = readl(i2c->regs + HSI2C_CONF) | HSI2C_AUTO_MODE;
+ writel(val, i2c->regs + HSI2C_CONF);
+}
+
+static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c)
+{
+ unsigned long timeout;
+
+ if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
+ return;
+
+ /*
+ * HSI2C_MASTER_ST_LOSE state in EXYNOS7 variant before transaction
+ * indicates that bus is stuck (SDA is low). In such case bus recovery
+ * can be performed.
+ */
+ timeout = jiffies + msecs_to_jiffies(100);
+ for (;;) {
+ u32 st = readl(i2c->regs + HSI2C_TRANS_STATUS);
+
+ if ((st & HSI2C_MASTER_ST_MASK) != HSI2C_MASTER_ST_LOSE)
+ return;
+
+ if (time_is_before_jiffies(timeout))
+ return;
+
+ exynos5_i2c_bus_recover(i2c);
+ }
+}
+
+/*
+ * 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 = 0;
+ u32 i2c_auto_conf = 0;
+ u32 fifo_ctl;
+ unsigned long flags;
+ unsigned short trig_lvl;
+
+ if (i2c->variant->hw == I2C_TYPE_EXYNOS7)
+ int_en |= HSI2C_INT_I2C_TRANS;
+ else
+ int_en |= HSI2C_INT_I2C;
+
+ 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;
+
+ trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
+ (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len;
+ fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl);
+
+ int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN |
+ HSI2C_INT_TRAILING_EN);
+ } else {
+ i2c_ctl |= HSI2C_TXCHON;
+
+ trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
+ (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len;
+ fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_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);
+
+ exynos5_i2c_bus_check(i2c);
+
+ /*
+ * 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 = adap->algo_data;
+ int i, ret;
+
+ if (i2c->suspended) {
+ dev_err(i2c->dev, "HS-I2C is not initialized.\n");
+ return -EIO;
+ }
+
+ ret = clk_enable(i2c->clk);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num; ++i) {
+ ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num);
+ if (ret)
+ break;
+ }
+
+ clk_disable(i2c->clk);
+
+ return ret ?: num;
+}
+
+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;
+ int ret;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock))
+ i2c->op_clock = HSI2C_FS_TX_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;
+ }
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret)
+ return ret;
+
+ 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;
+ }
+
+ i2c->variant = of_device_get_match_data(&pdev->dev);
+
+ ret = exynos5_hsi2c_clock_setup(i2c);
+ if (ret)
+ goto err_clk;
+
+ exynos5_i2c_reset(i2c);
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0)
+ goto err_clk;
+
+ platform_set_drvdata(pdev, i2c);
+
+ clk_disable(i2c->clk);
+
+ return 0;
+
+ 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);
+
+ clk_unprepare(i2c->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos5_i2c_suspend_noirq(struct device *dev)
+{
+ struct exynos5_i2c *i2c = dev_get_drvdata(dev);
+
+ i2c->suspended = 1;
+
+ clk_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static int exynos5_i2c_resume_noirq(struct device *dev)
+{
+ struct exynos5_i2c *i2c = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret)
+ return ret;
+
+ ret = exynos5_hsi2c_clock_setup(i2c);
+ if (ret) {
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+ }
+
+ exynos5_i2c_init(i2c);
+ clk_disable(i2c->clk);
+ i2c->suspended = 0;
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_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 = {
+ .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");
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
new file mode 100644
index 000000000..46aef609f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -0,0 +1,752 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * FSI-attached I2C master algorithm
+ *
+ * Copyright 2018 IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fsi.h>
+#include <linux/i2c.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#define FSI_ENGID_I2C 0x7
+
+#define I2C_DEFAULT_CLK_DIV 6
+
+/* i2c registers */
+#define I2C_FSI_FIFO 0x00
+#define I2C_FSI_CMD 0x04
+#define I2C_FSI_MODE 0x08
+#define I2C_FSI_WATER_MARK 0x0C
+#define I2C_FSI_INT_MASK 0x10
+#define I2C_FSI_INT_COND 0x14
+#define I2C_FSI_OR_INT_MASK 0x14
+#define I2C_FSI_INTS 0x18
+#define I2C_FSI_AND_INT_MASK 0x18
+#define I2C_FSI_STAT 0x1C
+#define I2C_FSI_RESET_I2C 0x1C
+#define I2C_FSI_ESTAT 0x20
+#define I2C_FSI_RESET_ERR 0x20
+#define I2C_FSI_RESID_LEN 0x24
+#define I2C_FSI_SET_SCL 0x24
+#define I2C_FSI_PORT_BUSY 0x28
+#define I2C_FSI_RESET_SCL 0x2C
+#define I2C_FSI_SET_SDA 0x30
+#define I2C_FSI_RESET_SDA 0x34
+
+/* cmd register */
+#define I2C_CMD_WITH_START BIT(31)
+#define I2C_CMD_WITH_ADDR BIT(30)
+#define I2C_CMD_RD_CONT BIT(29)
+#define I2C_CMD_WITH_STOP BIT(28)
+#define I2C_CMD_FORCELAUNCH BIT(27)
+#define I2C_CMD_ADDR GENMASK(23, 17)
+#define I2C_CMD_READ BIT(16)
+#define I2C_CMD_LEN GENMASK(15, 0)
+
+/* mode register */
+#define I2C_MODE_CLKDIV GENMASK(31, 16)
+#define I2C_MODE_PORT GENMASK(15, 10)
+#define I2C_MODE_ENHANCED BIT(3)
+#define I2C_MODE_DIAG BIT(2)
+#define I2C_MODE_PACE_ALLOW BIT(1)
+#define I2C_MODE_WRAP BIT(0)
+
+/* watermark register */
+#define I2C_WATERMARK_HI GENMASK(15, 12)
+#define I2C_WATERMARK_LO GENMASK(7, 4)
+
+#define I2C_FIFO_HI_LVL 4
+#define I2C_FIFO_LO_LVL 4
+
+/* interrupt register */
+#define I2C_INT_INV_CMD BIT(15)
+#define I2C_INT_PARITY BIT(14)
+#define I2C_INT_BE_OVERRUN BIT(13)
+#define I2C_INT_BE_ACCESS BIT(12)
+#define I2C_INT_LOST_ARB BIT(11)
+#define I2C_INT_NACK BIT(10)
+#define I2C_INT_DAT_REQ BIT(9)
+#define I2C_INT_CMD_COMP BIT(8)
+#define I2C_INT_STOP_ERR BIT(7)
+#define I2C_INT_BUSY BIT(6)
+#define I2C_INT_IDLE BIT(5)
+
+/* status register */
+#define I2C_STAT_INV_CMD BIT(31)
+#define I2C_STAT_PARITY BIT(30)
+#define I2C_STAT_BE_OVERRUN BIT(29)
+#define I2C_STAT_BE_ACCESS BIT(28)
+#define I2C_STAT_LOST_ARB BIT(27)
+#define I2C_STAT_NACK BIT(26)
+#define I2C_STAT_DAT_REQ BIT(25)
+#define I2C_STAT_CMD_COMP BIT(24)
+#define I2C_STAT_STOP_ERR BIT(23)
+#define I2C_STAT_MAX_PORT GENMASK(22, 16)
+#define I2C_STAT_ANY_INT BIT(15)
+#define I2C_STAT_SCL_IN BIT(11)
+#define I2C_STAT_SDA_IN BIT(10)
+#define I2C_STAT_PORT_BUSY BIT(9)
+#define I2C_STAT_SELF_BUSY BIT(8)
+#define I2C_STAT_FIFO_COUNT GENMASK(7, 0)
+
+#define I2C_STAT_ERR (I2C_STAT_INV_CMD | \
+ I2C_STAT_PARITY | \
+ I2C_STAT_BE_OVERRUN | \
+ I2C_STAT_BE_ACCESS | \
+ I2C_STAT_LOST_ARB | \
+ I2C_STAT_NACK | \
+ I2C_STAT_STOP_ERR)
+#define I2C_STAT_ANY_RESP (I2C_STAT_ERR | \
+ I2C_STAT_DAT_REQ | \
+ I2C_STAT_CMD_COMP)
+
+/* extended status register */
+#define I2C_ESTAT_FIFO_SZ GENMASK(31, 24)
+#define I2C_ESTAT_SCL_IN_SY BIT(15)
+#define I2C_ESTAT_SDA_IN_SY BIT(14)
+#define I2C_ESTAT_S_SCL BIT(13)
+#define I2C_ESTAT_S_SDA BIT(12)
+#define I2C_ESTAT_M_SCL BIT(11)
+#define I2C_ESTAT_M_SDA BIT(10)
+#define I2C_ESTAT_HI_WATER BIT(9)
+#define I2C_ESTAT_LO_WATER BIT(8)
+#define I2C_ESTAT_PORT_BUSY BIT(7)
+#define I2C_ESTAT_SELF_BUSY BIT(6)
+#define I2C_ESTAT_VERSION GENMASK(4, 0)
+
+/* port busy register */
+#define I2C_PORT_BUSY_RESET BIT(31)
+
+/* wait for command complete or data request */
+#define I2C_CMD_SLEEP_MAX_US 500
+#define I2C_CMD_SLEEP_MIN_US 50
+
+/* wait after reset; choose time from legacy driver */
+#define I2C_RESET_SLEEP_MAX_US 2000
+#define I2C_RESET_SLEEP_MIN_US 1000
+
+/* choose timeout length from legacy driver; it's well tested */
+#define I2C_ABORT_TIMEOUT msecs_to_jiffies(100)
+
+struct fsi_i2c_master {
+ struct fsi_device *fsi;
+ u8 fifo_size;
+ struct list_head ports;
+ struct mutex lock;
+};
+
+struct fsi_i2c_port {
+ struct list_head list;
+ struct i2c_adapter adapter;
+ struct fsi_i2c_master *master;
+ u16 port;
+ u16 xfrd;
+};
+
+static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
+ u32 *data)
+{
+ int rc;
+ __be32 data_be;
+
+ rc = fsi_device_read(fsi, reg, &data_be, sizeof(data_be));
+ if (rc)
+ return rc;
+
+ *data = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg,
+ u32 *data)
+{
+ __be32 data_be = cpu_to_be32p(data);
+
+ return fsi_device_write(fsi, reg, &data_be, sizeof(data_be));
+}
+
+static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c)
+{
+ int rc;
+ u32 mode = I2C_MODE_ENHANCED, extended_status, watermark;
+ u32 interrupt = 0;
+
+ /* since we use polling, disable interrupts */
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt);
+ if (rc)
+ return rc;
+
+ mode |= FIELD_PREP(I2C_MODE_CLKDIV, I2C_DEFAULT_CLK_DIV);
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status);
+ if (rc)
+ return rc;
+
+ i2c->fifo_size = FIELD_GET(I2C_ESTAT_FIFO_SZ, extended_status);
+ watermark = FIELD_PREP(I2C_WATERMARK_HI,
+ i2c->fifo_size - I2C_FIFO_HI_LVL);
+ watermark |= FIELD_PREP(I2C_WATERMARK_LO, I2C_FIFO_LO_LVL);
+
+ return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark);
+}
+
+static int fsi_i2c_set_port(struct fsi_i2c_port *port)
+{
+ int rc;
+ struct fsi_device *fsi = port->master->fsi;
+ u32 mode, dummy = 0;
+
+ rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+
+ if (FIELD_GET(I2C_MODE_PORT, mode) == port->port)
+ return 0;
+
+ mode = (mode & ~I2C_MODE_PORT) | FIELD_PREP(I2C_MODE_PORT, port->port);
+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+
+ /* reset engine when port is changed */
+ return fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy);
+}
+
+static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ bool stop)
+{
+ struct fsi_i2c_master *i2c = port->master;
+ u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR;
+
+ port->xfrd = 0;
+
+ if (msg->flags & I2C_M_RD)
+ cmd |= I2C_CMD_READ;
+
+ if (stop || msg->flags & I2C_M_STOP)
+ cmd |= I2C_CMD_WITH_STOP;
+
+ cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr);
+ cmd |= FIELD_PREP(I2C_CMD_LEN, msg->len);
+
+ return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd);
+}
+
+static int fsi_i2c_get_op_bytes(int op_bytes)
+{
+ /* fsi is limited to max 4 byte aligned ops */
+ if (op_bytes > 4)
+ return 4;
+ else if (op_bytes == 3)
+ return 2;
+ return op_bytes;
+}
+
+static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ u8 fifo_count)
+{
+ int write;
+ int rc;
+ struct fsi_i2c_master *i2c = port->master;
+ int bytes_to_write = i2c->fifo_size - fifo_count;
+ int bytes_remaining = msg->len - port->xfrd;
+
+ bytes_to_write = min(bytes_to_write, bytes_remaining);
+
+ while (bytes_to_write) {
+ write = fsi_i2c_get_op_bytes(bytes_to_write);
+
+ rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO,
+ &msg->buf[port->xfrd], write);
+ if (rc)
+ return rc;
+
+ port->xfrd += write;
+ bytes_to_write -= write;
+ }
+
+ return 0;
+}
+
+static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ u8 fifo_count)
+{
+ int read;
+ int rc;
+ struct fsi_i2c_master *i2c = port->master;
+ int bytes_to_read;
+ int xfr_remaining = msg->len - port->xfrd;
+ u32 dummy;
+
+ bytes_to_read = min_t(int, fifo_count, xfr_remaining);
+
+ while (bytes_to_read) {
+ read = fsi_i2c_get_op_bytes(bytes_to_read);
+
+ if (xfr_remaining) {
+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO,
+ &msg->buf[port->xfrd], read);
+ if (rc)
+ return rc;
+
+ port->xfrd += read;
+ xfr_remaining -= read;
+ } else {
+ /* no more buffer but data in fifo, need to clear it */
+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy,
+ read);
+ if (rc)
+ return rc;
+ }
+
+ bytes_to_read -= read;
+ }
+
+ return 0;
+}
+
+static int fsi_i2c_get_scl(struct i2c_adapter *adap)
+{
+ u32 stat = 0;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *i2c = port->master;
+
+ fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
+
+ return !!(stat & I2C_STAT_SCL_IN);
+}
+
+static void fsi_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ u32 dummy = 0;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *i2c = port->master;
+
+ if (val)
+ fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy);
+ else
+ fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy);
+}
+
+static int fsi_i2c_get_sda(struct i2c_adapter *adap)
+{
+ u32 stat = 0;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *i2c = port->master;
+
+ fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
+
+ return !!(stat & I2C_STAT_SDA_IN);
+}
+
+static void fsi_i2c_set_sda(struct i2c_adapter *adap, int val)
+{
+ u32 dummy = 0;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *i2c = port->master;
+
+ if (val)
+ fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy);
+ else
+ fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy);
+}
+
+static void fsi_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+ int rc;
+ u32 mode;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *i2c = port->master;
+
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return;
+
+ mode |= I2C_MODE_DIAG;
+ fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+}
+
+static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ int rc;
+ u32 mode;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *i2c = port->master;
+
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return;
+
+ mode &= ~I2C_MODE_DIAG;
+ fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+}
+
+static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c,
+ struct fsi_i2c_port *port)
+{
+ int rc;
+ u32 stat, dummy = 0;
+
+ /* force bus reset, ignore errors */
+ i2c_recover_bus(&port->adapter);
+
+ /* reset errors */
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy);
+ if (rc)
+ return rc;
+
+ /* wait for command complete */
+ usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US);
+
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
+ if (rc)
+ return rc;
+
+ if (stat & I2C_STAT_CMD_COMP)
+ return 0;
+
+ /* failed to get command complete; reset engine again */
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy);
+ if (rc)
+ return rc;
+
+ /* re-init engine again */
+ return fsi_i2c_dev_init(i2c);
+}
+
+static int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port)
+{
+ int rc;
+ u32 mode, dummy = 0;
+
+ /* reset engine */
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy);
+ if (rc)
+ return rc;
+
+ /* re-init engine */
+ rc = fsi_i2c_dev_init(i2c);
+ if (rc)
+ return rc;
+
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+
+ /* set port; default after reset is 0 */
+ if (port) {
+ mode &= ~I2C_MODE_PORT;
+ mode |= FIELD_PREP(I2C_MODE_PORT, port);
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
+ if (rc)
+ return rc;
+ }
+
+ /* reset busy register; hw workaround */
+ dummy = I2C_PORT_BUSY_RESET;
+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_PORT_BUSY, &dummy);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status)
+{
+ int rc;
+ unsigned long start;
+ u32 cmd = I2C_CMD_WITH_STOP;
+ u32 stat;
+ struct fsi_i2c_master *i2c = port->master;
+ struct fsi_device *fsi = i2c->fsi;
+
+ rc = fsi_i2c_reset_engine(i2c, port->port);
+ if (rc)
+ return rc;
+
+ rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &stat);
+ if (rc)
+ return rc;
+
+ /* if sda is low, peform full bus reset */
+ if (!(stat & I2C_STAT_SDA_IN)) {
+ rc = fsi_i2c_reset_bus(i2c, port);
+ if (rc)
+ return rc;
+ }
+
+ /* skip final stop command for these errors */
+ if (status & (I2C_STAT_PARITY | I2C_STAT_LOST_ARB | I2C_STAT_STOP_ERR))
+ return 0;
+
+ /* write stop command */
+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_CMD, &cmd);
+ if (rc)
+ return rc;
+
+ /* wait until we see command complete in the master */
+ start = jiffies;
+
+ do {
+ rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &status);
+ if (rc)
+ return rc;
+
+ if (status & I2C_STAT_CMD_COMP)
+ return 0;
+
+ usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US);
+ } while (time_after(start + I2C_ABORT_TIMEOUT, jiffies));
+
+ return -ETIMEDOUT;
+}
+
+static int fsi_i2c_handle_status(struct fsi_i2c_port *port,
+ struct i2c_msg *msg, u32 status)
+{
+ int rc;
+ u8 fifo_count;
+
+ if (status & I2C_STAT_ERR) {
+ rc = fsi_i2c_abort(port, status);
+ if (rc)
+ return rc;
+
+ if (status & I2C_STAT_INV_CMD)
+ return -EINVAL;
+
+ if (status & (I2C_STAT_PARITY | I2C_STAT_BE_OVERRUN |
+ I2C_STAT_BE_ACCESS))
+ return -EPROTO;
+
+ if (status & I2C_STAT_NACK)
+ return -ENXIO;
+
+ if (status & I2C_STAT_LOST_ARB)
+ return -EAGAIN;
+
+ if (status & I2C_STAT_STOP_ERR)
+ return -EBADMSG;
+
+ return -EIO;
+ }
+
+ if (status & I2C_STAT_DAT_REQ) {
+ fifo_count = FIELD_GET(I2C_STAT_FIFO_COUNT, status);
+
+ if (msg->flags & I2C_M_RD)
+ return fsi_i2c_read_fifo(port, msg, fifo_count);
+
+ return fsi_i2c_write_fifo(port, msg, fifo_count);
+ }
+
+ if (status & I2C_STAT_CMD_COMP) {
+ if (port->xfrd < msg->len)
+ return -ENODATA;
+
+ return msg->len;
+ }
+
+ return 0;
+}
+
+static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg,
+ unsigned long timeout)
+{
+ u32 status = 0;
+ int rc;
+ unsigned long start = jiffies;
+
+ do {
+ rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT,
+ &status);
+ if (rc)
+ return rc;
+
+ if (status & I2C_STAT_ANY_RESP) {
+ rc = fsi_i2c_handle_status(port, msg, status);
+ if (rc < 0)
+ return rc;
+
+ /* cmd complete and all data xfrd */
+ if (rc == msg->len)
+ return 0;
+
+ /* need to xfr more data, but maybe don't need wait */
+ continue;
+ }
+
+ usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US);
+ } while (time_after(start + timeout, jiffies));
+
+ return -ETIMEDOUT;
+}
+
+static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int i, rc;
+ unsigned long start_time;
+ struct fsi_i2c_port *port = adap->algo_data;
+ struct fsi_i2c_master *master = port->master;
+ struct i2c_msg *msg;
+
+ mutex_lock(&master->lock);
+
+ rc = fsi_i2c_set_port(port);
+ if (rc)
+ goto unlock;
+
+ for (i = 0; i < num; i++) {
+ msg = msgs + i;
+ start_time = jiffies;
+
+ rc = fsi_i2c_start(port, msg, i == num - 1);
+ if (rc)
+ goto unlock;
+
+ rc = fsi_i2c_wait(port, msg,
+ adap->timeout - (jiffies - start_time));
+ if (rc)
+ goto unlock;
+ }
+
+unlock:
+ mutex_unlock(&master->lock);
+ return rc ? : num;
+}
+
+static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING |
+ I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = fsi_i2c_get_scl,
+ .set_scl = fsi_i2c_set_scl,
+ .get_sda = fsi_i2c_get_sda,
+ .set_sda = fsi_i2c_set_sda,
+ .prepare_recovery = fsi_i2c_prepare_recovery,
+ .unprepare_recovery = fsi_i2c_unprepare_recovery,
+};
+
+static const struct i2c_algorithm fsi_i2c_algorithm = {
+ .master_xfer = fsi_i2c_xfer,
+ .functionality = fsi_i2c_functionality,
+};
+
+static int fsi_i2c_probe(struct device *dev)
+{
+ struct fsi_i2c_master *i2c;
+ struct fsi_i2c_port *port;
+ struct device_node *np;
+ int rc;
+ u32 port_no;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ mutex_init(&i2c->lock);
+ i2c->fsi = to_fsi_dev(dev);
+ INIT_LIST_HEAD(&i2c->ports);
+
+ rc = fsi_i2c_dev_init(i2c);
+ if (rc)
+ return rc;
+
+ /* Add adapter for each i2c port of the master. */
+ for_each_available_child_of_node(dev->of_node, np) {
+ rc = of_property_read_u32(np, "reg", &port_no);
+ if (rc || port_no > USHRT_MAX)
+ continue;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ break;
+
+ port->master = i2c;
+ port->port = port_no;
+
+ port->adapter.owner = THIS_MODULE;
+ port->adapter.dev.of_node = np;
+ port->adapter.dev.parent = dev;
+ port->adapter.algo = &fsi_i2c_algorithm;
+ port->adapter.bus_recovery_info = &fsi_i2c_bus_recovery_info;
+ port->adapter.algo_data = port;
+
+ snprintf(port->adapter.name, sizeof(port->adapter.name),
+ "i2c_bus-%u", port_no);
+
+ rc = i2c_add_adapter(&port->adapter);
+ if (rc < 0) {
+ dev_err(dev, "Failed to register adapter: %d\n", rc);
+ kfree(port);
+ continue;
+ }
+
+ list_add(&port->list, &i2c->ports);
+ }
+
+ dev_set_drvdata(dev, i2c);
+
+ return 0;
+}
+
+static int fsi_i2c_remove(struct device *dev)
+{
+ struct fsi_i2c_master *i2c = dev_get_drvdata(dev);
+ struct fsi_i2c_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &i2c->ports, list) {
+ list_del(&port->list);
+ i2c_del_adapter(&port->adapter);
+ kfree(port);
+ }
+
+ return 0;
+}
+
+static const struct fsi_device_id fsi_i2c_ids[] = {
+ { FSI_ENGID_I2C, FSI_VERSION_ANY },
+ { }
+};
+
+static struct fsi_driver fsi_i2c_driver = {
+ .id_table = fsi_i2c_ids,
+ .drv = {
+ .name = "i2c-fsi",
+ .bus = &fsi_bus_type,
+ .probe = fsi_i2c_probe,
+ .remove = fsi_i2c_remove,
+ },
+};
+
+module_fsi_driver(fsi_i2c_driver);
+
+MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>");
+MODULE_DESCRIPTION("FSI attached I2C master");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 000000000..87014d144
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,429 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/platform_data/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+
+struct i2c_gpio_private_data {
+ struct gpio_desc *sda;
+ struct gpio_desc *scl;
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data bit_data;
+ struct i2c_gpio_platform_data pdata;
+#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
+ struct dentry *debug_dir;
+#endif
+};
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+ struct i2c_gpio_private_data *priv = data;
+
+ gpiod_set_value_cansleep(priv->sda, state);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+ struct i2c_gpio_private_data *priv = data;
+
+ gpiod_set_value_cansleep(priv->scl, state);
+}
+
+static int i2c_gpio_getsda(void *data)
+{
+ struct i2c_gpio_private_data *priv = data;
+
+ return gpiod_get_value_cansleep(priv->sda);
+}
+
+static int i2c_gpio_getscl(void *data)
+{
+ struct i2c_gpio_private_data *priv = data;
+
+ return gpiod_get_value_cansleep(priv->scl);
+}
+
+#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
+static struct dentry *i2c_gpio_debug_dir;
+
+#define setsda(bd, val) ((bd)->setsda((bd)->data, val))
+#define setscl(bd, val) ((bd)->setscl((bd)->data, val))
+#define getsda(bd) ((bd)->getsda((bd)->data))
+#define getscl(bd) ((bd)->getscl((bd)->data))
+
+#define WIRE_ATTRIBUTE(wire) \
+static int fops_##wire##_get(void *data, u64 *val) \
+{ \
+ struct i2c_gpio_private_data *priv = data; \
+ \
+ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
+ *val = get##wire(&priv->bit_data); \
+ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
+ return 0; \
+} \
+static int fops_##wire##_set(void *data, u64 val) \
+{ \
+ struct i2c_gpio_private_data *priv = data; \
+ \
+ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
+ set##wire(&priv->bit_data, val); \
+ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \
+ return 0; \
+} \
+DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n")
+
+WIRE_ATTRIBUTE(scl);
+WIRE_ATTRIBUTE(sda);
+
+static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv,
+ u32 pattern, u8 pattern_size)
+{
+ struct i2c_algo_bit_data *bit_data = &priv->bit_data;
+ int i;
+
+ i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
+
+ /* START condition */
+ setsda(bit_data, 0);
+ udelay(bit_data->udelay);
+
+ /* Send pattern, request ACK, don't send STOP */
+ for (i = pattern_size - 1; i >= 0; i--) {
+ setscl(bit_data, 0);
+ udelay(bit_data->udelay / 2);
+ setsda(bit_data, (pattern >> i) & 1);
+ udelay((bit_data->udelay + 1) / 2);
+ setscl(bit_data, 1);
+ udelay(bit_data->udelay);
+ }
+
+ i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
+}
+
+static int fops_incomplete_addr_phase_set(void *data, u64 addr)
+{
+ struct i2c_gpio_private_data *priv = data;
+ u32 pattern;
+
+ if (addr > 0x7f)
+ return -EINVAL;
+
+ /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */
+ pattern = (addr << 2) | 3;
+
+ i2c_gpio_incomplete_transfer(priv, pattern, 9);
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n");
+
+static int fops_incomplete_write_byte_set(void *data, u64 addr)
+{
+ struct i2c_gpio_private_data *priv = data;
+ u32 pattern;
+
+ if (addr > 0x7f)
+ return -EINVAL;
+
+ /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */
+ pattern = (addr << 2) | 1;
+ /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */
+ pattern = (pattern << 9) | 1;
+
+ i2c_gpio_incomplete_transfer(priv, pattern, 18);
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n");
+
+static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
+{
+ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
+
+ /*
+ * If there will be a debugfs-dir per i2c adapter somewhen, put the
+ * 'fault-injector' dir there. Until then, we have a global dir with
+ * all adapters as subdirs.
+ */
+ if (!i2c_gpio_debug_dir) {
+ i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL);
+ if (!i2c_gpio_debug_dir)
+ return;
+ }
+
+ priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir);
+ if (!priv->debug_dir)
+ return;
+
+ debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl);
+ debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda);
+ debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir,
+ priv, &fops_incomplete_addr_phase);
+ debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir,
+ priv, &fops_incomplete_write_byte);
+}
+
+static void i2c_gpio_fault_injector_exit(struct platform_device *pdev)
+{
+ struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
+
+ debugfs_remove_recursive(priv->debug_dir);
+}
+#else
+static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {}
+static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {}
+#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/
+
+static void of_i2c_gpio_get_props(struct device_node *np,
+ struct i2c_gpio_platform_data *pdata)
+{
+ u32 reg;
+
+ of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+
+ if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+ pdata->timeout = msecs_to_jiffies(reg);
+
+ pdata->sda_is_open_drain =
+ of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+ pdata->scl_is_open_drain =
+ of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+ pdata->scl_is_output_only =
+ of_property_read_bool(np, "i2c-gpio,scl-output-only");
+}
+
+static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
+ const char *con_id,
+ unsigned int index,
+ enum gpiod_flags gflags)
+{
+ struct gpio_desc *retdesc;
+ int ret;
+
+ retdesc = devm_gpiod_get(dev, con_id, gflags);
+ if (!IS_ERR(retdesc)) {
+ dev_dbg(dev, "got GPIO from name %s\n", con_id);
+ return retdesc;
+ }
+
+ retdesc = devm_gpiod_get_index(dev, NULL, index, gflags);
+ if (!IS_ERR(retdesc)) {
+ dev_dbg(dev, "got GPIO from index %u\n", index);
+ return retdesc;
+ }
+
+ ret = PTR_ERR(retdesc);
+
+ /* FIXME: hack in the old code, is this really necessary? */
+ if (ret == -EINVAL)
+ retdesc = ERR_PTR(-EPROBE_DEFER);
+
+ /* This happens if the GPIO driver is not yet probed, let's defer */
+ if (ret == -ENOENT)
+ retdesc = ERR_PTR(-EPROBE_DEFER);
+
+ if (PTR_ERR(retdesc) != -EPROBE_DEFER)
+ dev_err(dev, "error trying to get descriptor: %d\n", ret);
+
+ return retdesc;
+}
+
+static int i2c_gpio_probe(struct platform_device *pdev)
+{
+ struct i2c_gpio_private_data *priv;
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_algo_bit_data *bit_data;
+ struct i2c_adapter *adap;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ enum gpiod_flags gflags;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ adap = &priv->adap;
+ bit_data = &priv->bit_data;
+ pdata = &priv->pdata;
+
+ if (np) {
+ of_i2c_gpio_get_props(np, pdata);
+ } else {
+ /*
+ * If all platform data settings are zero it is OK
+ * to not provide any platform data from the board.
+ */
+ if (dev_get_platdata(dev))
+ memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata));
+ }
+
+ /*
+ * First get the GPIO pins; if it fails, we'll defer the probe.
+ * If the SDA line is marked from platform data or device tree as
+ * "open drain" it means something outside of our control is making
+ * this line being handled as open drain, and we should just handle
+ * it as any other output. Else we enforce open drain as this is
+ * required for an I2C bus.
+ */
+ if (pdata->sda_is_open_drain)
+ gflags = GPIOD_OUT_HIGH;
+ else
+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
+ priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags);
+ if (IS_ERR(priv->sda))
+ return PTR_ERR(priv->sda);
+
+ /*
+ * If the SCL line is marked from platform data or device tree as
+ * "open drain" it means something outside of our control is making
+ * this line being handled as open drain, and we should just handle
+ * it as any other output. Else we enforce open drain as this is
+ * required for an I2C bus.
+ */
+ if (pdata->scl_is_open_drain)
+ gflags = GPIOD_OUT_HIGH;
+ else
+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
+ priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags);
+ if (IS_ERR(priv->scl))
+ return PTR_ERR(priv->scl);
+
+ if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
+ dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
+
+ bit_data->setsda = i2c_gpio_setsda_val;
+ bit_data->setscl = i2c_gpio_setscl_val;
+
+ if (!pdata->scl_is_output_only)
+ bit_data->getscl = i2c_gpio_getscl;
+ bit_data->getsda = i2c_gpio_getsda;
+
+ if (pdata->udelay)
+ bit_data->udelay = pdata->udelay;
+ else if (pdata->scl_is_output_only)
+ bit_data->udelay = 50; /* 10 kHz */
+ else
+ bit_data->udelay = 5; /* 100 kHz */
+
+ if (pdata->timeout)
+ bit_data->timeout = pdata->timeout;
+ else
+ bit_data->timeout = HZ / 10; /* 100 ms */
+
+ bit_data->data = priv;
+
+ adap->owner = THIS_MODULE;
+ if (np)
+ strlcpy(adap->name, dev_name(dev), sizeof(adap->name));
+ else
+ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+
+ adap->algo_data = bit_data;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->dev.parent = dev;
+ adap->dev.of_node = np;
+
+ adap->nr = pdev->id;
+ ret = i2c_bit_add_numbered_bus(adap);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, priv);
+
+ /*
+ * FIXME: using global GPIO numbers is not helpful. If/when we
+ * get accessors to get the actual name of the GPIO line,
+ * from the descriptor, then provide that instead.
+ */
+ dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n",
+ desc_to_gpio(priv->sda), desc_to_gpio(priv->scl),
+ pdata->scl_is_output_only
+ ? ", no clock stretching" : "");
+
+ i2c_gpio_fault_injector_init(pdev);
+
+ return 0;
+}
+
+static int i2c_gpio_remove(struct platform_device *pdev)
+{
+ struct i2c_gpio_private_data *priv;
+ struct i2c_adapter *adap;
+
+ i2c_gpio_fault_injector_exit(pdev);
+
+ priv = platform_get_drvdata(pdev);
+ adap = &priv->adap;
+
+ i2c_del_adapter(adap);
+
+ return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_gpio_dt_ids[] = {
+ { .compatible = "i2c-gpio", },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+#endif
+
+static struct platform_driver i2c_gpio_driver = {
+ .driver = {
+ .name = "i2c-gpio",
+ .of_match_table = of_match_ptr(i2c_gpio_dt_ids),
+ },
+ .probe = i2c_gpio_probe,
+ .remove = i2c_gpio_remove,
+};
+
+static int __init i2c_gpio_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&i2c_gpio_driver);
+ if (ret)
+ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+ platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-gpio");
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
new file mode 100644
index 000000000..6a880c262
--- /dev/null
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008 Paul Mundt
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Copyright (C) 2008 Atom Create Engineering Co., Ltd.
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#define SMCR 0x00
+#define SMCR_START (1 << 0)
+#define SMCR_IRIC (1 << 1)
+#define SMCR_BBSY (1 << 2)
+#define SMCR_ACKE (1 << 3)
+#define SMCR_RST (1 << 4)
+#define SMCR_IEIC (1 << 6)
+
+#define SMSMADR 0x02
+
+#define SMMR 0x04
+#define SMMR_MODE0 (1 << 0)
+#define SMMR_MODE1 (1 << 1)
+#define SMMR_CAP (1 << 3)
+#define SMMR_TMMD (1 << 4)
+#define SMMR_SP (1 << 7)
+
+#define SMSADR 0x06
+#define SMTRDR 0x46
+
+struct highlander_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_adapter adapter;
+ struct completion cmd_complete;
+ unsigned long last_read_time;
+ int irq;
+ u8 *buf;
+ size_t buf_len;
+};
+
+static bool iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+ u16 smmr;
+
+ smmr = ioread16(dev->base + SMMR);
+ smmr |= SMMR_TMMD;
+
+ if (iic_force_normal)
+ smmr &= ~SMMR_SP;
+ else
+ smmr |= SMMR_SP;
+
+ iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *dst++ = be16_to_cpup((__be16 *)src);
+ src += 2;
+ }
+
+ if (len)
+ *dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *(__be16 *)dst = cpu_to_be16p(src++);
+ dst += 2;
+ }
+
+ if (len)
+ *dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+ u8 command, int len)
+{
+ unsigned int i;
+ u16 cmd = (command << 8) | command;
+
+ for (i = 0; i < len; i += 2) {
+ if (len - i == 1)
+ cmd = command << 8;
+ iowrite16(cmd, dev->base + SMSADR + i);
+ dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+ }
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+ return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+ u16 tmp = ioread16(dev->base + SMCR);
+
+ if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+ dev_warn(dev->dev, "ack abnormality\n");
+ return highlander_i2c_reset(dev);
+ }
+
+ return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+ struct highlander_i2c_dev *dev = dev_id;
+
+ highlander_i2c_done(dev);
+ complete(&dev->cmd_complete);
+
+ return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+ u16 smcr;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ for (;;) {
+ smcr = ioread16(dev->base + SMCR);
+
+ /*
+ * Don't bother checking ACKE here, this and the reset
+ * are handled in highlander_i2c_wait_xfer_done() when
+ * waiting for the ACK.
+ */
+
+ if (smcr & SMCR_IRIC)
+ return;
+ if (time_after(jiffies, timeout))
+ break;
+
+ cpu_relax();
+ cond_resched();
+ }
+
+ dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+ if (dev->irq)
+ wait_for_completion_timeout(&dev->cmd_complete,
+ msecs_to_jiffies(iic_timeout));
+ else
+ /* busy looping, the IRQ of champions */
+ highlander_i2c_poll(dev);
+
+ return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ if (highlander_i2c_wait_xfer_done(dev)) {
+ dev_err(dev->dev, "Arbitration loss\n");
+ return -EAGAIN;
+ }
+
+ /*
+ * The R0P7780LC0011RL FPGA needs a significant delay between
+ * data read cycles, otherwise the transceiver gets confused and
+ * garbage is returned when the read is subsequently aborted.
+ *
+ * It is not sufficient to wait for BBSY.
+ *
+ * While this generally only applies to the older SH7780-based
+ * Highlanders, the same issue can be observed on SH7785 ones,
+ * albeit less frequently. SH7780-based Highlanders may need
+ * this to be as high as 1000 ms.
+ */
+ if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)))
+ msleep(jiffies_to_msecs((dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ smbus_read_data(data, dev->buf, dev->buf_len);
+
+ dev->last_read_time = jiffies;
+
+ return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ smbus_write_data(dev->buf, data, dev->buf_len);
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+ u16 tmp;
+
+ init_completion(&dev->cmd_complete);
+
+ dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+ addr, command, read_write, size);
+
+ /*
+ * Set up the buffer and transfer size
+ */
+ switch (size) {
+ case I2C_SMBUS_BYTE_DATA:
+ dev->buf = &data->byte;
+ dev->buf_len = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ dev->buf = &data->block[1];
+ dev->buf_len = data->block[0];
+ break;
+ default:
+ dev_err(dev->dev, "unsupported command %d\n", size);
+ return -EINVAL;
+ }
+
+ /*
+ * Encode the mode setting
+ */
+ tmp = ioread16(dev->base + SMMR);
+ tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+ switch (dev->buf_len) {
+ case 1:
+ /* default */
+ break;
+ case 8:
+ tmp |= SMMR_MODE0;
+ break;
+ case 16:
+ tmp |= SMMR_MODE1;
+ break;
+ case 32:
+ tmp |= (SMMR_MODE0 | SMMR_MODE1);
+ break;
+ default:
+ dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+ return -EINVAL;
+ }
+
+ iowrite16(tmp, dev->base + SMMR);
+
+ /* Ensure we're in a sane state */
+ highlander_i2c_done(dev);
+
+ /* Set slave address */
+ iowrite16((addr << 1) | read_write, dev->base + SMSMADR);
+
+ highlander_i2c_command(dev, command, dev->buf_len);
+
+ if (read_write == I2C_SMBUS_READ)
+ return highlander_i2c_read(dev);
+ else
+ return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+ .smbus_xfer = highlander_i2c_smbus_xfer,
+ .functionality = highlander_i2c_func,
+};
+
+static int highlander_i2c_probe(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -ENODEV;
+ }
+
+ dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+ if (unlikely(!dev))
+ return -ENOMEM;
+
+ dev->base = ioremap_nocache(res->start, resource_size(res));
+ if (unlikely(!dev->base)) {
+ ret = -ENXIO;
+ goto err;
+ }
+
+ dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dev);
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0 || iic_force_poll)
+ dev->irq = 0;
+
+ if (dev->irq) {
+ ret = request_irq(dev->irq, highlander_i2c_irq, 0,
+ pdev->name, dev);
+ if (unlikely(ret))
+ goto err_unmap;
+
+ highlander_i2c_irq_enable(dev);
+ } else {
+ dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+ highlander_i2c_irq_disable(dev);
+ }
+
+ dev->last_read_time = jiffies; /* initial read jiffies */
+
+ highlander_i2c_setup(dev);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+ adap->algo = &highlander_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+
+ /*
+ * Reset the adapter
+ */
+ ret = highlander_i2c_reset(dev);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "controller didn't come up\n");
+ goto err_free_irq;
+ }
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+err_unmap:
+ iounmap(dev->base);
+err:
+ kfree(dev);
+
+ return ret;
+}
+
+static int highlander_i2c_remove(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+ .driver = {
+ .name = "i2c-highlander",
+ },
+
+ .probe = highlander_i2c_probe,
+ .remove = highlander_i2c_remove,
+};
+
+module_platform_driver(highlander_i2c_driver);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+ "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+ "Delay between data read cycles (default 0 ms)");
diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c
new file mode 100644
index 000000000..b5ad7696a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-hix5hd2.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Now only support 7 bit address.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* Register Map */
+#define HIX5I2C_CTRL 0x00
+#define HIX5I2C_COM 0x04
+#define HIX5I2C_ICR 0x08
+#define HIX5I2C_SR 0x0c
+#define HIX5I2C_SCL_H 0x10
+#define HIX5I2C_SCL_L 0x14
+#define HIX5I2C_TXR 0x18
+#define HIX5I2C_RXR 0x1c
+
+/* I2C_CTRL_REG */
+#define I2C_ENABLE BIT(8)
+#define I2C_UNMASK_TOTAL BIT(7)
+#define I2C_UNMASK_START BIT(6)
+#define I2C_UNMASK_END BIT(5)
+#define I2C_UNMASK_SEND BIT(4)
+#define I2C_UNMASK_RECEIVE BIT(3)
+#define I2C_UNMASK_ACK BIT(2)
+#define I2C_UNMASK_ARBITRATE BIT(1)
+#define I2C_UNMASK_OVER BIT(0)
+#define I2C_UNMASK_ALL (I2C_UNMASK_ACK | I2C_UNMASK_OVER)
+
+/* I2C_COM_REG */
+#define I2C_NO_ACK BIT(4)
+#define I2C_START BIT(3)
+#define I2C_READ BIT(2)
+#define I2C_WRITE BIT(1)
+#define I2C_STOP BIT(0)
+
+/* I2C_ICR_REG */
+#define I2C_CLEAR_START BIT(6)
+#define I2C_CLEAR_END BIT(5)
+#define I2C_CLEAR_SEND BIT(4)
+#define I2C_CLEAR_RECEIVE BIT(3)
+#define I2C_CLEAR_ACK BIT(2)
+#define I2C_CLEAR_ARBITRATE BIT(1)
+#define I2C_CLEAR_OVER BIT(0)
+#define I2C_CLEAR_ALL (I2C_CLEAR_START | I2C_CLEAR_END | \
+ I2C_CLEAR_SEND | I2C_CLEAR_RECEIVE | \
+ I2C_CLEAR_ACK | I2C_CLEAR_ARBITRATE | \
+ I2C_CLEAR_OVER)
+
+/* I2C_SR_REG */
+#define I2C_BUSY BIT(7)
+#define I2C_START_INTR BIT(6)
+#define I2C_END_INTR BIT(5)
+#define I2C_SEND_INTR BIT(4)
+#define I2C_RECEIVE_INTR BIT(3)
+#define I2C_ACK_INTR BIT(2)
+#define I2C_ARBITRATE_INTR BIT(1)
+#define I2C_OVER_INTR BIT(0)
+
+#define HIX5I2C_MAX_FREQ 400000 /* 400k */
+
+enum hix5hd2_i2c_state {
+ HIX5I2C_STAT_RW_ERR = -1,
+ HIX5I2C_STAT_INIT,
+ HIX5I2C_STAT_RW,
+ HIX5I2C_STAT_SND_STOP,
+ HIX5I2C_STAT_RW_SUCCESS,
+};
+
+struct hix5hd2_i2c_priv {
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ struct completion msg_complete;
+ unsigned int msg_idx;
+ unsigned int msg_len;
+ int stop;
+ void __iomem *regs;
+ struct clk *clk;
+ struct device *dev;
+ spinlock_t lock; /* IRQ synchronization */
+ int err;
+ unsigned int freq;
+ enum hix5hd2_i2c_state state;
+};
+
+static u32 hix5hd2_i2c_clr_pend_irq(struct hix5hd2_i2c_priv *priv)
+{
+ u32 val = readl_relaxed(priv->regs + HIX5I2C_SR);
+
+ writel_relaxed(val, priv->regs + HIX5I2C_ICR);
+
+ return val;
+}
+
+static void hix5hd2_i2c_clr_all_irq(struct hix5hd2_i2c_priv *priv)
+{
+ writel_relaxed(I2C_CLEAR_ALL, priv->regs + HIX5I2C_ICR);
+}
+
+static void hix5hd2_i2c_disable_irq(struct hix5hd2_i2c_priv *priv)
+{
+ writel_relaxed(0, priv->regs + HIX5I2C_CTRL);
+}
+
+static void hix5hd2_i2c_enable_irq(struct hix5hd2_i2c_priv *priv)
+{
+ writel_relaxed(I2C_ENABLE | I2C_UNMASK_TOTAL | I2C_UNMASK_ALL,
+ priv->regs + HIX5I2C_CTRL);
+}
+
+static void hix5hd2_i2c_drv_setrate(struct hix5hd2_i2c_priv *priv)
+{
+ u32 rate, val;
+ u32 scl, sysclock;
+
+ /* close all i2c interrupt */
+ val = readl_relaxed(priv->regs + HIX5I2C_CTRL);
+ writel_relaxed(val & (~I2C_UNMASK_TOTAL), priv->regs + HIX5I2C_CTRL);
+
+ rate = priv->freq;
+ sysclock = clk_get_rate(priv->clk);
+ scl = (sysclock / (rate * 2)) / 2 - 1;
+ writel_relaxed(scl, priv->regs + HIX5I2C_SCL_H);
+ writel_relaxed(scl, priv->regs + HIX5I2C_SCL_L);
+
+ /* restore original interrupt*/
+ writel_relaxed(val, priv->regs + HIX5I2C_CTRL);
+
+ dev_dbg(priv->dev, "%s: sysclock=%d, rate=%d, scl=%d\n",
+ __func__, sysclock, rate, scl);
+}
+
+static void hix5hd2_i2c_init(struct hix5hd2_i2c_priv *priv)
+{
+ hix5hd2_i2c_disable_irq(priv);
+ hix5hd2_i2c_drv_setrate(priv);
+ hix5hd2_i2c_clr_all_irq(priv);
+ hix5hd2_i2c_enable_irq(priv);
+}
+
+static void hix5hd2_i2c_reset(struct hix5hd2_i2c_priv *priv)
+{
+ clk_disable_unprepare(priv->clk);
+ msleep(20);
+ clk_prepare_enable(priv->clk);
+ hix5hd2_i2c_init(priv);
+}
+
+static int hix5hd2_i2c_wait_bus_idle(struct hix5hd2_i2c_priv *priv)
+{
+ unsigned long stop_time;
+ u32 int_status;
+
+ /* wait for 100 milli seconds for the bus to be idle */
+ stop_time = jiffies + msecs_to_jiffies(100);
+ do {
+ int_status = hix5hd2_i2c_clr_pend_irq(priv);
+ if (!(int_status & I2C_BUSY))
+ return 0;
+
+ usleep_range(50, 200);
+ } while (time_before(jiffies, stop_time));
+
+ return -EBUSY;
+}
+
+static void hix5hd2_rw_over(struct hix5hd2_i2c_priv *priv)
+{
+ if (priv->state == HIX5I2C_STAT_SND_STOP)
+ dev_dbg(priv->dev, "%s: rw and send stop over\n", __func__);
+ else
+ dev_dbg(priv->dev, "%s: have not data to send\n", __func__);
+
+ priv->state = HIX5I2C_STAT_RW_SUCCESS;
+ priv->err = 0;
+}
+
+static void hix5hd2_rw_handle_stop(struct hix5hd2_i2c_priv *priv)
+{
+ if (priv->stop) {
+ priv->state = HIX5I2C_STAT_SND_STOP;
+ writel_relaxed(I2C_STOP, priv->regs + HIX5I2C_COM);
+ } else {
+ hix5hd2_rw_over(priv);
+ }
+}
+
+static void hix5hd2_read_handle(struct hix5hd2_i2c_priv *priv)
+{
+ if (priv->msg_len == 1) {
+ /* the last byte don't need send ACK */
+ writel_relaxed(I2C_READ | I2C_NO_ACK, priv->regs + HIX5I2C_COM);
+ } else if (priv->msg_len > 1) {
+ /* if i2c master receive data will send ACK */
+ writel_relaxed(I2C_READ, priv->regs + HIX5I2C_COM);
+ } else {
+ hix5hd2_rw_handle_stop(priv);
+ }
+}
+
+static void hix5hd2_write_handle(struct hix5hd2_i2c_priv *priv)
+{
+ u8 data;
+
+ if (priv->msg_len > 0) {
+ data = priv->msg->buf[priv->msg_idx++];
+ writel_relaxed(data, priv->regs + HIX5I2C_TXR);
+ writel_relaxed(I2C_WRITE, priv->regs + HIX5I2C_COM);
+ } else {
+ hix5hd2_rw_handle_stop(priv);
+ }
+}
+
+static int hix5hd2_rw_preprocess(struct hix5hd2_i2c_priv *priv)
+{
+ u8 data;
+
+ if (priv->state == HIX5I2C_STAT_INIT) {
+ priv->state = HIX5I2C_STAT_RW;
+ } else if (priv->state == HIX5I2C_STAT_RW) {
+ if (priv->msg->flags & I2C_M_RD) {
+ data = readl_relaxed(priv->regs + HIX5I2C_RXR);
+ priv->msg->buf[priv->msg_idx++] = data;
+ }
+ priv->msg_len--;
+ } else {
+ dev_dbg(priv->dev, "%s: error: priv->state = %d, msg_len = %d\n",
+ __func__, priv->state, priv->msg_len);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static irqreturn_t hix5hd2_i2c_irq(int irqno, void *dev_id)
+{
+ struct hix5hd2_i2c_priv *priv = dev_id;
+ u32 int_status;
+ int ret;
+
+ spin_lock(&priv->lock);
+
+ int_status = hix5hd2_i2c_clr_pend_irq(priv);
+
+ /* handle error */
+ if (int_status & I2C_ARBITRATE_INTR) {
+ /* bus error */
+ dev_dbg(priv->dev, "ARB bus loss\n");
+ priv->err = -EAGAIN;
+ priv->state = HIX5I2C_STAT_RW_ERR;
+ goto stop;
+ } else if (int_status & I2C_ACK_INTR) {
+ /* ack error */
+ dev_dbg(priv->dev, "No ACK from device\n");
+ priv->err = -ENXIO;
+ priv->state = HIX5I2C_STAT_RW_ERR;
+ goto stop;
+ }
+
+ if (int_status & I2C_OVER_INTR) {
+ if (priv->msg_len > 0) {
+ ret = hix5hd2_rw_preprocess(priv);
+ if (ret) {
+ priv->err = ret;
+ priv->state = HIX5I2C_STAT_RW_ERR;
+ goto stop;
+ }
+ if (priv->msg->flags & I2C_M_RD)
+ hix5hd2_read_handle(priv);
+ else
+ hix5hd2_write_handle(priv);
+ } else {
+ hix5hd2_rw_over(priv);
+ }
+ }
+
+stop:
+ if ((priv->state == HIX5I2C_STAT_RW_SUCCESS &&
+ priv->msg->len == priv->msg_idx) ||
+ (priv->state == HIX5I2C_STAT_RW_ERR)) {
+ hix5hd2_i2c_disable_irq(priv);
+ hix5hd2_i2c_clr_pend_irq(priv);
+ complete(&priv->msg_complete);
+ }
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ hix5hd2_i2c_clr_all_irq(priv);
+ hix5hd2_i2c_enable_irq(priv);
+
+ writel_relaxed(i2c_8bit_addr_from_msg(priv->msg),
+ priv->regs + HIX5I2C_TXR);
+
+ writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv,
+ struct i2c_msg *msgs, int stop)
+{
+ unsigned long timeout;
+ int ret;
+
+ priv->msg = msgs;
+ priv->msg_idx = 0;
+ priv->msg_len = priv->msg->len;
+ priv->stop = stop;
+ priv->err = 0;
+ priv->state = HIX5I2C_STAT_INIT;
+
+ reinit_completion(&priv->msg_complete);
+ hix5hd2_i2c_message_start(priv, stop);
+
+ timeout = wait_for_completion_timeout(&priv->msg_complete,
+ priv->adap.timeout);
+ if (timeout == 0) {
+ priv->state = HIX5I2C_STAT_RW_ERR;
+ priv->err = -ETIMEDOUT;
+ dev_warn(priv->dev, "%s timeout=%d\n",
+ msgs->flags & I2C_M_RD ? "rx" : "tx",
+ priv->adap.timeout);
+ }
+ ret = priv->state;
+
+ /*
+ * If this is the last message to be transfered (stop == 1)
+ * Then check if the bus can be brought back to idle.
+ */
+ if (priv->state == HIX5I2C_STAT_RW_SUCCESS && stop)
+ ret = hix5hd2_i2c_wait_bus_idle(priv);
+
+ if (ret < 0)
+ hix5hd2_i2c_reset(priv);
+
+ return priv->err;
+}
+
+static int hix5hd2_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct hix5hd2_i2c_priv *priv = i2c_get_adapdata(adap);
+ int i, ret, stop;
+
+ pm_runtime_get_sync(priv->dev);
+
+ for (i = 0; i < num; i++, msgs++) {
+ stop = (i == num - 1);
+ ret = hix5hd2_i2c_xfer_msg(priv, msgs, stop);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = num;
+
+out:
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+ return ret;
+}
+
+static u32 hix5hd2_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm hix5hd2_i2c_algorithm = {
+ .master_xfer = hix5hd2_i2c_xfer,
+ .functionality = hix5hd2_i2c_func,
+};
+
+static int hix5hd2_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct hix5hd2_i2c_priv *priv;
+ struct resource *mem;
+ unsigned int freq;
+ int irq, ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "clock-frequency", &freq)) {
+ /* use 100k as default value */
+ priv->freq = 100000;
+ } else {
+ if (freq > HIX5I2C_MAX_FREQ) {
+ priv->freq = HIX5I2C_MAX_FREQ;
+ dev_warn(priv->dev, "use max freq %d instead\n",
+ HIX5I2C_MAX_FREQ);
+ } else {
+ priv->freq = freq;
+ }
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
+ return irq;
+ }
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+ clk_prepare_enable(priv->clk);
+
+ strlcpy(priv->adap.name, "hix5hd2-i2c", sizeof(priv->adap.name));
+ priv->dev = &pdev->dev;
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo = &hix5hd2_i2c_algorithm;
+ priv->adap.retries = 3;
+ priv->adap.dev.of_node = np;
+ priv->adap.algo_data = priv;
+ priv->adap.dev.parent = &pdev->dev;
+ i2c_set_adapdata(&priv->adap, priv);
+ platform_set_drvdata(pdev, priv);
+ spin_lock_init(&priv->lock);
+ init_completion(&priv->msg_complete);
+
+ hix5hd2_i2c_init(priv);
+
+ ret = devm_request_irq(&pdev->dev, irq, hix5hd2_i2c_irq,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ dev_name(&pdev->dev), priv);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", irq);
+ goto err_clk;
+ }
+
+ pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(priv->dev);
+ pm_runtime_set_active(priv->dev);
+ pm_runtime_enable(priv->dev);
+
+ ret = i2c_add_adapter(&priv->adap);
+ if (ret < 0)
+ goto err_runtime;
+
+ return ret;
+
+err_runtime:
+ pm_runtime_disable(priv->dev);
+ pm_runtime_set_suspended(priv->dev);
+err_clk:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int hix5hd2_i2c_remove(struct platform_device *pdev)
+{
+ struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ pm_runtime_disable(priv->dev);
+ pm_runtime_set_suspended(priv->dev);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hix5hd2_i2c_runtime_suspend(struct device *dev)
+{
+ struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int hix5hd2_i2c_runtime_resume(struct device *dev)
+{
+ struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev);
+
+ clk_prepare_enable(priv->clk);
+ hix5hd2_i2c_init(priv);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops hix5hd2_i2c_pm_ops = {
+ SET_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend,
+ hix5hd2_i2c_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id hix5hd2_i2c_match[] = {
+ { .compatible = "hisilicon,hix5hd2-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match);
+
+static struct platform_driver hix5hd2_i2c_driver = {
+ .probe = hix5hd2_i2c_probe,
+ .remove = hix5hd2_i2c_remove,
+ .driver = {
+ .name = "hix5hd2-i2c",
+ .pm = &hix5hd2_i2c_pm_ops,
+ .of_match_table = hix5hd2_i2c_match,
+ },
+};
+
+module_platform_driver(hix5hd2_i2c_driver);
+
+MODULE_DESCRIPTION("Hix5hd2 I2C Bus driver");
+MODULE_AUTHOR("Wei Yan <sledge.yanwei@huawei.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hix5hd2-i2c");
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
new file mode 100644
index 000000000..b7864cf42
--- /dev/null
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -0,0 +1,158 @@
+/*
+ i2c Support for the Apple `Hydra' Mac I/O
+
+ Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org>
+
+ Based on i2c Support for Via Technologies 82C586B South Bridge
+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+#include <asm/hydra.h>
+
+
+#define HYDRA_CPD_PD0 0x00000001 /* CachePD lines */
+#define HYDRA_CPD_PD1 0x00000002
+#define HYDRA_CPD_PD2 0x00000004
+#define HYDRA_CPD_PD3 0x00000008
+
+#define HYDRA_SCLK HYDRA_CPD_PD0
+#define HYDRA_SDAT HYDRA_CPD_PD1
+#define HYDRA_SCLK_OE 0x00000010
+#define HYDRA_SDAT_OE 0x00000020
+
+static inline void pdregw(void *data, u32 val)
+{
+ struct Hydra *hydra = (struct Hydra *)data;
+ writel(val, &hydra->CachePD);
+}
+
+static inline u32 pdregr(void *data)
+{
+ struct Hydra *hydra = (struct Hydra *)data;
+ return readl(&hydra->CachePD);
+}
+
+static void hydra_bit_setscl(void *data, int state)
+{
+ u32 val = pdregr(data);
+ if (state)
+ val &= ~HYDRA_SCLK_OE;
+ else {
+ val &= ~HYDRA_SCLK;
+ val |= HYDRA_SCLK_OE;
+ }
+ pdregw(data, val);
+}
+
+static void hydra_bit_setsda(void *data, int state)
+{
+ u32 val = pdregr(data);
+ if (state)
+ val &= ~HYDRA_SDAT_OE;
+ else {
+ val &= ~HYDRA_SDAT;
+ val |= HYDRA_SDAT_OE;
+ }
+ pdregw(data, val);
+}
+
+static int hydra_bit_getscl(void *data)
+{
+ return (pdregr(data) & HYDRA_SCLK) != 0;
+}
+
+static int hydra_bit_getsda(void *data)
+{
+ return (pdregr(data) & HYDRA_SDAT) != 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct i2c_algo_bit_data hydra_bit_data = {
+ .setsda = hydra_bit_setsda,
+ .setscl = hydra_bit_setscl,
+ .getsda = hydra_bit_getsda,
+ .getscl = hydra_bit_getscl,
+ .udelay = 5,
+ .timeout = HZ
+};
+
+static struct i2c_adapter hydra_adap = {
+ .owner = THIS_MODULE,
+ .name = "Hydra i2c",
+ .algo_data = &hydra_bit_data,
+};
+
+static const struct pci_device_id hydra_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, hydra_ids);
+
+static int hydra_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ unsigned long base = pci_resource_start(dev, 0);
+ int res;
+
+ if (!request_mem_region(base+offsetof(struct Hydra, CachePD), 4,
+ hydra_adap.name))
+ return -EBUSY;
+
+ hydra_bit_data.data = pci_ioremap_bar(dev, 0);
+ if (hydra_bit_data.data == NULL) {
+ release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
+ return -ENODEV;
+ }
+
+ pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */
+ hydra_adap.dev.parent = &dev->dev;
+ res = i2c_bit_add_bus(&hydra_adap);
+ if (res < 0) {
+ iounmap(hydra_bit_data.data);
+ release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
+ return res;
+ }
+ return 0;
+}
+
+static void hydra_remove(struct pci_dev *dev)
+{
+ pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */
+ i2c_del_adapter(&hydra_adap);
+ iounmap(hydra_bit_data.data);
+ release_mem_region(pci_resource_start(dev, 0)+
+ offsetof(struct Hydra, CachePD), 4);
+}
+
+
+static struct pci_driver hydra_driver = {
+ .name = "hydra_smbus",
+ .id_table = hydra_ids,
+ .probe = hydra_probe,
+ .remove = hydra_remove,
+};
+
+module_pci_driver(hydra_driver);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
new file mode 100644
index 000000000..fb0ddaad8
--- /dev/null
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -0,0 +1,1785 @@
+/*
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
+ <mdsxyz123@yahoo.com>
+ Copyright (C) 2007 - 2014 Jean Delvare <jdelvare@suse.de>
+ Copyright (C) 2010 Intel Corporation,
+ David Woodhouse <dwmw2@infradead.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ * Supports the following Intel I/O Controller Hubs (ICH):
+ *
+ * I/O Block I2C
+ * region SMBus Block proc. block
+ * Chip name PCI ID size PEC buffer call read
+ * ---------------------------------------------------------------------------
+ * 82801AA (ICH) 0x2413 16 no no no no
+ * 82801AB (ICH0) 0x2423 16 no no no no
+ * 82801BA (ICH2) 0x2443 16 no no no no
+ * 82801CA (ICH3) 0x2483 32 soft no no no
+ * 82801DB (ICH4) 0x24c3 32 hard yes no no
+ * 82801E (ICH5) 0x24d3 32 hard yes yes yes
+ * 6300ESB 0x25a4 32 hard yes yes yes
+ * 82801F (ICH6) 0x266a 32 hard yes yes yes
+ * 6310ESB/6320ESB 0x269b 32 hard yes yes yes
+ * 82801G (ICH7) 0x27da 32 hard yes yes yes
+ * 82801H (ICH8) 0x283e 32 hard yes yes yes
+ * 82801I (ICH9) 0x2930 32 hard yes yes yes
+ * EP80579 (Tolapai) 0x5032 32 hard yes yes yes
+ * ICH10 0x3a30 32 hard yes yes yes
+ * ICH10 0x3a60 32 hard yes yes yes
+ * 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes
+ * 6 Series (PCH) 0x1c22 32 hard yes yes yes
+ * Patsburg (PCH) 0x1d22 32 hard yes yes yes
+ * Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes
+ * Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes
+ * Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
+ * DH89xxCC (PCH) 0x2330 32 hard yes yes yes
+ * Panther Point (PCH) 0x1e22 32 hard yes yes yes
+ * Lynx Point (PCH) 0x8c22 32 hard yes yes yes
+ * Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes
+ * Avoton (SOC) 0x1f3c 32 hard yes yes yes
+ * Wellsburg (PCH) 0x8d22 32 hard yes yes yes
+ * Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes
+ * 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 (PCH) 0x8ca2 32 hard yes yes yes
+ * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
+ * BayTrail (SOC) 0x0f12 32 hard yes yes yes
+ * Braswell (SOC) 0x2292 32 hard yes yes yes
+ * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
+ * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
+ * DNV (SOC) 0x19df 32 hard yes yes yes
+ * Broxton (SOC) 0x5ad4 32 hard yes yes yes
+ * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
+ * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes
+ * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes
+ * Gemini Lake (SOC) 0x31d4 32 hard yes yes yes
+ * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes
+ * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes
+ * Cedar Fork (PCH) 0x18df 32 hard yes yes yes
+ * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes
+ * Comet Lake (PCH) 0x02a3 32 hard yes yes yes
+ *
+ * Features supported by this driver:
+ * Software PEC no
+ * Hardware PEC yes
+ * Block buffer yes
+ * Block process call transaction no
+ * I2C block read transaction yes (doesn't use the block buffer)
+ * Slave mode no
+ * SMBus Host Notify yes
+ * Interrupt processing yes
+ *
+ * See the file Documentation/i2c/busses/i2c-i801 for details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/itco_wdt.h>
+#include <linux/pm_runtime.h>
+
+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
+#include <linux/gpio.h>
+#include <linux/platform_data/i2c-mux-gpio.h>
+#endif
+
+/* I801 SMBus address offsets */
+#define SMBHSTSTS(p) (0 + (p)->smba)
+#define SMBHSTCNT(p) (2 + (p)->smba)
+#define SMBHSTCMD(p) (3 + (p)->smba)
+#define SMBHSTADD(p) (4 + (p)->smba)
+#define SMBHSTDAT0(p) (5 + (p)->smba)
+#define SMBHSTDAT1(p) (6 + (p)->smba)
+#define SMBBLKDAT(p) (7 + (p)->smba)
+#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */
+#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */
+#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */
+#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */
+#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */
+#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */
+
+/* PCI Address Constants */
+#define SMBBAR 4
+#define SMBPCICTL 0x004
+#define SMBPCISTS 0x006
+#define SMBHSTCFG 0x040
+#define TCOBASE 0x050
+#define TCOCTL 0x054
+
+#define ACPIBASE 0x040
+#define ACPIBASE_SMI_OFF 0x030
+#define ACPICTRL 0x044
+#define ACPICTRL_EN 0x080
+
+#define SBREG_BAR 0x10
+#define SBREG_SMBCTRL 0xc6000c
+#define SBREG_SMBCTRL_DNV 0xcf000c
+
+/* Host status bits for SMBPCISTS */
+#define SMBPCISTS_INTS BIT(3)
+
+/* Control bits for SMBPCICTL */
+#define SMBPCICTL_INTDIS BIT(10)
+
+/* Host configuration bits for SMBHSTCFG */
+#define SMBHSTCFG_HST_EN BIT(0)
+#define SMBHSTCFG_SMB_SMI_EN BIT(1)
+#define SMBHSTCFG_I2C_EN BIT(2)
+#define SMBHSTCFG_SPD_WD BIT(4)
+
+/* TCO configuration bits for TCOCTL */
+#define TCOCTL_EN BIT(8)
+
+/* Auxiliary status register bits, ICH4+ only */
+#define SMBAUXSTS_CRCE BIT(0)
+#define SMBAUXSTS_STCO BIT(1)
+
+/* Auxiliary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC BIT(0)
+#define SMBAUXCTL_E32B BIT(1)
+
+/* Other settings */
+#define MAX_RETRIES 400
+
+/* I801 command constants */
+#define I801_QUICK 0x00
+#define I801_BYTE 0x04
+#define I801_BYTE_DATA 0x08
+#define I801_WORD_DATA 0x0C
+#define I801_PROC_CALL 0x10 /* unimplemented */
+#define I801_BLOCK_DATA 0x14
+#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
+
+/* I801 Host Control register bits */
+#define SMBHSTCNT_INTREN BIT(0)
+#define SMBHSTCNT_KILL BIT(1)
+#define SMBHSTCNT_LAST_BYTE BIT(5)
+#define SMBHSTCNT_START BIT(6)
+#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE BIT(7)
+#define SMBHSTSTS_INUSE_STS BIT(6)
+#define SMBHSTSTS_SMBALERT_STS BIT(5)
+#define SMBHSTSTS_FAILED BIT(4)
+#define SMBHSTSTS_BUS_ERR BIT(3)
+#define SMBHSTSTS_DEV_ERR BIT(2)
+#define SMBHSTSTS_INTR BIT(1)
+#define SMBHSTSTS_HOST_BUSY BIT(0)
+
+/* Host Notify Status register bits */
+#define SMBSLVSTS_HST_NTFY_STS BIT(0)
+
+/* Host Notify Command register bits */
+#define SMBSLVCMD_HST_NTFY_INTREN BIT(0)
+
+#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
+ SMBHSTSTS_DEV_ERR)
+
+#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \
+ STATUS_ERROR_FLAGS)
+
+/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
+#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df
+#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
+#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
+#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292
+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
+#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
+#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
+#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
+#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
+#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
+#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d
+#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
+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23
+#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3
+#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3
+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
+#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
+#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
+#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3
+
+struct i801_mux_config {
+ char *gpio_chip;
+ unsigned values[3];
+ int n_values;
+ unsigned classes[3];
+ unsigned gpios[2]; /* Relative to gpio_chip->base */
+ int n_gpios;
+};
+
+struct i801_priv {
+ struct i2c_adapter adapter;
+ unsigned long smba;
+ unsigned char original_hstcfg;
+ unsigned char original_slvcmd;
+ struct pci_dev *pci_dev;
+ unsigned int features;
+
+ /* isr processing */
+ wait_queue_head_t waitq;
+ u8 status;
+
+ /* Command state used by isr for byte-by-byte block transactions */
+ u8 cmd;
+ bool is_read;
+ int count;
+ int len;
+ u8 *data;
+
+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
+ const struct i801_mux_config *mux_drvdata;
+ struct platform_device *mux_pdev;
+#endif
+ struct platform_device *tco_pdev;
+
+ /*
+ * If set to true the host controller registers are reserved for
+ * ACPI AML use. Protected by acpi_lock.
+ */
+ bool acpi_reserved;
+ struct mutex acpi_lock;
+};
+
+#define FEATURE_SMBUS_PEC BIT(0)
+#define FEATURE_BLOCK_BUFFER BIT(1)
+#define FEATURE_BLOCK_PROC BIT(2)
+#define FEATURE_I2C_BLOCK_READ BIT(3)
+#define FEATURE_IRQ BIT(4)
+#define FEATURE_HOST_NOTIFY BIT(5)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF BIT(15)
+#define FEATURE_TCO BIT(16)
+
+static const char *i801_feature_names[] = {
+ "SMBus PEC",
+ "Block buffer",
+ "Block process call",
+ "I2C block read",
+ "Interrupt",
+ "SMBus Host Notify",
+};
+
+static unsigned int disable_features;
+module_param(disable_features, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
+ "\t\t 0x01 disable SMBus PEC\n"
+ "\t\t 0x02 disable the block buffer\n"
+ "\t\t 0x08 disable the I2C block read functionality\n"
+ "\t\t 0x10 don't use interrupts\n"
+ "\t\t 0x20 disable SMBus Host Notify ");
+
+/* Make sure the SMBus host is ready to start transmitting.
+ Return 0 if it is, -EBUSY if it is not. */
+static int i801_check_pre(struct i801_priv *priv)
+{
+ int status;
+
+ status = inb_p(SMBHSTSTS(priv));
+ if (status & SMBHSTSTS_HOST_BUSY) {
+ dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
+ return -EBUSY;
+ }
+
+ status &= STATUS_FLAGS;
+ if (status) {
+ dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
+ status);
+ outb_p(status, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+ if (status) {
+ dev_err(&priv->pci_dev->dev,
+ "Failed clearing status flags (%02x)\n",
+ status);
+ return -EBUSY;
+ }
+ }
+
+ /*
+ * Clear CRC status if needed.
+ * During normal operation, i801_check_post() takes care
+ * of it after every operation. We do it here only in case
+ * the hardware was already in this state when the driver
+ * started.
+ */
+ if (priv->features & FEATURE_SMBUS_PEC) {
+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
+ if (status) {
+ dev_dbg(&priv->pci_dev->dev,
+ "Clearing aux status flags (%02x)\n", status);
+ outb_p(status, SMBAUXSTS(priv));
+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
+ if (status) {
+ dev_err(&priv->pci_dev->dev,
+ "Failed clearing aux status flags (%02x)\n",
+ status);
+ return -EBUSY;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Convert the status register to an error code, and clear it.
+ * Note that status only contains the bits we want to clear, not the
+ * actual register value.
+ */
+static int i801_check_post(struct i801_priv *priv, int status)
+{
+ int result = 0;
+
+ /*
+ * If the SMBus is still busy, we give up
+ * Note: This timeout condition only happens when using polling
+ * transactions. For interrupt operation, NAK/timeout is indicated by
+ * DEV_ERR.
+ */
+ if (unlikely(status < 0)) {
+ dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
+ /* try to stop the current command */
+ dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
+ outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv));
+ usleep_range(1000, 2000);
+ outb_p(0, SMBHSTCNT(priv));
+
+ /* Check if it worked */
+ status = inb_p(SMBHSTSTS(priv));
+ if ((status & SMBHSTSTS_HOST_BUSY) ||
+ !(status & SMBHSTSTS_FAILED))
+ dev_err(&priv->pci_dev->dev,
+ "Failed terminating the transaction\n");
+ outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
+ return -ETIMEDOUT;
+ }
+
+ if (status & SMBHSTSTS_FAILED) {
+ result = -EIO;
+ dev_err(&priv->pci_dev->dev, "Transaction failed\n");
+ }
+ if (status & SMBHSTSTS_DEV_ERR) {
+ /*
+ * This may be a PEC error, check and clear it.
+ *
+ * AUXSTS is handled differently from HSTSTS.
+ * For HSTSTS, i801_isr() or i801_wait_intr()
+ * has already cleared the error bits in hardware,
+ * and we are passed a copy of the original value
+ * in "status".
+ * For AUXSTS, the hardware register is left
+ * for us to handle here.
+ * This is asymmetric, slightly iffy, but safe,
+ * since all this code is serialized and the CRCE
+ * bit is harmless as long as it's cleared before
+ * the next operation.
+ */
+ if ((priv->features & FEATURE_SMBUS_PEC) &&
+ (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) {
+ outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv));
+ result = -EBADMSG;
+ dev_dbg(&priv->pci_dev->dev, "PEC error\n");
+ } else {
+ result = -ENXIO;
+ dev_dbg(&priv->pci_dev->dev, "No response\n");
+ }
+ }
+ if (status & SMBHSTSTS_BUS_ERR) {
+ result = -EAGAIN;
+ dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
+ }
+
+ /* Clear status flags except BYTE_DONE, to be cleared by caller */
+ outb_p(status, SMBHSTSTS(priv));
+
+ return result;
+}
+
+/* Wait for BUSY being cleared and either INTR or an error flag being set */
+static int i801_wait_intr(struct i801_priv *priv)
+{
+ int timeout = 0;
+ int status;
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ usleep_range(250, 500);
+ status = inb_p(SMBHSTSTS(priv));
+ } while (((status & SMBHSTSTS_HOST_BUSY) ||
+ !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) &&
+ (timeout++ < MAX_RETRIES));
+
+ if (timeout > MAX_RETRIES) {
+ dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n");
+ return -ETIMEDOUT;
+ }
+ return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR);
+}
+
+/* Wait for either BYTE_DONE or an error flag being set */
+static int i801_wait_byte_done(struct i801_priv *priv)
+{
+ int timeout = 0;
+ int status;
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ usleep_range(250, 500);
+ status = inb_p(SMBHSTSTS(priv));
+ } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) &&
+ (timeout++ < MAX_RETRIES));
+
+ if (timeout > MAX_RETRIES) {
+ dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n");
+ return -ETIMEDOUT;
+ }
+ return status & STATUS_ERROR_FLAGS;
+}
+
+static int i801_transaction(struct i801_priv *priv, int xact)
+{
+ int status;
+ int result;
+ const struct i2c_adapter *adap = &priv->adapter;
+
+ result = i801_check_pre(priv);
+ if (result < 0)
+ return result;
+
+ if (priv->features & FEATURE_IRQ) {
+ outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
+ SMBHSTCNT(priv));
+ result = wait_event_timeout(priv->waitq,
+ (status = priv->status),
+ adap->timeout);
+ if (!result) {
+ status = -ETIMEDOUT;
+ dev_warn(&priv->pci_dev->dev,
+ "Timeout waiting for interrupt!\n");
+ }
+ priv->status = 0;
+ return i801_check_post(priv, status);
+ }
+
+ /* the current contents of SMBHSTCNT can be overwritten, since PEC,
+ * SMBSCMD are passed in xact */
+ outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
+
+ status = i801_wait_intr(priv);
+ return i801_check_post(priv, status);
+}
+
+static int i801_block_transaction_by_block(struct i801_priv *priv,
+ union i2c_smbus_data *data,
+ char read_write, int hwpec)
+{
+ int i, len;
+ int status;
+
+ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
+
+ /* Use 32-byte buffer to process this transaction */
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ outb_p(len, SMBHSTDAT0(priv));
+ for (i = 0; i < len; i++)
+ outb_p(data->block[i+1], SMBBLKDAT(priv));
+ }
+
+ status = i801_transaction(priv, I801_BLOCK_DATA |
+ (hwpec ? SMBHSTCNT_PEC_EN : 0));
+ if (status)
+ return status;
+
+ if (read_write == I2C_SMBUS_READ) {
+ len = inb_p(SMBHSTDAT0(priv));
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+
+ data->block[0] = len;
+ for (i = 0; i < len; i++)
+ data->block[i + 1] = inb_p(SMBBLKDAT(priv));
+ }
+ return 0;
+}
+
+static void i801_isr_byte_done(struct i801_priv *priv)
+{
+ if (priv->is_read) {
+ /* For SMBus block reads, length is received with first byte */
+ if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) &&
+ (priv->count == 0)) {
+ priv->len = inb_p(SMBHSTDAT0(priv));
+ if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&priv->pci_dev->dev,
+ "Illegal SMBus block read size %d\n",
+ priv->len);
+ /* FIXME: Recover */
+ priv->len = I2C_SMBUS_BLOCK_MAX;
+ } else {
+ dev_dbg(&priv->pci_dev->dev,
+ "SMBus block read size is %d\n",
+ priv->len);
+ }
+ priv->data[-1] = priv->len;
+ }
+
+ /* Read next byte */
+ if (priv->count < priv->len)
+ priv->data[priv->count++] = inb(SMBBLKDAT(priv));
+ else
+ dev_dbg(&priv->pci_dev->dev,
+ "Discarding extra byte on block read\n");
+
+ /* Set LAST_BYTE for last byte of read transaction */
+ if (priv->count == priv->len - 1)
+ outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
+ SMBHSTCNT(priv));
+ } else if (priv->count < priv->len - 1) {
+ /* Write next byte, except for IRQ after last byte */
+ outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
+ }
+
+ /* Clear BYTE_DONE to continue with next byte */
+ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
+}
+
+static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
+{
+ unsigned short addr;
+
+ addr = inb_p(SMBNTFDADD(priv)) >> 1;
+
+ /*
+ * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba)
+ * always returns 0. Our current implementation doesn't provide
+ * data, so we just ignore it.
+ */
+ i2c_handle_smbus_host_notify(&priv->adapter, addr);
+
+ /* clear Host Notify bit and return */
+ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
+ return IRQ_HANDLED;
+}
+
+/*
+ * There are three kinds of interrupts:
+ *
+ * 1) i801 signals transaction completion with one of these interrupts:
+ * INTR - Success
+ * DEV_ERR - Invalid command, NAK or communication timeout
+ * BUS_ERR - SMI# transaction collision
+ * FAILED - transaction was canceled due to a KILL request
+ * When any of these occur, update ->status and wake up the waitq.
+ * ->status must be cleared before kicking off the next transaction.
+ *
+ * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
+ * occurs for each byte of a byte-by-byte to prepare the next byte.
+ *
+ * 3) Host Notify interrupts
+ */
+static irqreturn_t i801_isr(int irq, void *dev_id)
+{
+ struct i801_priv *priv = dev_id;
+ u16 pcists;
+ u8 status;
+
+ /* Confirm this is our interrupt */
+ pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
+ if (!(pcists & SMBPCISTS_INTS))
+ return IRQ_NONE;
+
+ if (priv->features & FEATURE_HOST_NOTIFY) {
+ status = inb_p(SMBSLVSTS(priv));
+ if (status & SMBSLVSTS_HST_NTFY_STS)
+ return i801_host_notify_isr(priv);
+ }
+
+ status = inb_p(SMBHSTSTS(priv));
+ if (status & SMBHSTSTS_BYTE_DONE)
+ i801_isr_byte_done(priv);
+
+ /*
+ * Clear irq sources and report transaction result.
+ * ->status must be cleared before the next transaction is started.
+ */
+ status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
+ if (status) {
+ outb_p(status, SMBHSTSTS(priv));
+ priv->status = status;
+ wake_up(&priv->waitq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * For "byte-by-byte" block transactions:
+ * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
+ * I2C read uses cmd=I801_I2C_BLOCK_DATA
+ */
+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
+ union i2c_smbus_data *data,
+ char read_write, int command,
+ int hwpec)
+{
+ int i, len;
+ int smbcmd;
+ int status;
+ int result;
+ const struct i2c_adapter *adap = &priv->adapter;
+
+ result = i801_check_pre(priv);
+ if (result < 0)
+ return result;
+
+ len = data->block[0];
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(len, SMBHSTDAT0(priv));
+ outb_p(data->block[1], SMBBLKDAT(priv));
+ }
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA &&
+ read_write == I2C_SMBUS_READ)
+ smbcmd = I801_I2C_BLOCK_DATA;
+ else
+ smbcmd = I801_BLOCK_DATA;
+
+ if (priv->features & FEATURE_IRQ) {
+ priv->is_read = (read_write == I2C_SMBUS_READ);
+ if (len == 1 && priv->is_read)
+ smbcmd |= SMBHSTCNT_LAST_BYTE;
+ priv->cmd = smbcmd | SMBHSTCNT_INTREN;
+ priv->len = len;
+ priv->count = 0;
+ priv->data = &data->block[1];
+
+ outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
+ result = wait_event_timeout(priv->waitq,
+ (status = priv->status),
+ adap->timeout);
+ if (!result) {
+ status = -ETIMEDOUT;
+ dev_warn(&priv->pci_dev->dev,
+ "Timeout waiting for interrupt!\n");
+ }
+ priv->status = 0;
+ return i801_check_post(priv, status);
+ }
+
+ for (i = 1; i <= len; i++) {
+ if (i == len && read_write == I2C_SMBUS_READ)
+ smbcmd |= SMBHSTCNT_LAST_BYTE;
+ outb_p(smbcmd, SMBHSTCNT(priv));
+
+ if (i == 1)
+ outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START,
+ SMBHSTCNT(priv));
+
+ status = i801_wait_byte_done(priv);
+ if (status)
+ goto exit;
+
+ if (i == 1 && read_write == I2C_SMBUS_READ
+ && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+ len = inb_p(SMBHSTDAT0(priv));
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&priv->pci_dev->dev,
+ "Illegal SMBus block read size %d\n",
+ len);
+ /* Recover */
+ while (inb_p(SMBHSTSTS(priv)) &
+ SMBHSTSTS_HOST_BUSY)
+ outb_p(SMBHSTSTS_BYTE_DONE,
+ SMBHSTSTS(priv));
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ return -EPROTO;
+ }
+ data->block[0] = len;
+ }
+
+ /* Retrieve/store value in SMBBLKDAT */
+ if (read_write == I2C_SMBUS_READ)
+ data->block[i] = inb_p(SMBBLKDAT(priv));
+ if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
+ outb_p(data->block[i+1], SMBBLKDAT(priv));
+
+ /* signals SMBBLKDAT ready */
+ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
+ }
+
+ status = i801_wait_intr(priv);
+exit:
+ return i801_check_post(priv, status);
+}
+
+static int i801_set_block_buffer_mode(struct i801_priv *priv)
+{
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
+ return -EIO;
+ return 0;
+}
+
+/* Block transaction function */
+static int i801_block_transaction(struct i801_priv *priv,
+ union i2c_smbus_data *data, char read_write,
+ int command, int hwpec)
+{
+ int result = 0;
+ unsigned char hostc;
+
+ if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* set I2C_EN bit in configuration register */
+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
+ hostc | SMBHSTCFG_I2C_EN);
+ } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+ dev_err(&priv->pci_dev->dev,
+ "I2C block read is unsupported!\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ /* Experience has shown that the block buffer can only be used for
+ SMBus (not I2C) block transactions, even though the datasheet
+ doesn't mention this limitation. */
+ if ((priv->features & FEATURE_BLOCK_BUFFER)
+ && command != I2C_SMBUS_I2C_BLOCK_DATA
+ && i801_set_block_buffer_mode(priv) == 0)
+ result = i801_block_transaction_by_block(priv, data,
+ read_write, hwpec);
+ else
+ result = i801_block_transaction_byte_by_byte(priv, data,
+ read_write,
+ command, hwpec);
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA
+ && read_write == I2C_SMBUS_WRITE) {
+ /* restore saved configuration register value */
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
+ }
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 i801_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int hwpec;
+ int block = 0;
+ int ret = 0, xact = 0;
+ struct i801_priv *priv = i2c_get_adapdata(adap);
+
+ mutex_lock(&priv->acpi_lock);
+ if (priv->acpi_reserved) {
+ mutex_unlock(&priv->acpi_lock);
+ return -EBUSY;
+ }
+
+ pm_runtime_get_sync(&priv->pci_dev->dev);
+
+ hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+ && size != I2C_SMBUS_QUICK
+ && size != I2C_SMBUS_I2C_BLOCK_DATA;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD(priv));
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0(priv));
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ }
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /*
+ * NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading.
+ * However if SPD Write Disable is set (Lynx Point and later),
+ * the read will fail if we don't set the R/#W bit.
+ */
+ outb_p(((addr & 0x7f) << 1) |
+ ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ?
+ (read_write & 0x01) : 0),
+ SMBHSTADD(priv));
+ if (read_write == I2C_SMBUS_READ) {
+ /* NB: page 240 of ICH5 datasheet also shows
+ * that DATA1 is the cmd field when reading */
+ outb_p(command, SMBHSTDAT1(priv));
+ } else
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
+ default:
+ dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+ size);
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (hwpec) /* enable/disable hardware PEC */
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
+ else
+ outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+ SMBAUXCTL(priv));
+
+ if (block)
+ ret = i801_block_transaction(priv, data, read_write, size,
+ hwpec);
+ else
+ ret = i801_transaction(priv, xact);
+
+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ time, so we forcibly disable it after every transaction. Turn off
+ E32B for the same reason. */
+ if (hwpec || block)
+ outb_p(inb_p(SMBAUXCTL(priv)) &
+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+
+ if (block)
+ goto out;
+ if (ret)
+ goto out;
+ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
+ goto out;
+
+ switch (xact & 0x7f) {
+ case I801_BYTE: /* Result put in SMBHSTDAT0 */
+ case I801_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0(priv));
+ break;
+ case I801_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0(priv)) +
+ (inb_p(SMBHSTDAT1(priv)) << 8);
+ break;
+ }
+
+out:
+ pm_runtime_mark_last_busy(&priv->pci_dev->dev);
+ pm_runtime_put_autosuspend(&priv->pci_dev->dev);
+ mutex_unlock(&priv->acpi_lock);
+ return ret;
+}
+
+
+static u32 i801_func(struct i2c_adapter *adapter)
+{
+ struct i801_priv *priv = i2c_get_adapdata(adapter);
+
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+ ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+ ((priv->features & FEATURE_I2C_BLOCK_READ) ?
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) |
+ ((priv->features & FEATURE_HOST_NOTIFY) ?
+ I2C_FUNC_SMBUS_HOST_NOTIFY : 0);
+}
+
+static void i801_enable_host_notify(struct i2c_adapter *adapter)
+{
+ struct i801_priv *priv = i2c_get_adapdata(adapter);
+
+ if (!(priv->features & FEATURE_HOST_NOTIFY))
+ return;
+
+ if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd))
+ outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd,
+ SMBSLVCMD(priv));
+
+ /* clear Host Notify bit to allow a new notification */
+ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
+}
+
+static void i801_disable_host_notify(struct i801_priv *priv)
+{
+ if (!(priv->features & FEATURE_HOST_NOTIFY))
+ return;
+
+ outb_p(priv->original_slvcmd, SMBSLVCMD(priv));
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = i801_access,
+ .functionality = i801_func,
+};
+
+static const struct pci_device_id i801_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) },
+ { 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_GEMINILAKE_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, i801_ids);
+
+#if defined CONFIG_X86 && defined CONFIG_DMI
+static unsigned char apanel_addr;
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+ ssize_t offset;
+ const unsigned char signature[] = "FJKEYINF";
+
+ for (offset = 0; offset < 0x10000; offset += 0x10) {
+ if (check_signature(bios + offset, signature,
+ sizeof(signature)-1))
+ return bios + offset;
+ }
+ return NULL;
+}
+
+static void __init input_apanel_init(void)
+{
+ void __iomem *bios;
+ const void __iomem *p;
+
+ bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+ p = bios_signature(bios);
+ if (p) {
+ /* just use the first address */
+ apanel_addr = readb(p + 8 + 3) >> 1;
+ }
+ iounmap(bios);
+}
+
+struct dmi_onboard_device_info {
+ const char *name;
+ u8 type;
+ unsigned short i2c_addr;
+ const char *i2c_type;
+};
+
+static const struct dmi_onboard_device_info dmi_devices[] = {
+ { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
+ { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
+ { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
+};
+
+static void dmi_check_onboard_device(u8 type, const char *name,
+ struct i2c_adapter *adap)
+{
+ int i;
+ struct i2c_board_info info;
+
+ for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
+ /* & ~0x80, ignore enabled/disabled bit */
+ if ((type & ~0x80) != dmi_devices[i].type)
+ continue;
+ if (strcasecmp(name, dmi_devices[i].name))
+ continue;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = dmi_devices[i].i2c_addr;
+ strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
+ i2c_new_device(adap, &info);
+ break;
+ }
+}
+
+/* We use our own function to check for onboard devices instead of
+ dmi_find_device() as some buggy BIOS's have the devices we are interested
+ in marked as disabled */
+static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
+{
+ int i, count;
+
+ if (dm->type != 10)
+ return;
+
+ count = (dm->length - sizeof(struct dmi_header)) / 2;
+ for (i = 0; i < count; i++) {
+ const u8 *d = (char *)(dm + 1) + (i * 2);
+ const char *name = ((char *) dm) + dm->length;
+ u8 type = d[0];
+ u8 s = d[1];
+
+ if (!s)
+ continue;
+ s--;
+ while (s > 0 && name[0]) {
+ name += strlen(name) + 1;
+ s--;
+ }
+ if (name[0] == 0) /* Bogus string reference */
+ continue;
+
+ dmi_check_onboard_device(type, name, adap);
+ }
+}
+
+/* Register optional slaves */
+static void i801_probe_optional_slaves(struct i801_priv *priv)
+{
+ /* Only register slaves on main SMBus channel */
+ if (priv->features & FEATURE_IDF)
+ return;
+
+ if (apanel_addr) {
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = apanel_addr;
+ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+ i2c_new_device(&priv->adapter, &info);
+ }
+
+ if (dmi_name_in_vendors("FUJITSU"))
+ dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+}
+#else
+static void __init input_apanel_init(void) {}
+static void i801_probe_optional_slaves(struct i801_priv *priv) {}
+#endif /* CONFIG_X86 && CONFIG_DMI */
+
+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
+static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
+ .gpio_chip = "gpio_ich",
+ .values = { 0x02, 0x03 },
+ .n_values = 2,
+ .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
+ .gpios = { 52, 53 },
+ .n_gpios = 2,
+};
+
+static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
+ .gpio_chip = "gpio_ich",
+ .values = { 0x02, 0x03, 0x01 },
+ .n_values = 3,
+ .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
+ .gpios = { 52, 53 },
+ .n_gpios = 2,
+};
+
+static const struct dmi_system_id mux_dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d18,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d18,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"),
+ },
+ .driver_data = &i801_mux_config_asus_z8_d12,
+ },
+ { }
+};
+
+/* Setup multiplexing if needed */
+static int i801_add_mux(struct i801_priv *priv)
+{
+ struct device *dev = &priv->adapter.dev;
+ const struct i801_mux_config *mux_config;
+ struct i2c_mux_gpio_platform_data gpio_data;
+ int err;
+
+ if (!priv->mux_drvdata)
+ return 0;
+ mux_config = priv->mux_drvdata;
+
+ /* Prepare the platform data */
+ memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
+ gpio_data.parent = priv->adapter.nr;
+ gpio_data.values = mux_config->values;
+ gpio_data.n_values = mux_config->n_values;
+ gpio_data.classes = mux_config->classes;
+ gpio_data.gpio_chip = mux_config->gpio_chip;
+ gpio_data.gpios = mux_config->gpios;
+ gpio_data.n_gpios = mux_config->n_gpios;
+ gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
+
+ /* Register the mux device */
+ priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
+ PLATFORM_DEVID_AUTO, &gpio_data,
+ sizeof(struct i2c_mux_gpio_platform_data));
+ if (IS_ERR(priv->mux_pdev)) {
+ err = PTR_ERR(priv->mux_pdev);
+ priv->mux_pdev = NULL;
+ dev_err(dev, "Failed to register i2c-mux-gpio device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void i801_del_mux(struct i801_priv *priv)
+{
+ if (priv->mux_pdev)
+ platform_device_unregister(priv->mux_pdev);
+}
+
+static unsigned int i801_get_adapter_class(struct i801_priv *priv)
+{
+ const struct dmi_system_id *id;
+ const struct i801_mux_config *mux_config;
+ unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ int i;
+
+ id = dmi_first_match(mux_dmi_table);
+ if (id) {
+ /* Remove branch classes from trunk */
+ mux_config = id->driver_data;
+ for (i = 0; i < mux_config->n_values; i++)
+ class &= ~mux_config->classes[i];
+
+ /* Remember for later */
+ priv->mux_drvdata = mux_config;
+ }
+
+ return class;
+}
+#else
+static inline int i801_add_mux(struct i801_priv *priv) { return 0; }
+static inline void i801_del_mux(struct i801_priv *priv) { }
+
+static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
+{
+ return I2C_CLASS_HWMON | I2C_CLASS_SPD;
+}
+#endif
+
+static const struct itco_wdt_platform_data tco_platform_data = {
+ .name = "Intel PCH",
+ .version = 4,
+};
+
+static DEFINE_SPINLOCK(p2sb_spinlock);
+
+static void i801_add_tco(struct i801_priv *priv)
+{
+ struct pci_dev *pci_dev = priv->pci_dev;
+ struct resource tco_res[3], *res;
+ struct platform_device *pdev;
+ unsigned int devfn;
+ u32 tco_base, tco_ctl;
+ u32 base_addr, ctrl_val;
+ u64 base64_addr;
+ u8 hidden;
+
+ if (!(priv->features & FEATURE_TCO))
+ return;
+
+ pci_read_config_dword(pci_dev, TCOBASE, &tco_base);
+ pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl);
+ if (!(tco_ctl & TCOCTL_EN))
+ return;
+
+ memset(tco_res, 0, sizeof(tco_res));
+
+ res = &tco_res[ICH_RES_IO_TCO];
+ res->start = tco_base & ~1;
+ res->end = res->start + 32 - 1;
+ res->flags = IORESOURCE_IO;
+
+ /*
+ * Power Management registers.
+ */
+ devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2);
+ pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr);
+
+ res = &tco_res[ICH_RES_IO_SMI];
+ res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF;
+ res->end = res->start + 3;
+ res->flags = IORESOURCE_IO;
+
+ /*
+ * Enable the ACPI I/O space.
+ */
+ pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val);
+ ctrl_val |= ACPICTRL_EN;
+ pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val);
+
+ /*
+ * We must access the NO_REBOOT bit over the Primary to Sideband
+ * bridge (P2SB). The BIOS prevents the P2SB device from being
+ * enumerated by the PCI subsystem, so we need to unhide/hide it
+ * to lookup the P2SB BAR.
+ */
+ spin_lock(&p2sb_spinlock);
+
+ devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1);
+
+ /* Unhide the P2SB device, if it is hidden */
+ pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden);
+ if (hidden)
+ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0);
+
+ pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr);
+ base64_addr = base_addr & 0xfffffff0;
+
+ pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr);
+ base64_addr |= (u64)base_addr << 32;
+
+ /* Hide the P2SB device, if it was hidden before */
+ if (hidden)
+ pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
+ spin_unlock(&p2sb_spinlock);
+
+ res = &tco_res[ICH_RES_MEM_OFF];
+ if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
+ res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV;
+ else
+ res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL;
+
+ res->end = res->start + 3;
+ res->flags = IORESOURCE_MEM;
+
+ pdev = platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
+ tco_res, 3, &tco_platform_data,
+ sizeof(tco_platform_data));
+ if (IS_ERR(pdev)) {
+ dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
+ return;
+ }
+
+ priv->tco_pdev = pdev;
+}
+
+#ifdef CONFIG_ACPI
+static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
+ acpi_physical_address address)
+{
+ return address >= priv->smba &&
+ address <= pci_resource_end(priv->pci_dev, SMBBAR);
+}
+
+static acpi_status
+i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
+ u64 *value, void *handler_context, void *region_context)
+{
+ struct i801_priv *priv = handler_context;
+ struct pci_dev *pdev = priv->pci_dev;
+ acpi_status status;
+
+ /*
+ * Once BIOS AML code touches the OpRegion we warn and inhibit any
+ * further access from the driver itself. This device is now owned
+ * by the system firmware.
+ */
+ mutex_lock(&priv->acpi_lock);
+
+ if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
+ priv->acpi_reserved = true;
+
+ dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
+ dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
+
+ /*
+ * BIOS is accessing the host controller so prevent it from
+ * suspending automatically from now on.
+ */
+ pm_runtime_get_sync(&pdev->dev);
+ }
+
+ if ((function & ACPI_IO_MASK) == ACPI_READ)
+ status = acpi_os_read_port(address, (u32 *)value, bits);
+ else
+ status = acpi_os_write_port(address, (u32)*value, bits);
+
+ mutex_unlock(&priv->acpi_lock);
+
+ return status;
+}
+
+static int i801_acpi_probe(struct i801_priv *priv)
+{
+ struct acpi_device *adev;
+ acpi_status status;
+
+ adev = ACPI_COMPANION(&priv->pci_dev->dev);
+ if (adev) {
+ status = acpi_install_address_space_handler(adev->handle,
+ ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler,
+ NULL, priv);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ }
+
+ return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]);
+}
+
+static void i801_acpi_remove(struct i801_priv *priv)
+{
+ struct acpi_device *adev;
+
+ adev = ACPI_COMPANION(&priv->pci_dev->dev);
+ if (!adev)
+ return;
+
+ acpi_remove_address_space_handler(adev->handle,
+ ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
+
+ mutex_lock(&priv->acpi_lock);
+ if (priv->acpi_reserved)
+ pm_runtime_put(&priv->pci_dev->dev);
+ mutex_unlock(&priv->acpi_lock);
+}
+#else
+static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
+static inline void i801_acpi_remove(struct i801_priv *priv) { }
+#endif
+
+static unsigned char i801_setup_hstcfg(struct i801_priv *priv)
+{
+ unsigned char hstcfg = priv->original_hstcfg;
+
+ hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
+ hstcfg |= SMBHSTCFG_HST_EN;
+ pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
+ return hstcfg;
+}
+
+static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned char temp;
+ int err, i;
+ struct i801_priv *priv;
+
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_adapdata(&priv->adapter, priv);
+ priv->adapter.owner = THIS_MODULE;
+ priv->adapter.class = i801_get_adapter_class(priv);
+ priv->adapter.algo = &smbus_algorithm;
+ priv->adapter.dev.parent = &dev->dev;
+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
+ priv->adapter.retries = 3;
+ mutex_init(&priv->acpi_lock);
+
+ priv->pci_dev = dev;
+ switch (dev->device) {
+ case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
+ case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
+ case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS:
+ case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS:
+ case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS:
+ case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
+ case PCI_DEVICE_ID_INTEL_CDF_SMBUS:
+ case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
+ case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
+ case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
+ case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
+ priv->features |= FEATURE_I2C_BLOCK_READ;
+ priv->features |= FEATURE_IRQ;
+ priv->features |= FEATURE_SMBUS_PEC;
+ priv->features |= FEATURE_BLOCK_BUFFER;
+ /* If we have ACPI based watchdog use that instead */
+ if (!acpi_has_watchdog())
+ priv->features |= FEATURE_TCO;
+ priv->features |= FEATURE_HOST_NOTIFY;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2:
+ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0:
+ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1:
+ case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2:
+ priv->features |= FEATURE_IDF;
+ /* fall through */
+ default:
+ priv->features |= FEATURE_I2C_BLOCK_READ;
+ priv->features |= FEATURE_IRQ;
+ /* fall through */
+ case PCI_DEVICE_ID_INTEL_82801DB_3:
+ priv->features |= FEATURE_SMBUS_PEC;
+ priv->features |= FEATURE_BLOCK_BUFFER;
+ /* fall through */
+ case PCI_DEVICE_ID_INTEL_82801CA_3:
+ priv->features |= FEATURE_HOST_NOTIFY;
+ /* fall through */
+ case PCI_DEVICE_ID_INTEL_82801BA_2:
+ case PCI_DEVICE_ID_INTEL_82801AB_3:
+ case PCI_DEVICE_ID_INTEL_82801AA_3:
+ break;
+ }
+
+ /* Disable features on user request */
+ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
+ if (priv->features & disable_features & (1 << i))
+ dev_notice(&dev->dev, "%s disabled by user\n",
+ i801_feature_names[i]);
+ }
+ priv->features &= ~disable_features;
+
+ err = pcim_enable_device(dev);
+ if (err) {
+ dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
+ err);
+ return err;
+ }
+ pcim_pin_device(dev);
+
+ /* Determine the address of the SMBus area */
+ priv->smba = pci_resource_start(dev, SMBBAR);
+ if (!priv->smba) {
+ dev_err(&dev->dev,
+ "SMBus base address uninitialized, upgrade BIOS\n");
+ return -ENODEV;
+ }
+
+ if (i801_acpi_probe(priv))
+ return -ENODEV;
+
+ err = pcim_iomap_regions(dev, 1 << SMBBAR,
+ dev_driver_string(&dev->dev));
+ if (err) {
+ dev_err(&dev->dev,
+ "Failed to request SMBus region 0x%lx-0x%Lx\n",
+ priv->smba,
+ (unsigned long long)pci_resource_end(dev, SMBBAR));
+ i801_acpi_remove(priv);
+ return err;
+ }
+
+ pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
+ temp = i801_setup_hstcfg(priv);
+ if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
+ dev_info(&dev->dev, "Enabling SMBus device\n");
+
+ if (temp & SMBHSTCFG_SMB_SMI_EN) {
+ dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
+ /* Disable SMBus interrupt feature if SMBus using SMI# */
+ priv->features &= ~FEATURE_IRQ;
+ }
+ if (temp & SMBHSTCFG_SPD_WD)
+ dev_info(&dev->dev, "SPD Write Disable is set\n");
+
+ /* Clear special mode bits */
+ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+ outb_p(inb_p(SMBAUXCTL(priv)) &
+ ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+
+ /* Remember original Host Notify setting */
+ if (priv->features & FEATURE_HOST_NOTIFY)
+ priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
+
+ /* Default timeout in interrupt mode: 200 ms */
+ priv->adapter.timeout = HZ / 5;
+
+ if (dev->irq == IRQ_NOTCONNECTED)
+ priv->features &= ~FEATURE_IRQ;
+
+ if (priv->features & FEATURE_IRQ) {
+ u16 pcictl, pcists;
+
+ /* Complain if an interrupt is already pending */
+ pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
+ if (pcists & SMBPCISTS_INTS)
+ dev_warn(&dev->dev, "An interrupt is pending!\n");
+
+ /* Check if interrupts have been disabled */
+ pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl);
+ if (pcictl & SMBPCICTL_INTDIS) {
+ dev_info(&dev->dev, "Interrupts are disabled\n");
+ priv->features &= ~FEATURE_IRQ;
+ }
+ }
+
+ if (priv->features & FEATURE_IRQ) {
+ init_waitqueue_head(&priv->waitq);
+
+ err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
+ IRQF_SHARED,
+ dev_driver_string(&dev->dev), priv);
+ if (err) {
+ dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
+ dev->irq, err);
+ priv->features &= ~FEATURE_IRQ;
+ }
+ }
+ dev_info(&dev->dev, "SMBus using %s\n",
+ priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
+
+ i801_add_tco(priv);
+
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+ "SMBus I801 adapter at %04lx", priv->smba);
+ err = i2c_add_adapter(&priv->adapter);
+ if (err) {
+ i801_acpi_remove(priv);
+ return err;
+ }
+
+ i801_enable_host_notify(&priv->adapter);
+
+ i801_probe_optional_slaves(priv);
+ /* We ignore errors - multiplexing is optional */
+ i801_add_mux(priv);
+
+ pci_set_drvdata(dev, priv);
+
+ dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NEVER_SKIP);
+ pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
+ pm_runtime_use_autosuspend(&dev->dev);
+ pm_runtime_put_autosuspend(&dev->dev);
+ pm_runtime_allow(&dev->dev);
+
+ return 0;
+}
+
+static void i801_remove(struct pci_dev *dev)
+{
+ struct i801_priv *priv = pci_get_drvdata(dev);
+
+ pm_runtime_forbid(&dev->dev);
+ pm_runtime_get_noresume(&dev->dev);
+
+ i801_disable_host_notify(priv);
+ i801_del_mux(priv);
+ i2c_del_adapter(&priv->adapter);
+ i801_acpi_remove(priv);
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+
+ platform_device_unregister(priv->tco_pdev);
+
+ /*
+ * do not call pci_disable_device(dev) since it can cause hard hangs on
+ * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+ */
+}
+
+static void i801_shutdown(struct pci_dev *dev)
+{
+ struct i801_priv *priv = pci_get_drvdata(dev);
+
+ /* Restore config registers to avoid hard hang on some systems */
+ i801_disable_host_notify(priv);
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int i801_suspend(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct i801_priv *priv = pci_get_drvdata(pci_dev);
+
+ pci_write_config_byte(pci_dev, SMBHSTCFG, priv->original_hstcfg);
+ return 0;
+}
+
+static int i801_resume(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct i801_priv *priv = pci_get_drvdata(pci_dev);
+
+ i801_setup_hstcfg(priv);
+ i801_enable_host_notify(&priv->adapter);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume);
+
+static struct pci_driver i801_driver = {
+ .name = "i801_smbus",
+ .id_table = i801_ids,
+ .probe = i801_probe,
+ .remove = i801_remove,
+ .shutdown = i801_shutdown,
+ .driver = {
+ .pm = &i801_pm_ops,
+ },
+};
+
+static int __init i2c_i801_init(void)
+{
+ if (dmi_name_in_vendors("FUJITSU"))
+ input_apanel_init();
+ return pci_register_driver(&i801_driver);
+}
+
+static void __exit i2c_i801_exit(void)
+{
+ pci_unregister_driver(&i801_driver);
+}
+
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("I801 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_i801_init);
+module_exit(i2c_i801_exit);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
new file mode 100644
index 000000000..6f6e1dfe7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -0,0 +1,809 @@
+/*
+ * drivers/i2c/busses/i2c-ibm_iic.c
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003, 2004 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Copyright (c) 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * Based on original work by
+ * Ian DaSilva <idasilva@mvista.com>
+ * Armin Kuster <akuster@mvista.com>
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * Original driver version was highly leveraged from i2c-elektor.c
+ *
+ * Copyright 1995-97 Simon G. Vogl
+ * 1998-99 Hans Berglund
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
+ * and even Frodo Looijaard <frodol@dds.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sched/signal.h>
+
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include "i2c-ibm_iic.h"
+
+#define DRIVER_VERSION "2.2"
+
+MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static bool iic_force_poll;
+module_param(iic_force_poll, bool, 0);
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+
+static bool iic_force_fast;
+module_param(iic_force_fast, bool, 0);
+MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)");
+
+#define DBG_LEVEL 0
+
+#ifdef DBG
+#undef DBG
+#endif
+
+#ifdef DBG2
+#undef DBG2
+#endif
+
+#if DBG_LEVEL > 0
+# define DBG(f,x...) printk(KERN_DEBUG "ibm-iic" f, ##x)
+#else
+# define DBG(f,x...) ((void)0)
+#endif
+#if DBG_LEVEL > 1
+# define DBG2(f,x...) DBG(f, ##x)
+#else
+# define DBG2(f,x...) ((void)0)
+#endif
+#if DBG_LEVEL > 2
+static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header);
+ printk(KERN_DEBUG
+ " cntl = 0x%02x, mdcntl = 0x%02x\n"
+ " sts = 0x%02x, extsts = 0x%02x\n"
+ " clkdiv = 0x%02x, xfrcnt = 0x%02x\n"
+ " xtcntlss = 0x%02x, directcntl = 0x%02x\n",
+ in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
+ in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
+ in_8(&iic->xtcntlss), in_8(&iic->directcntl));
+}
+# define DUMP_REGS(h,dev) dump_iic_regs((h),(dev))
+#else
+# define DUMP_REGS(h,dev) ((void)0)
+#endif
+
+/* Bus timings (in ns) for bit-banging */
+static struct ibm_iic_timings {
+ unsigned int hd_sta;
+ unsigned int su_sto;
+ unsigned int low;
+ unsigned int high;
+ unsigned int buf;
+} timings [] = {
+/* Standard mode (100 KHz) */
+{
+ .hd_sta = 4000,
+ .su_sto = 4000,
+ .low = 4700,
+ .high = 4000,
+ .buf = 4700,
+},
+/* Fast mode (400 KHz) */
+{
+ .hd_sta = 600,
+ .su_sto = 600,
+ .low = 1300,
+ .high = 600,
+ .buf = 1300,
+}};
+
+/* Enable/disable interrupt generation */
+static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
+{
+ out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
+}
+
+/*
+ * Initialize IIC interface.
+ */
+static void iic_dev_init(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+ DBG("%d: init\n", dev->idx);
+
+ /* Clear master address */
+ out_8(&iic->lmadr, 0);
+ out_8(&iic->hmadr, 0);
+
+ /* Clear slave address */
+ out_8(&iic->lsadr, 0);
+ out_8(&iic->hsadr, 0);
+
+ /* Clear status & extended status */
+ out_8(&iic->sts, STS_SCMP | STS_IRQA);
+ out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA
+ | EXTSTS_ICT | EXTSTS_XFRA);
+
+ /* Set clock divider */
+ out_8(&iic->clkdiv, dev->clckdiv);
+
+ /* Clear transfer count */
+ out_8(&iic->xfrcnt, 0);
+
+ /* Clear extended control and status */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC
+ | XTCNTLSS_SWS);
+
+ /* Clear control register */
+ out_8(&iic->cntl, 0);
+
+ /* Enable interrupts if possible */
+ iic_interrupt_mode(dev, dev->irq >= 0);
+
+ /* Set mode control */
+ out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS
+ | (dev->fast_mode ? MDCNTL_FSM : 0));
+
+ DUMP_REGS("iic_init", dev);
+}
+
+/*
+ * Reset IIC interface
+ */
+static void iic_dev_reset(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ int i;
+ u8 dc;
+
+ DBG("%d: soft reset\n", dev->idx);
+ DUMP_REGS("reset", dev);
+
+ /* Place chip in the reset state */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+ /* Check if bus is free */
+ dc = in_8(&iic->directcntl);
+ if (!DIRCTNL_FREE(dc)){
+ DBG("%d: trying to regain bus control\n", dev->idx);
+
+ /* Try to set bus free state */
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+ /* Wait until we regain bus control */
+ for (i = 0; i < 100; ++i){
+ dc = in_8(&iic->directcntl);
+ if (DIRCTNL_FREE(dc))
+ break;
+
+ /* Toggle SCL line */
+ dc ^= DIRCNTL_SCC;
+ out_8(&iic->directcntl, dc);
+ udelay(10);
+ dc ^= DIRCNTL_SCC;
+ out_8(&iic->directcntl, dc);
+
+ /* be nice */
+ cond_resched();
+ }
+ }
+
+ /* Remove reset */
+ out_8(&iic->xtcntlss, 0);
+
+ /* Reinitialize interface */
+ iic_dev_init(dev);
+}
+
+/*
+ * Do 0-length transaction using bit-banging through IIC_DIRECTCNTL register.
+ */
+
+/* Wait for SCL and/or SDA to be high */
+static int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask)
+{
+ unsigned long x = jiffies + HZ / 28 + 2;
+ while ((in_8(&iic->directcntl) & mask) != mask){
+ if (unlikely(time_after(jiffies, x)))
+ return -1;
+ cond_resched();
+ }
+ return 0;
+}
+
+static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ const struct ibm_iic_timings *t = &timings[dev->fast_mode ? 1 : 0];
+ u8 mask, v, sda;
+ int i, res;
+
+ /* Only 7-bit addresses are supported */
+ if (unlikely(p->flags & I2C_M_TEN)){
+ DBG("%d: smbus_quick - 10 bit addresses are not supported\n",
+ dev->idx);
+ return -EINVAL;
+ }
+
+ DBG("%d: smbus_quick(0x%02x)\n", dev->idx, p->addr);
+
+ /* Reset IIC interface */
+ out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+ /* Wait for bus to become free */
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSDA | DIRCNTL_MSC)))
+ goto err;
+ ndelay(t->buf);
+
+ /* START */
+ out_8(&iic->directcntl, DIRCNTL_SCC);
+ sda = 0;
+ ndelay(t->hd_sta);
+
+ /* Send address */
+ v = i2c_8bit_addr_from_msg(p);
+ for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
+ out_8(&iic->directcntl, sda);
+ ndelay(t->low / 2);
+ sda = (v & mask) ? DIRCNTL_SDAC : 0;
+ out_8(&iic->directcntl, sda);
+ ndelay(t->low / 2);
+
+ out_8(&iic->directcntl, DIRCNTL_SCC | sda);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+ goto err;
+ ndelay(t->high);
+ }
+
+ /* ACK */
+ out_8(&iic->directcntl, sda);
+ ndelay(t->low / 2);
+ out_8(&iic->directcntl, DIRCNTL_SDAC);
+ ndelay(t->low / 2);
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+ goto err;
+ res = (in_8(&iic->directcntl) & DIRCNTL_MSDA) ? -EREMOTEIO : 1;
+ ndelay(t->high);
+
+ /* STOP */
+ out_8(&iic->directcntl, 0);
+ ndelay(t->low);
+ out_8(&iic->directcntl, DIRCNTL_SCC);
+ if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+ goto err;
+ ndelay(t->su_sto);
+ out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+ ndelay(t->buf);
+
+ DBG("%d: smbus_quick -> %s\n", dev->idx, res ? "NACK" : "ACK");
+out:
+ /* Remove reset */
+ out_8(&iic->xtcntlss, 0);
+
+ /* Reinitialize interface */
+ iic_dev_init(dev);
+
+ return res;
+err:
+ DBG("%d: smbus_quick - bus is stuck\n", dev->idx);
+ res = -EREMOTEIO;
+ goto out;
+}
+
+/*
+ * IIC interrupt handler
+ */
+static irqreturn_t iic_handler(int irq, void *dev_id)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+ DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
+ dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
+
+ /* Acknowledge IRQ and wakeup iic_wait_for_tc */
+ out_8(&iic->sts, STS_IRQA | STS_SCMP);
+ wake_up_interruptible(&dev->wq);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Get master transfer result and clear errors if any.
+ * Returns the number of actually transferred bytes or error (<0)
+ */
+static int iic_xfer_result(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+ if (unlikely(in_8(&iic->sts) & STS_ERR)){
+ DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
+ in_8(&iic->extsts));
+
+ /* Clear errors and possible pending IRQs */
+ out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
+ EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
+
+ /* Flush master data buffer */
+ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+
+ /* Is bus free?
+ * If error happened during combined xfer
+ * IIC interface is usually stuck in some strange
+ * state, the only way out - soft reset.
+ */
+ if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ DBG("%d: bus is stuck, resetting\n", dev->idx);
+ iic_dev_reset(dev);
+ }
+ return -EREMOTEIO;
+ }
+ else
+ return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
+}
+
+/*
+ * Try to abort active transfer.
+ */
+static void iic_abort_xfer(struct ibm_iic_private* dev)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ unsigned long x;
+
+ DBG("%d: iic_abort_xfer\n", dev->idx);
+
+ out_8(&iic->cntl, CNTL_HMT);
+
+ /*
+ * Wait for the abort command to complete.
+ * It's not worth to be optimized, just poll (timeout >= 1 tick)
+ */
+ x = jiffies + 2;
+ while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ if (time_after(jiffies, x)){
+ DBG("%d: abort timeout, resetting...\n", dev->idx);
+ iic_dev_reset(dev);
+ return;
+ }
+ schedule();
+ }
+
+ /* Just to clear errors */
+ iic_xfer_result(dev);
+}
+
+/*
+ * Wait for master transfer to complete.
+ * It puts current process to sleep until we get interrupt or timeout expires.
+ * Returns the number of transferred bytes or error (<0)
+ */
+static int iic_wait_for_tc(struct ibm_iic_private* dev){
+
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ int ret = 0;
+
+ if (dev->irq >= 0){
+ /* Interrupt mode */
+ ret = wait_event_interruptible_timeout(dev->wq,
+ !(in_8(&iic->sts) & STS_PT), dev->adap.timeout);
+
+ if (unlikely(ret < 0))
+ DBG("%d: wait interrupted\n", dev->idx);
+ else if (unlikely(in_8(&iic->sts) & STS_PT)){
+ DBG("%d: wait timeout\n", dev->idx);
+ ret = -ETIMEDOUT;
+ }
+ }
+ else {
+ /* Polling mode */
+ unsigned long x = jiffies + dev->adap.timeout;
+
+ while (in_8(&iic->sts) & STS_PT){
+ if (unlikely(time_after(jiffies, x))){
+ DBG("%d: poll timeout\n", dev->idx);
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ if (unlikely(signal_pending(current))){
+ DBG("%d: poll interrupted\n", dev->idx);
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ }
+
+ if (unlikely(ret < 0))
+ iic_abort_xfer(dev);
+ else
+ ret = iic_xfer_result(dev);
+
+ DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
+
+ return ret;
+}
+
+/*
+ * Low level master transfer routine
+ */
+static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
+ int combined_xfer)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ char* buf = pm->buf;
+ int i, j, loops, ret = 0;
+ int len = pm->len;
+
+ u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
+ if (pm->flags & I2C_M_RD)
+ cntl |= CNTL_RW;
+
+ loops = (len + 3) / 4;
+ for (i = 0; i < loops; ++i, len -= 4){
+ int count = len > 4 ? 4 : len;
+ u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
+
+ if (!(cntl & CNTL_RW))
+ for (j = 0; j < count; ++j)
+ out_8((void __iomem *)&iic->mdbuf, *buf++);
+
+ if (i < loops - 1)
+ cmd |= CNTL_CHT;
+ else if (combined_xfer)
+ cmd |= CNTL_RPST;
+
+ DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
+
+ /* Start transfer */
+ out_8(&iic->cntl, cmd);
+
+ /* Wait for completion */
+ ret = iic_wait_for_tc(dev);
+
+ if (unlikely(ret < 0))
+ break;
+ else if (unlikely(ret != count)){
+ DBG("%d: xfer_bytes, requested %d, transferred %d\n",
+ dev->idx, count, ret);
+
+ /* If it's not a last part of xfer, abort it */
+ if (combined_xfer || (i < loops - 1))
+ iic_abort_xfer(dev);
+
+ ret = -EREMOTEIO;
+ break;
+ }
+
+ if (cntl & CNTL_RW)
+ for (j = 0; j < count; ++j)
+ *buf++ = in_8((void __iomem *)&iic->mdbuf);
+ }
+
+ return ret > 0 ? 0 : ret;
+}
+
+/*
+ * Set target slave address for master transfer
+ */
+static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
+{
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ u16 addr = msg->addr;
+
+ DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
+ addr, msg->flags & I2C_M_TEN ? 10 : 7);
+
+ if (msg->flags & I2C_M_TEN){
+ out_8(&iic->cntl, CNTL_AMD);
+ out_8(&iic->lmadr, addr);
+ out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
+ }
+ else {
+ out_8(&iic->cntl, 0);
+ out_8(&iic->lmadr, addr << 1);
+ }
+}
+
+static inline int iic_invalid_address(const struct i2c_msg* p)
+{
+ return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
+}
+
+static inline int iic_address_neq(const struct i2c_msg* p1,
+ const struct i2c_msg* p2)
+{
+ return (p1->addr != p2->addr)
+ || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
+}
+
+/*
+ * Generic master transfer entrypoint.
+ * Returns the number of processed messages or error (<0)
+ */
+static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
+ volatile struct iic_regs __iomem *iic = dev->vaddr;
+ int i, ret = 0;
+
+ DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
+
+ /* Check the sanity of the passed messages.
+ * Uhh, generic i2c layer is more suitable place for such code...
+ */
+ if (unlikely(iic_invalid_address(&msgs[0]))){
+ DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
+ msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
+ return -EINVAL;
+ }
+ for (i = 0; i < num; ++i){
+ if (unlikely(msgs[i].len <= 0)){
+ if (num == 1 && !msgs[0].len){
+ /* Special case for I2C_SMBUS_QUICK emulation.
+ * IBM IIC doesn't support 0-length transactions
+ * so we have to emulate them using bit-banging.
+ */
+ return iic_smbus_quick(dev, &msgs[0]);
+ }
+ DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
+ msgs[i].len, i);
+ return -EINVAL;
+ }
+ if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){
+ DBG("%d: invalid addr in msg[%d]\n", dev->idx, i);
+ return -EINVAL;
+ }
+ }
+
+ /* Check bus state */
+ if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
+ DBG("%d: iic_xfer, bus is not free\n", dev->idx);
+
+ /* Usually it means something serious has happened.
+ * We *cannot* have unfinished previous transfer
+ * so it doesn't make any sense to try to stop it.
+ * Probably we were not able to recover from the
+ * previous error.
+ * The only *reasonable* thing I can think of here
+ * is soft reset. --ebs
+ */
+ iic_dev_reset(dev);
+
+ if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+ DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
+ return -EREMOTEIO;
+ }
+ }
+ else {
+ /* Flush master data buffer (just in case) */
+ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+ }
+
+ /* Load slave address */
+ iic_address(dev, &msgs[0]);
+
+ /* Do real transfer */
+ for (i = 0; i < num && !ret; ++i)
+ ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
+
+ return ret < 0 ? ret : num;
+}
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm iic_algo = {
+ .master_xfer = iic_xfer,
+ .functionality = iic_func
+};
+
+/*
+ * Calculates IICx_CLCKDIV value for a specific OPB clock frequency
+ */
+static inline u8 iic_clckdiv(unsigned int opb)
+{
+ /* Compatibility kludge, should go away after all cards
+ * are fixed to fill correct value for opbfreq.
+ * Previous driver version used hardcoded divider value 4,
+ * it corresponds to OPB frequency from the range (40, 50] MHz
+ */
+ if (!opb){
+ printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq,"
+ " fix your board specific setup\n");
+ opb = 50000000;
+ }
+
+ /* Convert to MHz */
+ opb /= 1000000;
+
+ if (opb < 20 || opb > 150){
+ printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n",
+ opb);
+ opb = opb < 20 ? 20 : 150;
+ }
+ return (u8)((opb + 9) / 10 - 1);
+}
+
+static int iic_request_irq(struct platform_device *ofdev,
+ struct ibm_iic_private *dev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ int irq;
+
+ if (iic_force_poll)
+ return 0;
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
+ return 0;
+ }
+
+ /* Disable interrupts until we finish initialization, assumes
+ * level-sensitive IRQ setup...
+ */
+ iic_interrupt_mode(dev, 0);
+ if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
+ dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
+ /* Fallback to the polling mode */
+ return 0;
+ }
+
+ return irq;
+}
+
+/*
+ * Register single IIC interface
+ */
+static int iic_probe(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ struct ibm_iic_private *dev;
+ struct i2c_adapter *adap;
+ const u32 *freq;
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&ofdev->dev, "failed to allocate device data\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(ofdev, dev);
+
+ dev->vaddr = of_iomap(np, 0);
+ if (dev->vaddr == NULL) {
+ dev_err(&ofdev->dev, "failed to iomap device\n");
+ ret = -ENXIO;
+ goto error_cleanup;
+ }
+
+ init_waitqueue_head(&dev->wq);
+
+ dev->irq = iic_request_irq(ofdev, dev);
+ if (!dev->irq)
+ dev_warn(&ofdev->dev, "using polling mode\n");
+
+ /* Board specific settings */
+ if (iic_force_fast || of_get_property(np, "fast-mode", NULL))
+ dev->fast_mode = 1;
+
+ freq = of_get_property(np, "clock-frequency", NULL);
+ if (freq == NULL) {
+ freq = of_get_property(np->parent, "clock-frequency", NULL);
+ if (freq == NULL) {
+ dev_err(&ofdev->dev, "Unable to get bus frequency\n");
+ ret = -EINVAL;
+ goto error_cleanup;
+ }
+ }
+
+ dev->clckdiv = iic_clckdiv(*freq);
+ dev_dbg(&ofdev->dev, "clckdiv = %d\n", dev->clckdiv);
+
+ /* Initialize IIC interface */
+ iic_dev_init(dev);
+
+ /* Register it with i2c layer */
+ adap = &dev->adap;
+ adap->dev.parent = &ofdev->dev;
+ adap->dev.of_node = of_node_get(np);
+ strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
+ i2c_set_adapdata(adap, dev);
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = &iic_algo;
+ adap->timeout = HZ;
+
+ ret = i2c_add_adapter(adap);
+ if (ret < 0)
+ goto error_cleanup;
+
+ dev_info(&ofdev->dev, "using %s mode\n",
+ dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
+
+ return 0;
+
+error_cleanup:
+ if (dev->irq) {
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ }
+
+ if (dev->vaddr)
+ iounmap(dev->vaddr);
+
+ kfree(dev);
+ return ret;
+}
+
+/*
+ * Cleanup initialized IIC interface
+ */
+static int iic_remove(struct platform_device *ofdev)
+{
+ struct ibm_iic_private *dev = platform_get_drvdata(ofdev);
+
+ i2c_del_adapter(&dev->adap);
+
+ if (dev->irq) {
+ iic_interrupt_mode(dev, 0);
+ free_irq(dev->irq, dev);
+ }
+
+ iounmap(dev->vaddr);
+ kfree(dev);
+
+ return 0;
+}
+
+static const struct of_device_id ibm_iic_match[] = {
+ { .compatible = "ibm,iic", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ibm_iic_match);
+
+static struct platform_driver ibm_iic_driver = {
+ .driver = {
+ .name = "ibm-iic",
+ .of_match_table = ibm_iic_match,
+ },
+ .probe = iic_probe,
+ .remove = iic_remove,
+};
+
+module_platform_driver(ibm_iic_driver);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
new file mode 100644
index 000000000..fdaa48292
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -0,0 +1,123 @@
+/*
+ * drivers/i2c/busses/i2c-ibm_iic.h
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Ian DaSilva <idasilva@mvista.com>
+ * Armin Kuster <akuster@mvista.com>
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __I2C_IBM_IIC_H_
+#define __I2C_IBM_IIC_H_
+
+#include <linux/i2c.h>
+
+struct iic_regs {
+ u16 mdbuf;
+ u16 sbbuf;
+ u8 lmadr;
+ u8 hmadr;
+ u8 cntl;
+ u8 mdcntl;
+ u8 sts;
+ u8 extsts;
+ u8 lsadr;
+ u8 hsadr;
+ u8 clkdiv;
+ u8 intmsk;
+ u8 xfrcnt;
+ u8 xtcntlss;
+ u8 directcntl;
+};
+
+struct ibm_iic_private {
+ struct i2c_adapter adap;
+ volatile struct iic_regs __iomem *vaddr;
+ wait_queue_head_t wq;
+ int idx;
+ int irq;
+ int fast_mode;
+ u8 clckdiv;
+};
+
+/* IICx_CNTL register */
+#define CNTL_HMT 0x80
+#define CNTL_AMD 0x40
+#define CNTL_TCT_MASK 0x30
+#define CNTL_TCT_SHIFT 4
+#define CNTL_RPST 0x08
+#define CNTL_CHT 0x04
+#define CNTL_RW 0x02
+#define CNTL_PT 0x01
+
+/* IICx_MDCNTL register */
+#define MDCNTL_FSDB 0x80
+#define MDCNTL_FMDB 0x40
+#define MDCNTL_EGC 0x20
+#define MDCNTL_FSM 0x10
+#define MDCNTL_ESM 0x08
+#define MDCNTL_EINT 0x04
+#define MDCNTL_EUBS 0x02
+#define MDCNTL_HSCL 0x01
+
+/* IICx_STS register */
+#define STS_SSS 0x80
+#define STS_SLPR 0x40
+#define STS_MDBS 0x20
+#define STS_MDBF 0x10
+#define STS_SCMP 0x08
+#define STS_ERR 0x04
+#define STS_IRQA 0x02
+#define STS_PT 0x01
+
+/* IICx_EXTSTS register */
+#define EXTSTS_IRQP 0x80
+#define EXTSTS_BCS_MASK 0x70
+#define EXTSTS_BCS_FREE 0x40
+#define EXTSTS_IRQD 0x08
+#define EXTSTS_LA 0x04
+#define EXTSTS_ICT 0x02
+#define EXTSTS_XFRA 0x01
+
+/* IICx_INTRMSK register */
+#define INTRMSK_EIRC 0x80
+#define INTRMSK_EIRS 0x40
+#define INTRMSK_EIWC 0x20
+#define INTRMSK_EIWS 0x10
+#define INTRMSK_EIHE 0x08
+#define INTRMSK_EIIC 0x04
+#define INTRMSK_EITA 0x02
+#define INTRMSK_EIMTC 0x01
+
+/* IICx_XFRCNT register */
+#define XFRCNT_MTC_MASK 0x07
+
+/* IICx_XTCNTLSS register */
+#define XTCNTLSS_SRC 0x80
+#define XTCNTLSS_SRS 0x40
+#define XTCNTLSS_SWC 0x20
+#define XTCNTLSS_SWS 0x10
+#define XTCNTLSS_SRST 0x01
+
+/* IICx_DIRECTCNTL register */
+#define DIRCNTL_SDAC 0x08
+#define DIRCNTL_SCC 0x04
+#define DIRCNTL_MSDA 0x02
+#define DIRCNTL_MSC 0x01
+
+/* Check if we really control the I2C bus and bus is free */
+#define DIRCTNL_FREE(v) (((v) & 0x0f) == 0x0f)
+
+#endif /* __I2C_IBM_IIC_H_ */
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
new file mode 100644
index 000000000..f038858b6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -0,0 +1,1522 @@
+/*
+ * I2C adapter for the IMG Serial Control Bus (SCB) IP block.
+ *
+ * Copyright (C) 2009, 2010, 2012, 2014 Imagination Technologies 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.
+ *
+ * There are three ways that this I2C controller can be driven:
+ *
+ * - Raw control of the SDA and SCK signals.
+ *
+ * This corresponds to MODE_RAW, which takes control of the signals
+ * directly for a certain number of clock cycles (the INT_TIMING
+ * interrupt can be used for timing).
+ *
+ * - Atomic commands. A low level I2C symbol (such as generate
+ * start/stop/ack/nack bit, generate byte, receive byte, and receive
+ * ACK) is given to the hardware, with detection of completion by bits
+ * in the LINESTAT register.
+ *
+ * This mode of operation is used by MODE_ATOMIC, which uses an I2C
+ * state machine in the interrupt handler to compose/react to I2C
+ * transactions using atomic mode commands, and also by MODE_SEQUENCE,
+ * which emits a simple fixed sequence of atomic mode commands.
+ *
+ * Due to software control, the use of atomic commands usually results
+ * in suboptimal use of the bus, with gaps between the I2C symbols while
+ * the driver decides what to do next.
+ *
+ * - Automatic mode. A bus address, and whether to read/write is
+ * specified, and the hardware takes care of the I2C state machine,
+ * using a FIFO to send/receive bytes of data to an I2C slave. The
+ * driver just has to keep the FIFO drained or filled in response to the
+ * appropriate FIFO interrupts.
+ *
+ * This corresponds to MODE_AUTOMATIC, which manages the FIFOs and deals
+ * with control of repeated start bits between I2C messages.
+ *
+ * Use of automatic mode and the FIFO can make much more efficient use
+ * of the bus compared to individual atomic commands, with potentially
+ * no wasted time between I2C symbols or I2C messages.
+ *
+ * In most cases MODE_AUTOMATIC is used, however if any of the messages in
+ * a transaction are zero byte writes (e.g. used by i2cdetect for probing
+ * the bus), MODE_ATOMIC must be used since automatic mode is normally
+ * started by the writing of data into the FIFO.
+ *
+ * The other modes are used in specific circumstances where MODE_ATOMIC and
+ * MODE_AUTOMATIC aren't appropriate. MODE_RAW is used to implement a bus
+ * recovery routine. MODE_SEQUENCE is used to reset the bus and make sure
+ * it is in a sane state.
+ *
+ * Notice that the driver implements a timer-based timeout mechanism.
+ * The reason for this mechanism is to reduce the number of interrupts
+ * received in automatic mode.
+ *
+ * The driver would get a slave event and transaction done interrupts for
+ * each atomic mode command that gets completed. However, these events are
+ * not needed in automatic mode, becase those atomic mode commands are
+ * managed automatically by the hardware.
+ *
+ * In practice, normal I2C transactions will be complete well before you
+ * get the timer interrupt, as the timer is re-scheduled during FIFO
+ * maintenance and disabled after the transaction is complete.
+ *
+ * In this way normal automatic mode operation isn't impacted by
+ * unnecessary interrupts, but the exceptional abort condition can still be
+ * detected (with a slight delay).
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+/* Register offsets */
+
+#define SCB_STATUS_REG 0x00
+#define SCB_OVERRIDE_REG 0x04
+#define SCB_READ_ADDR_REG 0x08
+#define SCB_READ_COUNT_REG 0x0c
+#define SCB_WRITE_ADDR_REG 0x10
+#define SCB_READ_DATA_REG 0x14
+#define SCB_WRITE_DATA_REG 0x18
+#define SCB_FIFO_STATUS_REG 0x1c
+#define SCB_CONTROL_SOFT_RESET 0x1f
+#define SCB_CLK_SET_REG 0x3c
+#define SCB_INT_STATUS_REG 0x40
+#define SCB_INT_CLEAR_REG 0x44
+#define SCB_INT_MASK_REG 0x48
+#define SCB_CONTROL_REG 0x4c
+#define SCB_TIME_TPL_REG 0x50
+#define SCB_TIME_TPH_REG 0x54
+#define SCB_TIME_TP2S_REG 0x58
+#define SCB_TIME_TBI_REG 0x60
+#define SCB_TIME_TSL_REG 0x64
+#define SCB_TIME_TDL_REG 0x68
+#define SCB_TIME_TSDL_REG 0x6c
+#define SCB_TIME_TSDH_REG 0x70
+#define SCB_READ_XADDR_REG 0x74
+#define SCB_WRITE_XADDR_REG 0x78
+#define SCB_WRITE_COUNT_REG 0x7c
+#define SCB_CORE_REV_REG 0x80
+#define SCB_TIME_TCKH_REG 0x84
+#define SCB_TIME_TCKL_REG 0x88
+#define SCB_FIFO_FLUSH_REG 0x8c
+#define SCB_READ_FIFO_REG 0x94
+#define SCB_CLEAR_REG 0x98
+
+/* SCB_CONTROL_REG bits */
+
+#define SCB_CONTROL_CLK_ENABLE 0x1e0
+#define SCB_CONTROL_TRANSACTION_HALT 0x200
+
+#define FIFO_READ_FULL BIT(0)
+#define FIFO_READ_EMPTY BIT(1)
+#define FIFO_WRITE_FULL BIT(2)
+#define FIFO_WRITE_EMPTY BIT(3)
+
+/* SCB_CLK_SET_REG bits */
+#define SCB_FILT_DISABLE BIT(31)
+#define SCB_FILT_BYPASS BIT(30)
+#define SCB_FILT_INC_MASK 0x7f
+#define SCB_FILT_INC_SHIFT 16
+#define SCB_INC_MASK 0x7f
+#define SCB_INC_SHIFT 8
+
+/* SCB_INT_*_REG bits */
+
+#define INT_BUS_INACTIVE BIT(0)
+#define INT_UNEXPECTED_START BIT(1)
+#define INT_SCLK_LOW_TIMEOUT BIT(2)
+#define INT_SDAT_LOW_TIMEOUT BIT(3)
+#define INT_WRITE_ACK_ERR BIT(4)
+#define INT_ADDR_ACK_ERR BIT(5)
+#define INT_FIFO_FULL BIT(9)
+#define INT_FIFO_FILLING BIT(10)
+#define INT_FIFO_EMPTY BIT(11)
+#define INT_FIFO_EMPTYING BIT(12)
+#define INT_TRANSACTION_DONE BIT(15)
+#define INT_SLAVE_EVENT BIT(16)
+#define INT_MASTER_HALTED BIT(17)
+#define INT_TIMING BIT(18)
+#define INT_STOP_DETECTED BIT(19)
+
+#define INT_FIFO_FULL_FILLING (INT_FIFO_FULL | INT_FIFO_FILLING)
+
+/* Level interrupts need clearing after handling instead of before */
+#define INT_LEVEL 0x01e00
+
+/* Don't allow any interrupts while the clock may be off */
+#define INT_ENABLE_MASK_INACTIVE 0x00000
+
+/* Interrupt masks for the different driver modes */
+
+#define INT_ENABLE_MASK_RAW INT_TIMING
+
+#define INT_ENABLE_MASK_ATOMIC (INT_TRANSACTION_DONE | \
+ INT_SLAVE_EVENT | \
+ INT_ADDR_ACK_ERR | \
+ INT_WRITE_ACK_ERR)
+
+#define INT_ENABLE_MASK_AUTOMATIC (INT_SCLK_LOW_TIMEOUT | \
+ INT_ADDR_ACK_ERR | \
+ INT_WRITE_ACK_ERR | \
+ INT_FIFO_FULL | \
+ INT_FIFO_FILLING | \
+ INT_FIFO_EMPTY | \
+ INT_MASTER_HALTED | \
+ INT_STOP_DETECTED)
+
+#define INT_ENABLE_MASK_WAITSTOP (INT_SLAVE_EVENT | \
+ INT_ADDR_ACK_ERR | \
+ INT_WRITE_ACK_ERR)
+
+/* SCB_STATUS_REG fields */
+
+#define LINESTAT_SCLK_LINE_STATUS BIT(0)
+#define LINESTAT_SCLK_EN BIT(1)
+#define LINESTAT_SDAT_LINE_STATUS BIT(2)
+#define LINESTAT_SDAT_EN BIT(3)
+#define LINESTAT_DET_START_STATUS BIT(4)
+#define LINESTAT_DET_STOP_STATUS BIT(5)
+#define LINESTAT_DET_ACK_STATUS BIT(6)
+#define LINESTAT_DET_NACK_STATUS BIT(7)
+#define LINESTAT_BUS_IDLE BIT(8)
+#define LINESTAT_T_DONE_STATUS BIT(9)
+#define LINESTAT_SCLK_OUT_STATUS BIT(10)
+#define LINESTAT_SDAT_OUT_STATUS BIT(11)
+#define LINESTAT_GEN_LINE_MASK_STATUS BIT(12)
+#define LINESTAT_START_BIT_DET BIT(13)
+#define LINESTAT_STOP_BIT_DET BIT(14)
+#define LINESTAT_ACK_DET BIT(15)
+#define LINESTAT_NACK_DET BIT(16)
+#define LINESTAT_INPUT_HELD_V BIT(17)
+#define LINESTAT_ABORT_DET BIT(18)
+#define LINESTAT_ACK_OR_NACK_DET (LINESTAT_ACK_DET | LINESTAT_NACK_DET)
+#define LINESTAT_INPUT_DATA 0xff000000
+#define LINESTAT_INPUT_DATA_SHIFT 24
+
+#define LINESTAT_CLEAR_SHIFT 13
+#define LINESTAT_LATCHED (0x3f << LINESTAT_CLEAR_SHIFT)
+
+/* SCB_OVERRIDE_REG fields */
+
+#define OVERRIDE_SCLK_OVR BIT(0)
+#define OVERRIDE_SCLKEN_OVR BIT(1)
+#define OVERRIDE_SDAT_OVR BIT(2)
+#define OVERRIDE_SDATEN_OVR BIT(3)
+#define OVERRIDE_MASTER BIT(9)
+#define OVERRIDE_LINE_OVR_EN BIT(10)
+#define OVERRIDE_DIRECT BIT(11)
+#define OVERRIDE_CMD_SHIFT 4
+#define OVERRIDE_CMD_MASK 0x1f
+#define OVERRIDE_DATA_SHIFT 24
+
+#define OVERRIDE_SCLK_DOWN (OVERRIDE_LINE_OVR_EN | \
+ OVERRIDE_SCLKEN_OVR)
+#define OVERRIDE_SCLK_UP (OVERRIDE_LINE_OVR_EN | \
+ OVERRIDE_SCLKEN_OVR | \
+ OVERRIDE_SCLK_OVR)
+#define OVERRIDE_SDAT_DOWN (OVERRIDE_LINE_OVR_EN | \
+ OVERRIDE_SDATEN_OVR)
+#define OVERRIDE_SDAT_UP (OVERRIDE_LINE_OVR_EN | \
+ OVERRIDE_SDATEN_OVR | \
+ OVERRIDE_SDAT_OVR)
+
+/* OVERRIDE_CMD values */
+
+#define CMD_PAUSE 0x00
+#define CMD_GEN_DATA 0x01
+#define CMD_GEN_START 0x02
+#define CMD_GEN_STOP 0x03
+#define CMD_GEN_ACK 0x04
+#define CMD_GEN_NACK 0x05
+#define CMD_RET_DATA 0x08
+#define CMD_RET_ACK 0x09
+
+/* Fixed timing values */
+
+#define TIMEOUT_TBI 0x0
+#define TIMEOUT_TSL 0xffff
+#define TIMEOUT_TDL 0x0
+
+/* Transaction timeout */
+
+#define IMG_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+/*
+ * Worst incs are 1 (innacurate) and 16*256 (irregular).
+ * So a sensible inc is the logarithmic mean: 64 (2^6), which is
+ * in the middle of the valid range (0-127).
+ */
+#define SCB_OPT_INC 64
+
+/* Setup the clock enable filtering for 25 ns */
+#define SCB_FILT_GLITCH 25
+
+/*
+ * Bits to return from interrupt handler functions for different modes.
+ * This delays completion until we've finished with the registers, so that the
+ * function waiting for completion can safely disable the clock to save power.
+ */
+#define ISR_COMPLETE_M BIT(31)
+#define ISR_FATAL_M BIT(30)
+#define ISR_WAITSTOP BIT(29)
+#define ISR_STATUS_M 0x0000ffff /* contains +ve errno */
+#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err)))
+#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M)
+
+#define IMG_I2C_PM_TIMEOUT 1000 /* ms */
+
+enum img_i2c_mode {
+ MODE_INACTIVE,
+ MODE_RAW,
+ MODE_ATOMIC,
+ MODE_AUTOMATIC,
+ MODE_SEQUENCE,
+ MODE_FATAL,
+ MODE_WAITSTOP,
+ MODE_SUSPEND,
+};
+
+/* Timing parameters for i2c modes (in ns) */
+struct img_i2c_timings {
+ const char *name;
+ unsigned int max_bitrate;
+ unsigned int tckh, tckl, tsdh, tsdl;
+ unsigned int tp2s, tpl, tph;
+};
+
+/* The timings array must be ordered from slower to faster */
+static struct img_i2c_timings timings[] = {
+ /* Standard mode */
+ {
+ .name = "standard",
+ .max_bitrate = 100000,
+ .tckh = 4000,
+ .tckl = 4700,
+ .tsdh = 4700,
+ .tsdl = 8700,
+ .tp2s = 4700,
+ .tpl = 4700,
+ .tph = 4000,
+ },
+ /* Fast mode */
+ {
+ .name = "fast",
+ .max_bitrate = 400000,
+ .tckh = 600,
+ .tckl = 1300,
+ .tsdh = 600,
+ .tsdl = 1200,
+ .tp2s = 1300,
+ .tpl = 600,
+ .tph = 600,
+ },
+};
+
+/* Reset dance */
+static u8 img_i2c_reset_seq[] = { CMD_GEN_START,
+ CMD_GEN_DATA, 0xff,
+ CMD_RET_ACK,
+ CMD_GEN_START,
+ CMD_GEN_STOP,
+ 0 };
+/* Just issue a stop (after an abort condition) */
+static u8 img_i2c_stop_seq[] = { CMD_GEN_STOP,
+ 0 };
+
+/* We're interested in different interrupts depending on the mode */
+static unsigned int img_i2c_int_enable_by_mode[] = {
+ [MODE_INACTIVE] = INT_ENABLE_MASK_INACTIVE,
+ [MODE_RAW] = INT_ENABLE_MASK_RAW,
+ [MODE_ATOMIC] = INT_ENABLE_MASK_ATOMIC,
+ [MODE_AUTOMATIC] = INT_ENABLE_MASK_AUTOMATIC,
+ [MODE_SEQUENCE] = INT_ENABLE_MASK_ATOMIC,
+ [MODE_FATAL] = 0,
+ [MODE_WAITSTOP] = INT_ENABLE_MASK_WAITSTOP,
+ [MODE_SUSPEND] = 0,
+};
+
+/* Atomic command names */
+static const char * const img_i2c_atomic_cmd_names[] = {
+ [CMD_PAUSE] = "PAUSE",
+ [CMD_GEN_DATA] = "GEN_DATA",
+ [CMD_GEN_START] = "GEN_START",
+ [CMD_GEN_STOP] = "GEN_STOP",
+ [CMD_GEN_ACK] = "GEN_ACK",
+ [CMD_GEN_NACK] = "GEN_NACK",
+ [CMD_RET_DATA] = "RET_DATA",
+ [CMD_RET_ACK] = "RET_ACK",
+};
+
+struct img_i2c {
+ struct i2c_adapter adap;
+
+ void __iomem *base;
+
+ /*
+ * The scb core clock is used to get the input frequency, and to disable
+ * it after every set of transactions to save some power.
+ */
+ struct clk *scb_clk, *sys_clk;
+ unsigned int bitrate;
+ bool need_wr_rd_fence;
+
+ /* state */
+ struct completion msg_complete;
+ spinlock_t lock; /* lock before doing anything with the state */
+ struct i2c_msg msg;
+
+ /* After the last transaction, wait for a stop bit */
+ bool last_msg;
+ int msg_status;
+
+ enum img_i2c_mode mode;
+ u32 int_enable; /* depends on mode */
+ u32 line_status; /* line status over command */
+
+ /*
+ * To avoid slave event interrupts in automatic mode, use a timer to
+ * poll the abort condition if we don't get an interrupt for too long.
+ */
+ struct timer_list check_timer;
+ bool t_halt;
+
+ /* atomic mode state */
+ bool at_t_done;
+ bool at_slave_event;
+ int at_cur_cmd;
+ u8 at_cur_data;
+
+ /* Sequence: either reset or stop. See img_i2c_sequence. */
+ u8 *seq;
+
+ /* raw mode */
+ unsigned int raw_timeout;
+};
+
+static int img_i2c_runtime_suspend(struct device *dev);
+static int img_i2c_runtime_resume(struct device *dev);
+
+static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value)
+{
+ writel(value, i2c->base + offset);
+}
+
+static u32 img_i2c_readl(struct img_i2c *i2c, u32 offset)
+{
+ return readl(i2c->base + offset);
+}
+
+/*
+ * The code to read from the master read fifo, and write to the master
+ * write fifo, checks a bit in an SCB register before every byte to
+ * ensure that the fifo is not full (write fifo) or empty (read fifo).
+ * Due to clock domain crossing inside the SCB block the updated value
+ * of this bit is only visible after 2 cycles.
+ *
+ * The scb_wr_rd_fence() function does 2 dummy writes (to the read-only
+ * revision register), and it's called after reading from or writing to the
+ * fifos to ensure that subsequent reads of the fifo status bits do not read
+ * stale values.
+ */
+static void img_i2c_wr_rd_fence(struct img_i2c *i2c)
+{
+ if (i2c->need_wr_rd_fence) {
+ img_i2c_writel(i2c, SCB_CORE_REV_REG, 0);
+ img_i2c_writel(i2c, SCB_CORE_REV_REG, 0);
+ }
+}
+
+static void img_i2c_switch_mode(struct img_i2c *i2c, enum img_i2c_mode mode)
+{
+ i2c->mode = mode;
+ i2c->int_enable = img_i2c_int_enable_by_mode[mode];
+ i2c->line_status = 0;
+}
+
+static void img_i2c_raw_op(struct img_i2c *i2c)
+{
+ i2c->raw_timeout = 0;
+ img_i2c_writel(i2c, SCB_OVERRIDE_REG,
+ OVERRIDE_SCLKEN_OVR |
+ OVERRIDE_SDATEN_OVR |
+ OVERRIDE_MASTER |
+ OVERRIDE_LINE_OVR_EN |
+ OVERRIDE_DIRECT |
+ ((i2c->at_cur_cmd & OVERRIDE_CMD_MASK) << OVERRIDE_CMD_SHIFT) |
+ (i2c->at_cur_data << OVERRIDE_DATA_SHIFT));
+}
+
+static const char *img_i2c_atomic_op_name(unsigned int cmd)
+{
+ if (unlikely(cmd >= ARRAY_SIZE(img_i2c_atomic_cmd_names)))
+ return "UNKNOWN";
+ return img_i2c_atomic_cmd_names[cmd];
+}
+
+/* Send a single atomic mode command to the hardware */
+static void img_i2c_atomic_op(struct img_i2c *i2c, int cmd, u8 data)
+{
+ i2c->at_cur_cmd = cmd;
+ i2c->at_cur_data = data;
+
+ /* work around lack of data setup time when generating data */
+ if (cmd == CMD_GEN_DATA && i2c->mode == MODE_ATOMIC) {
+ u32 line_status = img_i2c_readl(i2c, SCB_STATUS_REG);
+
+ if (line_status & LINESTAT_SDAT_LINE_STATUS && !(data & 0x80)) {
+ /* hold the data line down for a moment */
+ img_i2c_switch_mode(i2c, MODE_RAW);
+ img_i2c_raw_op(i2c);
+ return;
+ }
+ }
+
+ dev_dbg(i2c->adap.dev.parent,
+ "atomic cmd=%s (%d) data=%#x\n",
+ img_i2c_atomic_op_name(cmd), cmd, data);
+ i2c->at_t_done = (cmd == CMD_RET_DATA || cmd == CMD_RET_ACK);
+ i2c->at_slave_event = false;
+ i2c->line_status = 0;
+
+ img_i2c_writel(i2c, SCB_OVERRIDE_REG,
+ ((cmd & OVERRIDE_CMD_MASK) << OVERRIDE_CMD_SHIFT) |
+ OVERRIDE_MASTER |
+ OVERRIDE_DIRECT |
+ (data << OVERRIDE_DATA_SHIFT));
+}
+
+/* Start a transaction in atomic mode */
+static void img_i2c_atomic_start(struct img_i2c *i2c)
+{
+ img_i2c_switch_mode(i2c, MODE_ATOMIC);
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+ img_i2c_atomic_op(i2c, CMD_GEN_START, 0x00);
+}
+
+static void img_i2c_soft_reset(struct img_i2c *i2c)
+{
+ i2c->t_halt = false;
+ img_i2c_writel(i2c, SCB_CONTROL_REG, 0);
+ img_i2c_writel(i2c, SCB_CONTROL_REG,
+ SCB_CONTROL_CLK_ENABLE | SCB_CONTROL_SOFT_RESET);
+}
+
+/*
+ * Enable or release transaction halt for control of repeated starts.
+ * In version 3.3 of the IP when transaction halt is set, an interrupt
+ * will be generated after each byte of a transfer instead of after
+ * every transfer but before the stop bit.
+ * Due to this behaviour we have to be careful that every time we
+ * release the transaction halt we have to re-enable it straight away
+ * so that we only process a single byte, not doing so will result in
+ * all remaining bytes been processed and a stop bit being issued,
+ * which will prevent us having a repeated start.
+ */
+static void img_i2c_transaction_halt(struct img_i2c *i2c, bool t_halt)
+{
+ u32 val;
+
+ if (i2c->t_halt == t_halt)
+ return;
+ i2c->t_halt = t_halt;
+ val = img_i2c_readl(i2c, SCB_CONTROL_REG);
+ if (t_halt)
+ val |= SCB_CONTROL_TRANSACTION_HALT;
+ else
+ val &= ~SCB_CONTROL_TRANSACTION_HALT;
+ img_i2c_writel(i2c, SCB_CONTROL_REG, val);
+}
+
+/* Drain data from the FIFO into the buffer (automatic mode) */
+static void img_i2c_read_fifo(struct img_i2c *i2c)
+{
+ while (i2c->msg.len) {
+ u32 fifo_status;
+ u8 data;
+
+ img_i2c_wr_rd_fence(i2c);
+ fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
+ if (fifo_status & FIFO_READ_EMPTY)
+ break;
+
+ data = img_i2c_readl(i2c, SCB_READ_DATA_REG);
+ *i2c->msg.buf = data;
+
+ img_i2c_writel(i2c, SCB_READ_FIFO_REG, 0xff);
+ i2c->msg.len--;
+ i2c->msg.buf++;
+ }
+}
+
+/* Fill the FIFO with data from the buffer (automatic mode) */
+static void img_i2c_write_fifo(struct img_i2c *i2c)
+{
+ while (i2c->msg.len) {
+ u32 fifo_status;
+
+ img_i2c_wr_rd_fence(i2c);
+ fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
+ if (fifo_status & FIFO_WRITE_FULL)
+ break;
+
+ img_i2c_writel(i2c, SCB_WRITE_DATA_REG, *i2c->msg.buf);
+ i2c->msg.len--;
+ i2c->msg.buf++;
+ }
+
+ /* Disable fifo emptying interrupt if nothing more to write */
+ if (!i2c->msg.len)
+ i2c->int_enable &= ~INT_FIFO_EMPTYING;
+}
+
+/* Start a read transaction in automatic mode */
+static void img_i2c_read(struct img_i2c *i2c)
+{
+ img_i2c_switch_mode(i2c, MODE_AUTOMATIC);
+ if (!i2c->last_msg)
+ i2c->int_enable |= INT_SLAVE_EVENT;
+
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+ img_i2c_writel(i2c, SCB_READ_ADDR_REG, i2c->msg.addr);
+ img_i2c_writel(i2c, SCB_READ_COUNT_REG, i2c->msg.len);
+
+ mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
+}
+
+/* Start a write transaction in automatic mode */
+static void img_i2c_write(struct img_i2c *i2c)
+{
+ img_i2c_switch_mode(i2c, MODE_AUTOMATIC);
+ if (!i2c->last_msg)
+ i2c->int_enable |= INT_SLAVE_EVENT;
+
+ img_i2c_writel(i2c, SCB_WRITE_ADDR_REG, i2c->msg.addr);
+ img_i2c_writel(i2c, SCB_WRITE_COUNT_REG, i2c->msg.len);
+
+ mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
+ img_i2c_write_fifo(i2c);
+
+ /* img_i2c_write_fifo() may modify int_enable */
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+}
+
+/*
+ * Indicate that the transaction is complete. This is called from the
+ * ISR to wake up the waiting thread, after which the ISR must not
+ * access any more SCB registers.
+ */
+static void img_i2c_complete_transaction(struct img_i2c *i2c, int status)
+{
+ img_i2c_switch_mode(i2c, MODE_INACTIVE);
+ if (status) {
+ i2c->msg_status = status;
+ img_i2c_transaction_halt(i2c, false);
+ }
+ complete(&i2c->msg_complete);
+}
+
+static unsigned int img_i2c_raw_atomic_delay_handler(struct img_i2c *i2c,
+ u32 int_status, u32 line_status)
+{
+ /* Stay in raw mode for this, so we don't just loop infinitely */
+ img_i2c_atomic_op(i2c, i2c->at_cur_cmd, i2c->at_cur_data);
+ img_i2c_switch_mode(i2c, MODE_ATOMIC);
+ return 0;
+}
+
+static unsigned int img_i2c_raw(struct img_i2c *i2c, u32 int_status,
+ u32 line_status)
+{
+ if (int_status & INT_TIMING) {
+ if (i2c->raw_timeout == 0)
+ return img_i2c_raw_atomic_delay_handler(i2c,
+ int_status, line_status);
+ --i2c->raw_timeout;
+ }
+ return 0;
+}
+
+static unsigned int img_i2c_sequence(struct img_i2c *i2c, u32 int_status)
+{
+ static const unsigned int continue_bits[] = {
+ [CMD_GEN_START] = LINESTAT_START_BIT_DET,
+ [CMD_GEN_DATA] = LINESTAT_INPUT_HELD_V,
+ [CMD_RET_ACK] = LINESTAT_ACK_DET | LINESTAT_NACK_DET,
+ [CMD_RET_DATA] = LINESTAT_INPUT_HELD_V,
+ [CMD_GEN_STOP] = LINESTAT_STOP_BIT_DET,
+ };
+ int next_cmd = -1;
+ u8 next_data = 0x00;
+
+ if (int_status & INT_SLAVE_EVENT)
+ i2c->at_slave_event = true;
+ if (int_status & INT_TRANSACTION_DONE)
+ i2c->at_t_done = true;
+
+ if (!i2c->at_slave_event || !i2c->at_t_done)
+ return 0;
+
+ /* wait if no continue bits are set */
+ if (i2c->at_cur_cmd >= 0 &&
+ i2c->at_cur_cmd < ARRAY_SIZE(continue_bits)) {
+ unsigned int cont_bits = continue_bits[i2c->at_cur_cmd];
+
+ if (cont_bits) {
+ cont_bits |= LINESTAT_ABORT_DET;
+ if (!(i2c->line_status & cont_bits))
+ return 0;
+ }
+ }
+
+ /* follow the sequence of commands in i2c->seq */
+ next_cmd = *i2c->seq;
+ /* stop on a nil */
+ if (!next_cmd) {
+ img_i2c_writel(i2c, SCB_OVERRIDE_REG, 0);
+ return ISR_COMPLETE(0);
+ }
+ /* when generating data, the next byte is the data */
+ if (next_cmd == CMD_GEN_DATA) {
+ ++i2c->seq;
+ next_data = *i2c->seq;
+ }
+ ++i2c->seq;
+ img_i2c_atomic_op(i2c, next_cmd, next_data);
+
+ return 0;
+}
+
+static void img_i2c_reset_start(struct img_i2c *i2c)
+{
+ /* Initiate the magic dance */
+ img_i2c_switch_mode(i2c, MODE_SEQUENCE);
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+ i2c->seq = img_i2c_reset_seq;
+ i2c->at_slave_event = true;
+ i2c->at_t_done = true;
+ i2c->at_cur_cmd = -1;
+
+ /* img_i2c_reset_seq isn't empty so the following won't fail */
+ img_i2c_sequence(i2c, 0);
+}
+
+static void img_i2c_stop_start(struct img_i2c *i2c)
+{
+ /* Initiate a stop bit sequence */
+ img_i2c_switch_mode(i2c, MODE_SEQUENCE);
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+ i2c->seq = img_i2c_stop_seq;
+ i2c->at_slave_event = true;
+ i2c->at_t_done = true;
+ i2c->at_cur_cmd = -1;
+
+ /* img_i2c_stop_seq isn't empty so the following won't fail */
+ img_i2c_sequence(i2c, 0);
+}
+
+static unsigned int img_i2c_atomic(struct img_i2c *i2c,
+ u32 int_status,
+ u32 line_status)
+{
+ int next_cmd = -1;
+ u8 next_data = 0x00;
+
+ if (int_status & INT_SLAVE_EVENT)
+ i2c->at_slave_event = true;
+ if (int_status & INT_TRANSACTION_DONE)
+ i2c->at_t_done = true;
+
+ if (!i2c->at_slave_event || !i2c->at_t_done)
+ goto next_atomic_cmd;
+ if (i2c->line_status & LINESTAT_ABORT_DET) {
+ dev_dbg(i2c->adap.dev.parent, "abort condition detected\n");
+ next_cmd = CMD_GEN_STOP;
+ i2c->msg_status = -EIO;
+ goto next_atomic_cmd;
+ }
+
+ /* i2c->at_cur_cmd may have completed */
+ switch (i2c->at_cur_cmd) {
+ case CMD_GEN_START:
+ next_cmd = CMD_GEN_DATA;
+ next_data = i2c_8bit_addr_from_msg(&i2c->msg);
+ break;
+ case CMD_GEN_DATA:
+ if (i2c->line_status & LINESTAT_INPUT_HELD_V)
+ next_cmd = CMD_RET_ACK;
+ break;
+ case CMD_RET_ACK:
+ if (i2c->line_status & LINESTAT_ACK_DET ||
+ (i2c->line_status & LINESTAT_NACK_DET &&
+ i2c->msg.flags & I2C_M_IGNORE_NAK)) {
+ if (i2c->msg.len == 0) {
+ next_cmd = CMD_GEN_STOP;
+ } else if (i2c->msg.flags & I2C_M_RD) {
+ next_cmd = CMD_RET_DATA;
+ } else {
+ next_cmd = CMD_GEN_DATA;
+ next_data = *i2c->msg.buf;
+ --i2c->msg.len;
+ ++i2c->msg.buf;
+ }
+ } else if (i2c->line_status & LINESTAT_NACK_DET) {
+ i2c->msg_status = -EIO;
+ next_cmd = CMD_GEN_STOP;
+ }
+ break;
+ case CMD_RET_DATA:
+ if (i2c->line_status & LINESTAT_INPUT_HELD_V) {
+ *i2c->msg.buf = (i2c->line_status &
+ LINESTAT_INPUT_DATA)
+ >> LINESTAT_INPUT_DATA_SHIFT;
+ --i2c->msg.len;
+ ++i2c->msg.buf;
+ if (i2c->msg.len)
+ next_cmd = CMD_GEN_ACK;
+ else
+ next_cmd = CMD_GEN_NACK;
+ }
+ break;
+ case CMD_GEN_ACK:
+ if (i2c->line_status & LINESTAT_ACK_DET) {
+ next_cmd = CMD_RET_DATA;
+ } else {
+ i2c->msg_status = -EIO;
+ next_cmd = CMD_GEN_STOP;
+ }
+ break;
+ case CMD_GEN_NACK:
+ next_cmd = CMD_GEN_STOP;
+ break;
+ case CMD_GEN_STOP:
+ img_i2c_writel(i2c, SCB_OVERRIDE_REG, 0);
+ return ISR_COMPLETE(0);
+ default:
+ dev_err(i2c->adap.dev.parent, "bad atomic command %d\n",
+ i2c->at_cur_cmd);
+ i2c->msg_status = -EIO;
+ next_cmd = CMD_GEN_STOP;
+ break;
+ }
+
+next_atomic_cmd:
+ if (next_cmd != -1) {
+ /* don't actually stop unless we're the last transaction */
+ if (next_cmd == CMD_GEN_STOP && !i2c->msg_status &&
+ !i2c->last_msg)
+ return ISR_COMPLETE(0);
+ img_i2c_atomic_op(i2c, next_cmd, next_data);
+ }
+ return 0;
+}
+
+/*
+ * Timer function to check if something has gone wrong in automatic mode (so we
+ * don't have to handle so many interrupts just to catch an exception).
+ */
+static void img_i2c_check_timer(struct timer_list *t)
+{
+ struct img_i2c *i2c = from_timer(i2c, t, check_timer);
+ unsigned long flags;
+ unsigned int line_status;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ line_status = img_i2c_readl(i2c, SCB_STATUS_REG);
+
+ /* check for an abort condition */
+ if (line_status & LINESTAT_ABORT_DET) {
+ dev_dbg(i2c->adap.dev.parent,
+ "abort condition detected by check timer\n");
+ /* enable slave event interrupt mask to trigger irq */
+ img_i2c_writel(i2c, SCB_INT_MASK_REG,
+ i2c->int_enable | INT_SLAVE_EVENT);
+ }
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+}
+
+static unsigned int img_i2c_auto(struct img_i2c *i2c,
+ unsigned int int_status,
+ unsigned int line_status)
+{
+ if (int_status & (INT_WRITE_ACK_ERR | INT_ADDR_ACK_ERR))
+ return ISR_COMPLETE(EIO);
+
+ if (line_status & LINESTAT_ABORT_DET) {
+ dev_dbg(i2c->adap.dev.parent, "abort condition detected\n");
+ /* empty the read fifo */
+ if ((i2c->msg.flags & I2C_M_RD) &&
+ (int_status & INT_FIFO_FULL_FILLING))
+ img_i2c_read_fifo(i2c);
+ /* use atomic mode and try to force a stop bit */
+ i2c->msg_status = -EIO;
+ img_i2c_stop_start(i2c);
+ return 0;
+ }
+
+ /* Enable transaction halt on start bit */
+ if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) {
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+ /* we're no longer interested in the slave event */
+ i2c->int_enable &= ~INT_SLAVE_EVENT;
+ }
+
+ mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
+
+ if (int_status & INT_STOP_DETECTED) {
+ /* Drain remaining data in FIFO and complete transaction */
+ if (i2c->msg.flags & I2C_M_RD)
+ img_i2c_read_fifo(i2c);
+ return ISR_COMPLETE(0);
+ }
+
+ if (i2c->msg.flags & I2C_M_RD) {
+ if (int_status & (INT_FIFO_FULL_FILLING | INT_MASTER_HALTED)) {
+ img_i2c_read_fifo(i2c);
+ if (i2c->msg.len == 0)
+ return ISR_WAITSTOP;
+ }
+ } else {
+ if (int_status & (INT_FIFO_EMPTY | INT_MASTER_HALTED)) {
+ if ((int_status & INT_FIFO_EMPTY) &&
+ i2c->msg.len == 0)
+ return ISR_WAITSTOP;
+ img_i2c_write_fifo(i2c);
+ }
+ }
+ if (int_status & INT_MASTER_HALTED) {
+ /*
+ * Release and then enable transaction halt, to
+ * allow only a single byte to proceed.
+ */
+ img_i2c_transaction_halt(i2c, false);
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+ }
+
+ return 0;
+}
+
+static irqreturn_t img_i2c_isr(int irq, void *dev_id)
+{
+ struct img_i2c *i2c = (struct img_i2c *)dev_id;
+ u32 int_status, line_status;
+ /* We handle transaction completion AFTER accessing registers */
+ unsigned int hret;
+
+ /* Read interrupt status register. */
+ int_status = img_i2c_readl(i2c, SCB_INT_STATUS_REG);
+ /* Clear detected interrupts. */
+ img_i2c_writel(i2c, SCB_INT_CLEAR_REG, int_status);
+
+ /*
+ * Read line status and clear it until it actually is clear. We have
+ * to be careful not to lose any line status bits that get latched.
+ */
+ line_status = img_i2c_readl(i2c, SCB_STATUS_REG);
+ if (line_status & LINESTAT_LATCHED) {
+ img_i2c_writel(i2c, SCB_CLEAR_REG,
+ (line_status & LINESTAT_LATCHED)
+ >> LINESTAT_CLEAR_SHIFT);
+ img_i2c_wr_rd_fence(i2c);
+ }
+
+ spin_lock(&i2c->lock);
+
+ /* Keep track of line status bits received */
+ i2c->line_status &= ~LINESTAT_INPUT_DATA;
+ i2c->line_status |= line_status;
+
+ /*
+ * Certain interrupts indicate that sclk low timeout is not
+ * a problem. If any of these are set, just continue.
+ */
+ if ((int_status & INT_SCLK_LOW_TIMEOUT) &&
+ !(int_status & (INT_SLAVE_EVENT |
+ INT_FIFO_EMPTY |
+ INT_FIFO_FULL))) {
+ dev_crit(i2c->adap.dev.parent,
+ "fatal: clock low timeout occurred %s addr 0x%02x\n",
+ (i2c->msg.flags & I2C_M_RD) ? "reading" : "writing",
+ i2c->msg.addr);
+ hret = ISR_FATAL(EIO);
+ goto out;
+ }
+
+ if (i2c->mode == MODE_ATOMIC)
+ hret = img_i2c_atomic(i2c, int_status, line_status);
+ else if (i2c->mode == MODE_AUTOMATIC)
+ hret = img_i2c_auto(i2c, int_status, line_status);
+ else if (i2c->mode == MODE_SEQUENCE)
+ hret = img_i2c_sequence(i2c, int_status);
+ else if (i2c->mode == MODE_WAITSTOP && (int_status & INT_SLAVE_EVENT) &&
+ (line_status & LINESTAT_STOP_BIT_DET))
+ hret = ISR_COMPLETE(0);
+ else if (i2c->mode == MODE_RAW)
+ hret = img_i2c_raw(i2c, int_status, line_status);
+ else
+ hret = 0;
+
+ /* Clear detected level interrupts. */
+ img_i2c_writel(i2c, SCB_INT_CLEAR_REG, int_status & INT_LEVEL);
+
+out:
+ if (hret & ISR_WAITSTOP) {
+ /*
+ * Only wait for stop on last message.
+ * Also we may already have detected the stop bit.
+ */
+ if (!i2c->last_msg || i2c->line_status & LINESTAT_STOP_BIT_DET)
+ hret = ISR_COMPLETE(0);
+ else
+ img_i2c_switch_mode(i2c, MODE_WAITSTOP);
+ }
+
+ /* now we've finished using regs, handle transaction completion */
+ if (hret & ISR_COMPLETE_M) {
+ int status = -(hret & ISR_STATUS_M);
+
+ img_i2c_complete_transaction(i2c, status);
+ if (hret & ISR_FATAL_M)
+ img_i2c_switch_mode(i2c, MODE_FATAL);
+ }
+
+ /* Enable interrupts (int_enable may be altered by changing mode) */
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+
+ spin_unlock(&i2c->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* Force a bus reset sequence and wait for it to complete */
+static int img_i2c_reset_bus(struct img_i2c *i2c)
+{
+ unsigned long flags;
+ unsigned long time_left;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ reinit_completion(&i2c->msg_complete);
+ img_i2c_reset_start(i2c);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ time_left = wait_for_completion_timeout(&i2c->msg_complete,
+ IMG_I2C_TIMEOUT);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct img_i2c *i2c = i2c_get_adapdata(adap);
+ bool atomic = false;
+ int i, ret;
+ unsigned long time_left;
+
+ if (i2c->mode == MODE_SUSPEND) {
+ WARN(1, "refusing to service transaction in suspended state\n");
+ return -EIO;
+ }
+
+ if (i2c->mode == MODE_FATAL)
+ return -EIO;
+
+ for (i = 0; i < num; i++) {
+ /*
+ * 0 byte reads are not possible because the slave could try
+ * and pull the data line low, preventing a stop bit.
+ */
+ if (!msgs[i].len && msgs[i].flags & I2C_M_RD)
+ return -EIO;
+ /*
+ * 0 byte writes are possible and used for probing, but we
+ * cannot do them in automatic mode, so use atomic mode
+ * instead.
+ *
+ * Also, the I2C_M_IGNORE_NAK mode can only be implemented
+ * in atomic mode.
+ */
+ if (!msgs[i].len ||
+ (msgs[i].flags & I2C_M_IGNORE_NAK))
+ atomic = true;
+ }
+
+ ret = pm_runtime_get_sync(adap->dev.parent);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num; i++) {
+ struct i2c_msg *msg = &msgs[i];
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ /*
+ * Make a copy of the message struct. We mustn't modify the
+ * original or we'll confuse drivers and i2c-dev.
+ */
+ i2c->msg = *msg;
+ i2c->msg_status = 0;
+
+ /*
+ * After the last message we must have waited for a stop bit.
+ * Not waiting can cause problems when the clock is disabled
+ * before the stop bit is sent, and the linux I2C interface
+ * requires separate transfers not to joined with repeated
+ * start.
+ */
+ i2c->last_msg = (i == num - 1);
+ reinit_completion(&i2c->msg_complete);
+
+ /*
+ * Clear line status and all interrupts before starting a
+ * transfer, as we may have unserviced interrupts from
+ * previous transfers that might be handled in the context
+ * of the new transfer.
+ */
+ img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
+ img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
+
+ if (atomic) {
+ img_i2c_atomic_start(i2c);
+ } else {
+ /*
+ * Enable transaction halt if not the last message in
+ * the queue so that we can control repeated starts.
+ */
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+
+ if (msg->flags & I2C_M_RD)
+ img_i2c_read(i2c);
+ else
+ img_i2c_write(i2c);
+
+ /*
+ * Release and then enable transaction halt, to
+ * allow only a single byte to proceed.
+ * This doesn't have an effect on the initial transfer
+ * but will allow the following transfers to start
+ * processing if the previous transfer was marked as
+ * complete while the i2c block was halted.
+ */
+ img_i2c_transaction_halt(i2c, false);
+ img_i2c_transaction_halt(i2c, !i2c->last_msg);
+ }
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ time_left = wait_for_completion_timeout(&i2c->msg_complete,
+ IMG_I2C_TIMEOUT);
+ del_timer_sync(&i2c->check_timer);
+
+ if (time_left == 0) {
+ dev_err(adap->dev.parent, "i2c transfer timed out\n");
+ i2c->msg_status = -ETIMEDOUT;
+ break;
+ }
+
+ if (i2c->msg_status)
+ break;
+ }
+
+ pm_runtime_mark_last_busy(adap->dev.parent);
+ pm_runtime_put_autosuspend(adap->dev.parent);
+
+ return i2c->msg_status ? i2c->msg_status : num;
+}
+
+static u32 img_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm img_i2c_algo = {
+ .master_xfer = img_i2c_xfer,
+ .functionality = img_i2c_func,
+};
+
+static int img_i2c_init(struct img_i2c *i2c)
+{
+ unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh;
+ unsigned int i, data, prescale, inc, int_bitrate, filt;
+ struct img_i2c_timings timing;
+ u32 rev;
+ int ret;
+
+ ret = pm_runtime_get_sync(i2c->adap.dev.parent);
+ if (ret < 0)
+ return ret;
+
+ rev = img_i2c_readl(i2c, SCB_CORE_REV_REG);
+ if ((rev & 0x00ffffff) < 0x00020200) {
+ dev_info(i2c->adap.dev.parent,
+ "Unknown hardware revision (%d.%d.%d.%d)\n",
+ (rev >> 24) & 0xff, (rev >> 16) & 0xff,
+ (rev >> 8) & 0xff, rev & 0xff);
+ pm_runtime_mark_last_busy(i2c->adap.dev.parent);
+ pm_runtime_put_autosuspend(i2c->adap.dev.parent);
+ return -EINVAL;
+ }
+
+ /* Fencing enabled by default. */
+ i2c->need_wr_rd_fence = true;
+
+ /* Determine what mode we're in from the bitrate */
+ timing = timings[0];
+ for (i = 0; i < ARRAY_SIZE(timings); i++) {
+ if (i2c->bitrate <= timings[i].max_bitrate) {
+ timing = timings[i];
+ break;
+ }
+ }
+ if (i2c->bitrate > timings[ARRAY_SIZE(timings) - 1].max_bitrate) {
+ dev_warn(i2c->adap.dev.parent,
+ "requested bitrate (%u) is higher than the max bitrate supported (%u)\n",
+ i2c->bitrate,
+ timings[ARRAY_SIZE(timings) - 1].max_bitrate);
+ timing = timings[ARRAY_SIZE(timings) - 1];
+ i2c->bitrate = timing.max_bitrate;
+ }
+
+ bitrate_khz = i2c->bitrate / 1000;
+ clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
+
+ /* Find the prescale that would give us that inc (approx delay = 0) */
+ prescale = SCB_OPT_INC * clk_khz / (256 * 16 * bitrate_khz);
+ prescale = clamp_t(unsigned int, prescale, 1, 8);
+ clk_khz /= prescale;
+
+ /* Setup the clock increment value */
+ inc = (256 * 16 * bitrate_khz) / clk_khz;
+
+ /*
+ * The clock generation logic allows to filter glitches on the bus.
+ * This filter is able to remove bus glitches shorter than 50ns.
+ * If the clock enable rate is greater than 20 MHz, no filtering
+ * is required, so we need to disable it.
+ * If it's between the 20-40 MHz range, there's no need to divide
+ * the clock to get a filter.
+ */
+ if (clk_khz < 20000) {
+ filt = SCB_FILT_DISABLE;
+ } else if (clk_khz < 40000) {
+ filt = SCB_FILT_BYPASS;
+ } else {
+ /* Calculate filter clock */
+ filt = (64000 / ((clk_khz / 1000) * SCB_FILT_GLITCH));
+
+ /* Scale up if needed */
+ if (64000 % ((clk_khz / 1000) * SCB_FILT_GLITCH))
+ inc++;
+
+ if (filt > SCB_FILT_INC_MASK)
+ filt = SCB_FILT_INC_MASK;
+
+ filt = (filt & SCB_FILT_INC_MASK) << SCB_FILT_INC_SHIFT;
+ }
+ data = filt | ((inc & SCB_INC_MASK) << SCB_INC_SHIFT) | (prescale - 1);
+ img_i2c_writel(i2c, SCB_CLK_SET_REG, data);
+
+ /* Obtain the clock period of the fx16 clock in ns */
+ clk_period = (256 * 1000000) / (clk_khz * inc);
+
+ /* Calculate the bitrate in terms of internal clock pulses */
+ int_bitrate = 1000000 / (bitrate_khz * clk_period);
+ if ((1000000 % (bitrate_khz * clk_period)) >=
+ ((bitrate_khz * clk_period) / 2))
+ int_bitrate++;
+
+ /*
+ * Setup clock duty cycle, start with 50% and adjust TCKH and TCKL
+ * values from there if they don't meet minimum timing requirements
+ */
+ tckh = int_bitrate / 2;
+ tckl = int_bitrate - tckh;
+
+ /* Adjust TCKH and TCKL values */
+ data = DIV_ROUND_UP(timing.tckl, clk_period);
+
+ if (tckl < data) {
+ tckl = data;
+ tckh = int_bitrate - tckl;
+ }
+
+ if (tckh > 0)
+ --tckh;
+
+ if (tckl > 0)
+ --tckl;
+
+ img_i2c_writel(i2c, SCB_TIME_TCKH_REG, tckh);
+ img_i2c_writel(i2c, SCB_TIME_TCKL_REG, tckl);
+
+ /* Setup TSDH value */
+ tsdh = DIV_ROUND_UP(timing.tsdh, clk_period);
+
+ if (tsdh > 1)
+ data = tsdh - 1;
+ else
+ data = 0x01;
+ img_i2c_writel(i2c, SCB_TIME_TSDH_REG, data);
+
+ /* This value is used later */
+ tsdh = data;
+
+ /* Setup TPL value */
+ data = timing.tpl / clk_period;
+ if (data > 0)
+ --data;
+ img_i2c_writel(i2c, SCB_TIME_TPL_REG, data);
+
+ /* Setup TPH value */
+ data = timing.tph / clk_period;
+ if (data > 0)
+ --data;
+ img_i2c_writel(i2c, SCB_TIME_TPH_REG, data);
+
+ /* Setup TSDL value to TPL + TSDH + 2 */
+ img_i2c_writel(i2c, SCB_TIME_TSDL_REG, data + tsdh + 2);
+
+ /* Setup TP2S value */
+ data = timing.tp2s / clk_period;
+ if (data > 0)
+ --data;
+ img_i2c_writel(i2c, SCB_TIME_TP2S_REG, data);
+
+ img_i2c_writel(i2c, SCB_TIME_TBI_REG, TIMEOUT_TBI);
+ img_i2c_writel(i2c, SCB_TIME_TSL_REG, TIMEOUT_TSL);
+ img_i2c_writel(i2c, SCB_TIME_TDL_REG, TIMEOUT_TDL);
+
+ /* Take module out of soft reset and enable clocks */
+ img_i2c_soft_reset(i2c);
+
+ /* Disable all interrupts */
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, 0);
+
+ /* Clear all interrupts */
+ img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
+
+ /* Clear the scb_line_status events */
+ img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
+
+ /* Enable interrupts */
+ img_i2c_writel(i2c, SCB_INT_MASK_REG, i2c->int_enable);
+
+ /* Perform a synchronous sequence to reset the bus */
+ ret = img_i2c_reset_bus(i2c);
+
+ pm_runtime_mark_last_busy(i2c->adap.dev.parent);
+ pm_runtime_put_autosuspend(i2c->adap.dev.parent);
+
+ return ret;
+}
+
+static int img_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct img_i2c *i2c;
+ struct resource *res;
+ int irq, ret;
+ u32 val;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct img_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "can't get irq number\n");
+ return irq;
+ }
+
+ i2c->sys_clk = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(i2c->sys_clk)) {
+ dev_err(&pdev->dev, "can't get system clock\n");
+ return PTR_ERR(i2c->sys_clk);
+ }
+
+ i2c->scb_clk = devm_clk_get(&pdev->dev, "scb");
+ if (IS_ERR(i2c->scb_clk)) {
+ dev_err(&pdev->dev, "can't get core clock\n");
+ return PTR_ERR(i2c->scb_clk);
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, img_i2c_isr, 0,
+ pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "can't request irq %d\n", irq);
+ return ret;
+ }
+
+ /* Set up the exception check timer */
+ timer_setup(&i2c->check_timer, img_i2c_check_timer, 0);
+
+ i2c->bitrate = timings[0].max_bitrate;
+ if (!of_property_read_u32(node, "clock-frequency", &val))
+ i2c->bitrate = val;
+
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = node;
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &img_i2c_algo;
+ i2c->adap.retries = 5;
+ i2c->adap.nr = pdev->id;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name), "IMG SCB I2C");
+
+ img_i2c_switch_mode(i2c, MODE_INACTIVE);
+ spin_lock_init(&i2c->lock);
+ init_completion(&i2c->msg_complete);
+
+ platform_set_drvdata(pdev, i2c);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_i2c_runtime_resume(&pdev->dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = img_i2c_init(i2c);
+ if (ret)
+ goto rpm_disable;
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0)
+ goto rpm_disable;
+
+ return 0;
+
+rpm_disable:
+ if (!pm_runtime_enabled(&pdev->dev))
+ img_i2c_runtime_suspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ return ret;
+}
+
+static int img_i2c_remove(struct platform_device *dev)
+{
+ struct img_i2c *i2c = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&i2c->adap);
+ pm_runtime_disable(&dev->dev);
+ if (!pm_runtime_status_suspended(&dev->dev))
+ img_i2c_runtime_suspend(&dev->dev);
+
+ return 0;
+}
+
+static int img_i2c_runtime_suspend(struct device *dev)
+{
+ struct img_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(i2c->scb_clk);
+ clk_disable_unprepare(i2c->sys_clk);
+
+ return 0;
+}
+
+static int img_i2c_runtime_resume(struct device *dev)
+{
+ struct img_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(i2c->sys_clk);
+ if (ret) {
+ dev_err(dev, "Unable to enable sys clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(i2c->scb_clk);
+ if (ret) {
+ dev_err(dev, "Unable to enable scb clock\n");
+ clk_disable_unprepare(i2c->sys_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int img_i2c_suspend(struct device *dev)
+{
+ struct img_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ img_i2c_switch_mode(i2c, MODE_SUSPEND);
+
+ return 0;
+}
+
+static int img_i2c_resume(struct device *dev)
+{
+ struct img_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ img_i2c_init(i2c);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops img_i2c_pm = {
+ SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend,
+ img_i2c_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume)
+};
+
+static const struct of_device_id img_scb_i2c_match[] = {
+ { .compatible = "img,scb-i2c" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, img_scb_i2c_match);
+
+static struct platform_driver img_scb_i2c_driver = {
+ .driver = {
+ .name = "img-i2c-scb",
+ .of_match_table = img_scb_i2c_match,
+ .pm = &img_i2c_pm,
+ },
+ .probe = img_i2c_probe,
+ .remove = img_i2c_remove,
+};
+module_platform_driver(img_scb_i2c_driver);
+
+MODULE_AUTHOR("James Hogan <jhogan@kernel.org>");
+MODULE_DESCRIPTION("IMG host I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
new file mode 100644
index 000000000..06c4c767a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -0,0 +1,693 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This is i.MX low power i2c controller driver.
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#define DRIVER_NAME "imx-lpi2c"
+
+#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
+#define LPI2C_MCR 0x10 /* i2c contrl register */
+#define LPI2C_MSR 0x14 /* i2c status register */
+#define LPI2C_MIER 0x18 /* i2c interrupt enable */
+#define LPI2C_MCFGR0 0x20 /* i2c master configuration */
+#define LPI2C_MCFGR1 0x24 /* i2c master configuration */
+#define LPI2C_MCFGR2 0x28 /* i2c master configuration */
+#define LPI2C_MCFGR3 0x2C /* i2c master configuration */
+#define LPI2C_MCCR0 0x48 /* i2c master clk configuration */
+#define LPI2C_MCCR1 0x50 /* i2c master clk configuration */
+#define LPI2C_MFCR 0x58 /* i2c master FIFO control */
+#define LPI2C_MFSR 0x5C /* i2c master FIFO status */
+#define LPI2C_MTDR 0x60 /* i2c master TX data register */
+#define LPI2C_MRDR 0x70 /* i2c master RX data register */
+
+/* i2c command */
+#define TRAN_DATA 0X00
+#define RECV_DATA 0X01
+#define GEN_STOP 0X02
+#define RECV_DISCARD 0X03
+#define GEN_START 0X04
+#define START_NACK 0X05
+#define START_HIGH 0X06
+#define START_HIGH_NACK 0X07
+
+#define MCR_MEN BIT(0)
+#define MCR_RST BIT(1)
+#define MCR_DOZEN BIT(2)
+#define MCR_DBGEN BIT(3)
+#define MCR_RTF BIT(8)
+#define MCR_RRF BIT(9)
+#define MSR_TDF BIT(0)
+#define MSR_RDF BIT(1)
+#define MSR_SDF BIT(9)
+#define MSR_NDF BIT(10)
+#define MSR_ALF BIT(11)
+#define MSR_MBF BIT(24)
+#define MSR_BBF BIT(25)
+#define MIER_TDIE BIT(0)
+#define MIER_RDIE BIT(1)
+#define MIER_SDIE BIT(9)
+#define MIER_NDIE BIT(10)
+#define MCFGR1_AUTOSTOP BIT(8)
+#define MCFGR1_IGNACK BIT(9)
+#define MRDR_RXEMPTY BIT(14)
+
+#define I2C_CLK_RATIO 2
+#define CHUNK_DATA 256
+
+#define LPI2C_DEFAULT_RATE 100000
+#define STARDARD_MAX_BITRATE 400000
+#define FAST_MAX_BITRATE 1000000
+#define FAST_PLUS_MAX_BITRATE 3400000
+#define HIGHSPEED_MAX_BITRATE 5000000
+
+#define I2C_PM_TIMEOUT 10 /* ms */
+
+enum lpi2c_imx_mode {
+ STANDARD, /* 100+Kbps */
+ FAST, /* 400+Kbps */
+ FAST_PLUS, /* 1.0+Mbps */
+ HS, /* 3.4+Mbps */
+ ULTRA_FAST, /* 5.0+Mbps */
+};
+
+enum lpi2c_imx_pincfg {
+ TWO_PIN_OD,
+ TWO_PIN_OO,
+ TWO_PIN_PP,
+ FOUR_PIN_PP,
+};
+
+struct lpi2c_imx_struct {
+ struct i2c_adapter adapter;
+ struct clk *clk;
+ void __iomem *base;
+ __u8 *rx_buf;
+ __u8 *tx_buf;
+ struct completion complete;
+ unsigned int msglen;
+ unsigned int delivered;
+ unsigned int block_data;
+ unsigned int bitrate;
+ unsigned int txfifosize;
+ unsigned int rxfifosize;
+ enum lpi2c_imx_mode mode;
+};
+
+static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
+ unsigned int enable)
+{
+ writel(enable, lpi2c_imx->base + LPI2C_MIER);
+}
+
+static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
+
+ while (1) {
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+
+ /* check for arbitration lost, clear if set */
+ if (temp & MSR_ALF) {
+ writel(temp, lpi2c_imx->base + LPI2C_MSR);
+ return -EAGAIN;
+ }
+
+ if (temp & (MSR_BBF | MSR_MBF))
+ break;
+
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
+ return -ETIMEDOUT;
+ }
+ schedule();
+ }
+
+ return 0;
+}
+
+static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int bitrate = lpi2c_imx->bitrate;
+ enum lpi2c_imx_mode mode;
+
+ if (bitrate < STARDARD_MAX_BITRATE)
+ mode = STANDARD;
+ else if (bitrate < FAST_MAX_BITRATE)
+ mode = FAST;
+ else if (bitrate < FAST_PLUS_MAX_BITRATE)
+ mode = FAST_PLUS;
+ else if (bitrate < HIGHSPEED_MAX_BITRATE)
+ mode = HS;
+ else
+ mode = ULTRA_FAST;
+
+ lpi2c_imx->mode = mode;
+}
+
+static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ unsigned int temp;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp |= MCR_RRF | MCR_RTF;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+ writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
+
+ temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+ return lpi2c_imx_bus_busy(lpi2c_imx);
+}
+
+static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
+
+ writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
+
+ do {
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+ if (temp & MSR_SDF)
+ break;
+
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
+ break;
+ }
+ schedule();
+
+ } while (1);
+}
+
+/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
+static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u8 prescale, filt, sethold, clkhi, clklo, datavd;
+ unsigned int clk_rate, clk_cycle;
+ enum lpi2c_imx_pincfg pincfg;
+ unsigned int temp;
+
+ lpi2c_imx_set_mode(lpi2c_imx);
+
+ clk_rate = clk_get_rate(lpi2c_imx->clk);
+ if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
+ filt = 0;
+ else
+ filt = 2;
+
+ for (prescale = 0; prescale <= 7; prescale++) {
+ clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate)
+ - 3 - (filt >> 1);
+ clkhi = (clk_cycle + I2C_CLK_RATIO) / (I2C_CLK_RATIO + 1);
+ clklo = clk_cycle - clkhi;
+ if (clklo < 64)
+ break;
+ }
+
+ if (prescale > 7)
+ return -EINVAL;
+
+ /* set MCFGR1: PINCFG, PRESCALE, IGNACK */
+ if (lpi2c_imx->mode == ULTRA_FAST)
+ pincfg = TWO_PIN_OO;
+ else
+ pincfg = TWO_PIN_OD;
+ temp = prescale | pincfg << 24;
+
+ if (lpi2c_imx->mode == ULTRA_FAST)
+ temp |= MCFGR1_IGNACK;
+
+ writel(temp, lpi2c_imx->base + LPI2C_MCFGR1);
+
+ /* set MCFGR2: FILTSDA, FILTSCL */
+ temp = (filt << 16) | (filt << 24);
+ writel(temp, lpi2c_imx->base + LPI2C_MCFGR2);
+
+ /* set MCCR: DATAVD, SETHOLD, CLKHI, CLKLO */
+ sethold = clkhi;
+ datavd = clkhi >> 1;
+ temp = datavd << 24 | sethold << 16 | clkhi << 8 | clklo;
+
+ if (lpi2c_imx->mode == HS)
+ writel(temp, lpi2c_imx->base + LPI2C_MCCR1);
+ else
+ writel(temp, lpi2c_imx->base + LPI2C_MCCR0);
+
+ return 0;
+}
+
+static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp;
+ int ret;
+
+ ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
+ if (ret < 0)
+ return ret;
+
+ temp = MCR_RST;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+ writel(0, lpi2c_imx->base + LPI2C_MCR);
+
+ ret = lpi2c_imx_config(lpi2c_imx);
+ if (ret)
+ goto rpm_put;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp |= MCR_MEN;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+ return 0;
+
+rpm_put:
+ pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
+
+ return ret;
+}
+
+static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u32 temp;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp &= ~MCR_MEN;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+ pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
+
+ return 0;
+}
+
+static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long timeout;
+
+ timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ);
+
+ return timeout ? 0 : -ETIMEDOUT;
+}
+
+static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long orig_jiffies = jiffies;
+ u32 txcnt;
+
+ do {
+ txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+
+ if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
+ return -EIO;
+ }
+
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
+ return -ETIMEDOUT;
+ }
+ schedule();
+
+ } while (txcnt);
+
+ return 0;
+}
+
+static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ writel(lpi2c_imx->txfifosize >> 1, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp, remaining;
+
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+
+ if (remaining > (lpi2c_imx->rxfifosize >> 1))
+ temp = lpi2c_imx->rxfifosize >> 1;
+ else
+ temp = 0;
+
+ writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int data, txcnt;
+
+ txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+
+ while (txcnt < lpi2c_imx->txfifosize) {
+ if (lpi2c_imx->delivered == lpi2c_imx->msglen)
+ break;
+
+ data = lpi2c_imx->tx_buf[lpi2c_imx->delivered++];
+ writel(data, lpi2c_imx->base + LPI2C_MTDR);
+ txcnt++;
+ }
+
+ if (lpi2c_imx->delivered < lpi2c_imx->msglen)
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
+ else
+ complete(&lpi2c_imx->complete);
+}
+
+static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int blocklen, remaining;
+ unsigned int temp, data;
+
+ do {
+ data = readl(lpi2c_imx->base + LPI2C_MRDR);
+ if (data & MRDR_RXEMPTY)
+ break;
+
+ lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
+ } while (1);
+
+ /*
+ * First byte is the length of remaining packet in the SMBus block
+ * data read. Add it to msgs->len.
+ */
+ if (lpi2c_imx->block_data) {
+ blocklen = lpi2c_imx->rx_buf[0];
+ lpi2c_imx->msglen += blocklen;
+ }
+
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+
+ if (!remaining) {
+ complete(&lpi2c_imx->complete);
+ return;
+ }
+
+ /* not finished, still waiting for rx data */
+ lpi2c_imx_set_rx_watermark(lpi2c_imx);
+
+ /* multiple receive commands */
+ if (lpi2c_imx->block_data) {
+ lpi2c_imx->block_data = 0;
+ temp = remaining;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+ } else if (!(lpi2c_imx->delivered & 0xff)) {
+ temp = (remaining > CHUNK_DATA ? CHUNK_DATA : remaining) - 1;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+ }
+
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
+}
+
+static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ lpi2c_imx->tx_buf = msgs->buf;
+ lpi2c_imx_set_tx_watermark(lpi2c_imx);
+ lpi2c_imx_write_txfifo(lpi2c_imx);
+}
+
+static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ unsigned int temp;
+
+ lpi2c_imx->rx_buf = msgs->buf;
+ lpi2c_imx->block_data = msgs->flags & I2C_M_RECV_LEN;
+
+ lpi2c_imx_set_rx_watermark(lpi2c_imx);
+ temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
+}
+
+static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter);
+ unsigned int temp;
+ int i, result;
+
+ result = lpi2c_imx_master_enable(lpi2c_imx);
+ if (result)
+ return result;
+
+ for (i = 0; i < num; i++) {
+ result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
+ if (result)
+ goto disable;
+
+ /* quick smbus */
+ if (num == 1 && msgs[0].len == 0)
+ goto stop;
+
+ lpi2c_imx->delivered = 0;
+ lpi2c_imx->msglen = msgs[i].len;
+ init_completion(&lpi2c_imx->complete);
+
+ if (msgs[i].flags & I2C_M_RD)
+ lpi2c_imx_read(lpi2c_imx, &msgs[i]);
+ else
+ lpi2c_imx_write(lpi2c_imx, &msgs[i]);
+
+ result = lpi2c_imx_msg_complete(lpi2c_imx);
+ if (result)
+ goto stop;
+
+ if (!(msgs[i].flags & I2C_M_RD)) {
+ result = lpi2c_imx_txfifo_empty(lpi2c_imx);
+ if (result)
+ goto stop;
+ }
+ }
+
+stop:
+ lpi2c_imx_stop(lpi2c_imx);
+
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+ if ((temp & MSR_NDF) && !result)
+ result = -EIO;
+
+disable:
+ lpi2c_imx_master_disable(lpi2c_imx);
+
+ dev_dbg(&lpi2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+ (result < 0) ? "error" : "success msg",
+ (result < 0) ? result : num);
+
+ return (result < 0) ? result : num;
+}
+
+static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_id;
+ unsigned int temp;
+
+ lpi2c_imx_intctrl(lpi2c_imx, 0);
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+
+ if (temp & MSR_RDF)
+ lpi2c_imx_read_rxfifo(lpi2c_imx);
+
+ if (temp & MSR_TDF)
+ lpi2c_imx_write_txfifo(lpi2c_imx);
+
+ if (temp & MSR_NDF)
+ complete(&lpi2c_imx->complete);
+
+ return IRQ_HANDLED;
+}
+
+static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm lpi2c_imx_algo = {
+ .master_xfer = lpi2c_imx_xfer,
+ .functionality = lpi2c_imx_func,
+};
+
+static const struct of_device_id lpi2c_imx_of_match[] = {
+ { .compatible = "fsl,imx7ulp-lpi2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
+
+static int lpi2c_imx_probe(struct platform_device *pdev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx;
+ struct resource *res;
+ unsigned int temp;
+ int irq, ret;
+
+ lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
+ if (!lpi2c_imx)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ lpi2c_imx->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(lpi2c_imx->base))
+ return PTR_ERR(lpi2c_imx->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "can't get irq number\n");
+ return irq;
+ }
+
+ lpi2c_imx->adapter.owner = THIS_MODULE;
+ lpi2c_imx->adapter.algo = &lpi2c_imx_algo;
+ lpi2c_imx->adapter.dev.parent = &pdev->dev;
+ lpi2c_imx->adapter.dev.of_node = pdev->dev.of_node;
+ strlcpy(lpi2c_imx->adapter.name, pdev->name,
+ sizeof(lpi2c_imx->adapter.name));
+
+ lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(lpi2c_imx->clk)) {
+ dev_err(&pdev->dev, "can't get I2C peripheral clock\n");
+ return PTR_ERR(lpi2c_imx->clk);
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &lpi2c_imx->bitrate);
+ if (ret)
+ lpi2c_imx->bitrate = LPI2C_DEFAULT_RATE;
+
+ ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0,
+ pdev->name, lpi2c_imx);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", irq);
+ return ret;
+ }
+
+ i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
+ platform_set_drvdata(pdev, lpi2c_imx);
+
+ ret = clk_prepare_enable(lpi2c_imx->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk enable failed %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ temp = readl(lpi2c_imx->base + LPI2C_PARAM);
+ lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
+ lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
+
+ ret = i2c_add_adapter(&lpi2c_imx->adapter);
+ if (ret)
+ goto rpm_disable;
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
+ dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
+
+ return 0;
+
+rpm_disable:
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+ return ret;
+}
+
+static int lpi2c_imx_remove(struct platform_device *pdev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&lpi2c_imx->adapter);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int lpi2c_runtime_suspend(struct device *dev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(lpi2c_imx->clk);
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int lpi2c_runtime_resume(struct device *dev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ pinctrl_pm_select_default_state(dev);
+ ret = clk_prepare_enable(lpi2c_imx->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops lpi2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
+ lpi2c_runtime_resume, NULL)
+};
+#define IMX_LPI2C_PM (&lpi2c_pm_ops)
+#else
+#define IMX_LPI2C_PM NULL
+#endif
+
+static struct platform_driver lpi2c_imx_driver = {
+ .probe = lpi2c_imx_probe,
+ .remove = lpi2c_imx_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = lpi2c_imx_of_match,
+ .pm = IMX_LPI2C_PM,
+ },
+};
+
+module_platform_driver(lpi2c_imx_driver);
+
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
new file mode 100644
index 000000000..83c246e30
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -0,0 +1,1301 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2002 Motorola GSG-China
+ *
+ * Author:
+ * Darius Augulis, Teltonika Inc.
+ *
+ * Desc.:
+ * Implementation of I2C Adapter/Algorithm Driver
+ * for I2C Bus integrated in Freescale i.MX/MXC processors
+ *
+ * Derived from Motorola GSG China I2C example driver
+ *
+ * Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de
+ * Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de
+ * Copyright (C) 2007 RightHand Technologies, Inc.
+ * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/i2c-imx.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+/* This will be the driver name the kernel reports */
+#define DRIVER_NAME "imx-i2c"
+
+/* Default value */
+#define IMX_I2C_BIT_RATE 100000 /* 100kHz */
+
+/*
+ * Enable DMA if transfer byte size is bigger than this threshold.
+ * As the hardware request, it must bigger than 4 bytes.\
+ * I have set '16' here, maybe it's not the best but I think it's
+ * the appropriate.
+ */
+#define DMA_THRESHOLD 16
+#define DMA_TIMEOUT 1000
+
+/* IMX I2C registers:
+ * the I2C register offset is different between SoCs,
+ * to provid support for all these chips, split the
+ * register offset into a fixed base address and a
+ * variable shift value, then the full register offset
+ * will be calculated by
+ * reg_off = ( reg_base_addr << reg_shift)
+ */
+#define IMX_I2C_IADR 0x00 /* i2c slave address */
+#define IMX_I2C_IFDR 0x01 /* i2c frequency divider */
+#define IMX_I2C_I2CR 0x02 /* i2c control */
+#define IMX_I2C_I2SR 0x03 /* i2c status */
+#define IMX_I2C_I2DR 0x04 /* i2c transfer data */
+
+#define IMX_I2C_REGSHIFT 2
+#define VF610_I2C_REGSHIFT 0
+
+/* Bits of IMX I2C registers */
+#define I2SR_RXAK 0x01
+#define I2SR_IIF 0x02
+#define I2SR_SRW 0x04
+#define I2SR_IAL 0x10
+#define I2SR_IBB 0x20
+#define I2SR_IAAS 0x40
+#define I2SR_ICF 0x80
+#define I2CR_DMAEN 0x02
+#define I2CR_RSTA 0x04
+#define I2CR_TXAK 0x08
+#define I2CR_MTX 0x10
+#define I2CR_MSTA 0x20
+#define I2CR_IIEN 0x40
+#define I2CR_IEN 0x80
+
+/* register bits different operating codes definition:
+ * 1) I2SR: Interrupt flags clear operation differ between SoCs:
+ * - write zero to clear(w0c) INT flag on i.MX,
+ * - but write one to clear(w1c) INT flag on Vybrid.
+ * 2) I2CR: I2C module enable operation also differ between SoCs:
+ * - set I2CR_IEN bit enable the module on i.MX,
+ * - but clear I2CR_IEN bit enable the module on Vybrid.
+ */
+#define I2SR_CLR_OPCODE_W0C 0x0
+#define I2SR_CLR_OPCODE_W1C (I2SR_IAL | I2SR_IIF)
+#define I2CR_IEN_OPCODE_0 0x0
+#define I2CR_IEN_OPCODE_1 I2CR_IEN
+
+#define I2C_PM_TIMEOUT 10 /* ms */
+
+/*
+ * sorted list of clock divider, register value pairs
+ * taken from table 26-5, p.26-9, Freescale i.MX
+ * Integrated Portable System Processor Reference Manual
+ * Document Number: MC9328MXLRM, Rev. 5.1, 06/2007
+ *
+ * Duplicated divider values removed from list
+ */
+struct imx_i2c_clk_pair {
+ u16 div;
+ u16 val;
+};
+
+static struct imx_i2c_clk_pair imx_i2c_clk_div[] = {
+ { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
+ { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
+ { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
+ { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B },
+ { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A },
+ { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 },
+ { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 },
+ { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 },
+ { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 },
+ { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B },
+ { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
+ { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
+ { 3072, 0x1E }, { 3840, 0x1F }
+};
+
+/* Vybrid VF610 clock divider, register value pairs */
+static struct imx_i2c_clk_pair vf610_i2c_clk_div[] = {
+ { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
+ { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 },
+ { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D },
+ { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 },
+ { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 },
+ { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 },
+ { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 },
+ { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 },
+ { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 },
+ { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
+ { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 },
+ { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 },
+ { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B },
+ { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A },
+ { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
+};
+
+enum imx_i2c_type {
+ IMX1_I2C,
+ IMX21_I2C,
+ VF610_I2C,
+};
+
+struct imx_i2c_hwdata {
+ enum imx_i2c_type devtype;
+ unsigned regshift;
+ struct imx_i2c_clk_pair *clk_div;
+ unsigned ndivs;
+ unsigned i2sr_clr_opcode;
+ unsigned i2cr_ien_opcode;
+};
+
+struct imx_i2c_dma {
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_using;
+ struct completion cmd_complete;
+ dma_addr_t dma_buf;
+ unsigned int dma_len;
+ enum dma_transfer_direction dma_transfer_dir;
+ enum dma_data_direction dma_data_dir;
+};
+
+struct imx_i2c_struct {
+ struct i2c_adapter adapter;
+ struct clk *clk;
+ struct notifier_block clk_change_nb;
+ void __iomem *base;
+ wait_queue_head_t queue;
+ unsigned long i2csr;
+ unsigned int disable_delay;
+ int stopped;
+ unsigned int ifdr; /* IMX_I2C_IFDR */
+ unsigned int cur_clk;
+ unsigned int bitrate;
+ const struct imx_i2c_hwdata *hwdata;
+ struct i2c_bus_recovery_info rinfo;
+
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_pins_default;
+ struct pinctrl_state *pinctrl_pins_gpio;
+
+ struct imx_i2c_dma *dma;
+};
+
+static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
+ .devtype = IMX1_I2C,
+ .regshift = IMX_I2C_REGSHIFT,
+ .clk_div = imx_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(imx_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
+
+};
+
+static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
+ .devtype = IMX21_I2C,
+ .regshift = IMX_I2C_REGSHIFT,
+ .clk_div = imx_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(imx_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
+
+};
+
+static struct imx_i2c_hwdata vf610_i2c_hwdata = {
+ .devtype = VF610_I2C,
+ .regshift = VF610_I2C_REGSHIFT,
+ .clk_div = vf610_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(vf610_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_0,
+
+};
+
+static const struct platform_device_id imx_i2c_devtype[] = {
+ {
+ .name = "imx1-i2c",
+ .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
+ }, {
+ .name = "imx21-i2c",
+ .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
+
+static const struct of_device_id i2c_imx_dt_ids[] = {
+ { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
+ { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
+ { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
+
+static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
+{
+ return i2c_imx->hwdata->devtype == IMX1_I2C;
+}
+
+static inline void imx_i2c_write_reg(unsigned int val,
+ struct imx_i2c_struct *i2c_imx, unsigned int reg)
+{
+ writeb(val, i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
+}
+
+static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
+ unsigned int reg)
+{
+ return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
+}
+
+/* Functions for DMA support */
+static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
+ dma_addr_t phy_addr)
+{
+ struct imx_i2c_dma *dma;
+ struct dma_slave_config dma_sconfig;
+ struct device *dev = &i2c_imx->adapter.dev;
+ int ret;
+
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return;
+
+ dma->chan_tx = dma_request_slave_channel(dev, "tx");
+ if (!dma->chan_tx) {
+ dev_dbg(dev, "can't request DMA tx channel\n");
+ goto fail_al;
+ }
+
+ dma_sconfig.dst_addr = phy_addr +
+ (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
+ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconfig.dst_maxburst = 1;
+ dma_sconfig.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
+ if (ret < 0) {
+ dev_dbg(dev, "can't configure tx channel\n");
+ goto fail_tx;
+ }
+
+ dma->chan_rx = dma_request_slave_channel(dev, "rx");
+ if (!dma->chan_rx) {
+ dev_dbg(dev, "can't request DMA rx channel\n");
+ goto fail_tx;
+ }
+
+ dma_sconfig.src_addr = phy_addr +
+ (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconfig.src_maxburst = 1;
+ dma_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
+ if (ret < 0) {
+ dev_dbg(dev, "can't configure rx channel\n");
+ goto fail_rx;
+ }
+
+ i2c_imx->dma = dma;
+ init_completion(&dma->cmd_complete);
+ dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+ return;
+
+fail_rx:
+ dma_release_channel(dma->chan_rx);
+fail_tx:
+ dma_release_channel(dma->chan_tx);
+fail_al:
+ devm_kfree(dev, dma);
+ dev_info(dev, "can't use DMA, using PIO instead.\n");
+}
+
+static void i2c_imx_dma_callback(void *arg)
+{
+ struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg;
+ struct imx_i2c_dma *dma = i2c_imx->dma;
+
+ dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
+ dma->dma_len, dma->dma_data_dir);
+ complete(&dma->cmd_complete);
+}
+
+static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
+ struct i2c_msg *msgs)
+{
+ struct imx_i2c_dma *dma = i2c_imx->dma;
+ struct dma_async_tx_descriptor *txdesc;
+ struct device *dev = &i2c_imx->adapter.dev;
+ struct device *chan_dev = dma->chan_using->device->dev;
+
+ dma->dma_buf = dma_map_single(chan_dev, msgs->buf,
+ dma->dma_len, dma->dma_data_dir);
+ if (dma_mapping_error(chan_dev, dma->dma_buf)) {
+ dev_err(dev, "DMA mapping failed\n");
+ goto err_map;
+ }
+
+ txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
+ dma->dma_len, dma->dma_transfer_dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc) {
+ dev_err(dev, "Not able to get desc for DMA xfer\n");
+ goto err_desc;
+ }
+
+ reinit_completion(&dma->cmd_complete);
+ txdesc->callback = i2c_imx_dma_callback;
+ txdesc->callback_param = i2c_imx;
+ if (dma_submit_error(dmaengine_submit(txdesc))) {
+ dev_err(dev, "DMA submit failed\n");
+ goto err_submit;
+ }
+
+ dma_async_issue_pending(dma->chan_using);
+ return 0;
+
+err_submit:
+ dmaengine_terminate_all(dma->chan_using);
+err_desc:
+ dma_unmap_single(chan_dev, dma->dma_buf,
+ dma->dma_len, dma->dma_data_dir);
+err_map:
+ return -EINVAL;
+}
+
+static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
+{
+ struct imx_i2c_dma *dma = i2c_imx->dma;
+
+ dma->dma_buf = 0;
+ dma->dma_len = 0;
+
+ dma_release_channel(dma->chan_tx);
+ dma->chan_tx = NULL;
+
+ dma_release_channel(dma->chan_rx);
+ dma->chan_rx = NULL;
+
+ dma->chan_using = NULL;
+}
+
+static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
+{
+ unsigned int temp;
+
+ /*
+ * i2sr_clr_opcode is the value to clear all interrupts. Here we want to
+ * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
+ * toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
+ */
+ temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
+}
+
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
+{
+ unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ while (1) {
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+
+ /* check for arbitration lost */
+ if (temp & I2SR_IAL) {
+ i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
+ return -EAGAIN;
+ }
+
+ if (for_busy && (temp & I2SR_IBB)) {
+ i2c_imx->stopped = 0;
+ break;
+ }
+ if (!for_busy && !(temp & I2SR_IBB)) {
+ i2c_imx->stopped = 1;
+ break;
+ }
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> I2C bus is busy\n", __func__);
+ return -ETIMEDOUT;
+ }
+ schedule();
+ }
+
+ return 0;
+}
+
+static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
+{
+ wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
+
+ if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* check for arbitration lost */
+ if (i2c_imx->i2csr & I2SR_IAL) {
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__);
+ i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
+
+ i2c_imx->i2csr = 0;
+ return -EAGAIN;
+ }
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
+ i2c_imx->i2csr = 0;
+ return 0;
+}
+
+static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
+{
+ if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) {
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
+ return -ENXIO; /* No ACK */
+ }
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
+ return 0;
+}
+
+static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+ unsigned int i2c_clk_rate)
+{
+ struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
+ unsigned int div;
+ int i;
+
+ /* Divider value calculation */
+ if (i2c_imx->cur_clk == i2c_clk_rate)
+ return;
+
+ i2c_imx->cur_clk = i2c_clk_rate;
+
+ div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
+ if (div < i2c_clk_div[0].div)
+ i = 0;
+ else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
+ i = i2c_imx->hwdata->ndivs - 1;
+ else
+ for (i = 0; i2c_clk_div[i].div < div; i++)
+ ;
+
+ /* Store divider value */
+ i2c_imx->ifdr = i2c_clk_div[i].val;
+
+ /*
+ * There dummy delay is calculated.
+ * It should be about one I2C clock period long.
+ * This delay is used in I2C bus disable function
+ * to fix chip hardware bug.
+ */
+ i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div
+ + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
+
+#ifdef CONFIG_I2C_DEBUG_BUS
+ dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n",
+ i2c_clk_rate, div);
+ dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n",
+ i2c_clk_div[i].val, i2c_clk_div[i].div);
+#endif
+}
+
+static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct imx_i2c_struct *i2c_imx = container_of(nb,
+ struct imx_i2c_struct,
+ clk_change_nb);
+
+ if (action & POST_RATE_CHANGE)
+ i2c_imx_set_clk(i2c_imx, ndata->new_rate);
+
+ return NOTIFY_OK;
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+ unsigned int temp = 0;
+ int result;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
+ /* Enable I2C controller */
+ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
+
+ /* Wait controller to be stable */
+ usleep_range(50, 150);
+
+ /* Start I2C transaction */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_MSTA;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ result = i2c_imx_bus_busy(i2c_imx, 1);
+ if (result)
+ return result;
+
+ temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
+ temp &= ~I2CR_DMAEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ return result;
+}
+
+static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+{
+ unsigned int temp = 0;
+
+ if (!i2c_imx->stopped) {
+ /* Stop I2C transaction */
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (!(temp & I2CR_MSTA))
+ i2c_imx->stopped = 1;
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ if (i2c_imx->dma)
+ temp &= ~I2CR_DMAEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ }
+ if (is_imx1_i2c(i2c_imx)) {
+ /*
+ * This delay caused by an i.MXL hardware bug.
+ * If no (or too short) delay, no "STOP" bit will be generated.
+ */
+ udelay(i2c_imx->disable_delay);
+ }
+
+ if (!i2c_imx->stopped)
+ i2c_imx_bus_busy(i2c_imx, 0);
+
+ /* Disable I2C controller */
+ temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+}
+
+static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
+{
+ struct imx_i2c_struct *i2c_imx = dev_id;
+ unsigned int temp;
+
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+ if (temp & I2SR_IIF) {
+ /* save status register */
+ i2c_imx->i2csr = temp;
+ i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
+ wake_up(&i2c_imx->queue);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
+ struct i2c_msg *msgs)
+{
+ int result;
+ unsigned long time_left;
+ unsigned int temp = 0;
+ unsigned long orig_jiffies = jiffies;
+ struct imx_i2c_dma *dma = i2c_imx->dma;
+ struct device *dev = &i2c_imx->adapter.dev;
+
+ dma->chan_using = dma->chan_tx;
+ dma->dma_transfer_dir = DMA_MEM_TO_DEV;
+ dma->dma_data_dir = DMA_TO_DEVICE;
+ dma->dma_len = msgs->len - 1;
+ result = i2c_imx_dma_xfer(i2c_imx, msgs);
+ if (result)
+ return result;
+
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_DMAEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ /*
+ * Write slave address.
+ * The first byte must be transmitted by the CPU.
+ */
+ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
+ time_left = wait_for_completion_timeout(
+ &i2c_imx->dma->cmd_complete,
+ msecs_to_jiffies(DMA_TIMEOUT));
+ if (time_left == 0) {
+ dmaengine_terminate_all(dma->chan_using);
+ return -ETIMEDOUT;
+ }
+
+ /* Waiting for transfer complete. */
+ while (1) {
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+ if (temp & I2SR_ICF)
+ break;
+ if (time_after(jiffies, orig_jiffies +
+ msecs_to_jiffies(DMA_TIMEOUT))) {
+ dev_dbg(dev, "<%s> Timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ schedule();
+ }
+
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp &= ~I2CR_DMAEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ /* The last data byte must be transferred by the CPU. */
+ imx_i2c_write_reg(msgs->buf[msgs->len-1],
+ i2c_imx, IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+
+ return i2c_imx_acked(i2c_imx);
+}
+
+static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
+ struct i2c_msg *msgs, bool is_lastmsg)
+{
+ int result;
+ unsigned long time_left;
+ unsigned int temp;
+ unsigned long orig_jiffies = jiffies;
+ struct imx_i2c_dma *dma = i2c_imx->dma;
+ struct device *dev = &i2c_imx->adapter.dev;
+
+
+ dma->chan_using = dma->chan_rx;
+ dma->dma_transfer_dir = DMA_DEV_TO_MEM;
+ dma->dma_data_dir = DMA_FROM_DEVICE;
+ /* The last two data bytes must be transferred by the CPU. */
+ dma->dma_len = msgs->len - 2;
+ result = i2c_imx_dma_xfer(i2c_imx, msgs);
+ if (result)
+ return result;
+
+ time_left = wait_for_completion_timeout(
+ &i2c_imx->dma->cmd_complete,
+ msecs_to_jiffies(DMA_TIMEOUT));
+ if (time_left == 0) {
+ dmaengine_terminate_all(dma->chan_using);
+ return -ETIMEDOUT;
+ }
+
+ /* waiting for transfer complete. */
+ while (1) {
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+ if (temp & I2SR_ICF)
+ break;
+ if (time_after(jiffies, orig_jiffies +
+ msecs_to_jiffies(DMA_TIMEOUT))) {
+ dev_dbg(dev, "<%s> Timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ schedule();
+ }
+
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp &= ~I2CR_DMAEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ /* read n-1 byte data */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_TXAK;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ /* read n byte data */
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+
+ if (is_lastmsg) {
+ /*
+ * It must generate STOP before read I2DR to prevent
+ * controller from generating another clock cycle
+ */
+ dev_dbg(dev, "<%s> clear MSTA\n", __func__);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (!(temp & I2CR_MSTA))
+ i2c_imx->stopped = 1;
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ if (!i2c_imx->stopped)
+ i2c_imx_bus_busy(i2c_imx, 0);
+ } else {
+ /*
+ * For i2c master receiver repeat restart operation like:
+ * read -> repeat MSTA -> read/write
+ * The controller must set MTX before read the last byte in
+ * the first read operation, otherwise the first read cost
+ * one extra clock cycle.
+ */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_MTX;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ }
+ msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+
+ return 0;
+}
+
+static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+{
+ int i, result;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
+ __func__, i2c_8bit_addr_from_msg(msgs));
+
+ /* write slave address */
+ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ result = i2c_imx_acked(i2c_imx);
+ if (result)
+ return result;
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> write data\n", __func__);
+
+ /* write data */
+ for (i = 0; i < msgs->len; i++) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> write byte: B%d=0x%X\n",
+ __func__, i, msgs->buf[i]);
+ imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ result = i2c_imx_acked(i2c_imx);
+ if (result)
+ return result;
+ }
+ return 0;
+}
+
+static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg)
+{
+ int i, result;
+ unsigned int temp;
+ int block_data = msgs->flags & I2C_M_RECV_LEN;
+ int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data;
+
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> write slave address: addr=0x%x\n",
+ __func__, i2c_8bit_addr_from_msg(msgs));
+
+ /* write slave address */
+ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ result = i2c_imx_acked(i2c_imx);
+ if (result)
+ return result;
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
+
+ /* setup bus to read data */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp &= ~I2CR_MTX;
+
+ /*
+ * Reset the I2CR_TXAK flag initially for SMBus block read since the
+ * length is unknown
+ */
+ if ((msgs->len - 1) || block_data)
+ temp &= ~I2CR_TXAK;
+ if (use_dma)
+ temp |= I2CR_DMAEN;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
+
+ if (use_dma)
+ return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg);
+
+ /* read data */
+ for (i = 0; i < msgs->len; i++) {
+ u8 len = 0;
+
+ result = i2c_imx_trx_complete(i2c_imx);
+ if (result)
+ return result;
+ /*
+ * First byte is the length of remaining packet
+ * in the SMBus block data read. Add it to
+ * msgs->len.
+ */
+ if ((!i) && block_data) {
+ len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
+ return -EPROTO;
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> read length: 0x%X\n",
+ __func__, len);
+ msgs->len += len;
+ }
+ if (i == (msgs->len - 1)) {
+ if (is_lastmsg) {
+ /*
+ * It must generate STOP before read I2DR to prevent
+ * controller from generating another clock cycle
+ */
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> clear MSTA\n", __func__);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ if (!(temp & I2CR_MSTA))
+ i2c_imx->stopped = 1;
+ temp &= ~(I2CR_MSTA | I2CR_MTX);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ if (!i2c_imx->stopped)
+ i2c_imx_bus_busy(i2c_imx, 0);
+ } else {
+ /*
+ * For i2c master receiver repeat restart operation like:
+ * read -> repeat MSTA -> read/write
+ * The controller must set MTX before read the last byte in
+ * the first read operation, otherwise the first read cost
+ * one extra clock cycle.
+ */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_MTX;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ }
+ } else if (i == (msgs->len - 2)) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> set TXAK\n", __func__);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_TXAK;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ }
+ if ((!i) && block_data)
+ msgs->buf[0] = len;
+ else
+ msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> read byte: B%d=0x%X\n",
+ __func__, i, msgs->buf[i]);
+ }
+ return 0;
+}
+
+static int i2c_imx_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ unsigned int i, temp;
+ int result;
+ bool is_lastmsg = false;
+ struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
+
+ dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
+ if (result < 0)
+ goto out;
+
+ /* Start I2C transfer */
+ result = i2c_imx_start(i2c_imx);
+ if (result) {
+ if (i2c_imx->adapter.bus_recovery_info) {
+ i2c_recover_bus(&i2c_imx->adapter);
+ result = i2c_imx_start(i2c_imx);
+ }
+ }
+
+ if (result)
+ goto fail0;
+
+ /* read/write data */
+ for (i = 0; i < num; i++) {
+ if (i == num - 1)
+ is_lastmsg = true;
+
+ if (i) {
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> repeated start\n", __func__);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_RSTA;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ result = i2c_imx_bus_busy(i2c_imx, 1);
+ if (result)
+ goto fail0;
+ }
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> transfer message: %d\n", __func__, i);
+ /* write/read data */
+#ifdef CONFIG_I2C_DEBUG_BUS
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
+ __func__,
+ (temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
+ (temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
+ (temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
+ __func__,
+ (temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
+ (temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
+ (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
+ (temp & I2SR_RXAK ? 1 : 0));
+#endif
+ if (msgs[i].flags & I2C_M_RD)
+ result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);
+ else {
+ if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
+ result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
+ else
+ result = i2c_imx_write(i2c_imx, &msgs[i]);
+ }
+ if (result)
+ goto fail0;
+ }
+
+fail0:
+ /* Stop I2C transfer */
+ i2c_imx_stop(i2c_imx);
+
+ pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
+
+out:
+ dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+ (result < 0) ? "error" : "success msg",
+ (result < 0) ? result : num);
+ return (result < 0) ? result : num;
+}
+
+static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct imx_i2c_struct *i2c_imx;
+
+ i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+ pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
+}
+
+static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct imx_i2c_struct *i2c_imx;
+
+ i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+ pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
+}
+
+/*
+ * We switch SCL and SDA to their GPIO function and do some bitbanging
+ * for bus recovery. These alternative pinmux settings can be
+ * described in the device tree by a separate pinctrl state "gpio". If
+ * this is missing this is not a big problem, the only implication is
+ * that we can't do bus recovery.
+ */
+static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
+ struct platform_device *pdev)
+{
+ struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
+
+ i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!i2c_imx->pinctrl || IS_ERR(i2c_imx->pinctrl)) {
+ dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
+ return PTR_ERR(i2c_imx->pinctrl);
+ }
+
+ i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
+ "gpio");
+ rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
+ rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
+
+ if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
+ PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else if (IS_ERR(rinfo->sda_gpiod) ||
+ IS_ERR(rinfo->scl_gpiod) ||
+ IS_ERR(i2c_imx->pinctrl_pins_default) ||
+ IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
+ dev_dbg(&pdev->dev, "recovery information incomplete\n");
+ return 0;
+ }
+
+ dev_dbg(&pdev->dev, "using scl%s for recovery\n",
+ rinfo->sda_gpiod ? ",sda" : "");
+
+ rinfo->prepare_recovery = i2c_imx_prepare_recovery;
+ rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
+ rinfo->recover_bus = i2c_generic_scl_recovery;
+ i2c_imx->adapter.bus_recovery_info = rinfo;
+
+ return 0;
+}
+
+static u32 i2c_imx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm i2c_imx_algo = {
+ .master_xfer = i2c_imx_xfer,
+ .functionality = i2c_imx_func,
+};
+
+static int i2c_imx_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,
+ &pdev->dev);
+ struct imx_i2c_struct *i2c_imx;
+ struct resource *res;
+ struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ void __iomem *base;
+ int irq, ret;
+ dma_addr_t phy_addr;
+
+ dev_dbg(&pdev->dev, "<%s>\n", __func__);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "can't get irq number\n");
+ return irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ phy_addr = (dma_addr_t)res->start;
+ i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);
+ if (!i2c_imx)
+ return -ENOMEM;
+
+ if (of_id)
+ i2c_imx->hwdata = of_id->data;
+ else
+ i2c_imx->hwdata = (struct imx_i2c_hwdata *)
+ platform_get_device_id(pdev)->driver_data;
+
+ /* Setup i2c_imx driver structure */
+ strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
+ i2c_imx->adapter.owner = THIS_MODULE;
+ i2c_imx->adapter.algo = &i2c_imx_algo;
+ i2c_imx->adapter.dev.parent = &pdev->dev;
+ i2c_imx->adapter.nr = pdev->id;
+ i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
+ i2c_imx->base = base;
+
+ /* Get I2C clock */
+ i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_imx->clk)) {
+ if (PTR_ERR(i2c_imx->clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "can't get I2C clock\n");
+ return PTR_ERR(i2c_imx->clk);
+ }
+
+ ret = clk_prepare_enable(i2c_imx->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret);
+ return ret;
+ }
+
+ /* Init queue */
+ init_waitqueue_head(&i2c_imx->queue);
+
+ /* Set up adapter data */
+ i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
+
+ /* Set up platform driver data */
+ platform_set_drvdata(pdev, i2c_imx);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto rpm_disable;
+
+ /* Request IRQ */
+ ret = request_threaded_irq(irq, i2c_imx_isr, NULL, IRQF_SHARED,
+ pdev->name, i2c_imx);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", irq);
+ goto rpm_disable;
+ }
+
+ /* Set up clock divider */
+ i2c_imx->bitrate = IMX_I2C_BIT_RATE;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &i2c_imx->bitrate);
+ if (ret < 0 && pdata && pdata->bitrate)
+ i2c_imx->bitrate = pdata->bitrate;
+ i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call;
+ clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
+ i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
+
+ /* Set up chip registers to defaults */
+ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+
+ /* Init optional bus recovery function */
+ ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
+ /* Give it another chance if pinctrl used is not ready yet */
+ if (ret == -EPROBE_DEFER)
+ goto clk_notifier_unregister;
+
+ /* Add I2C adapter */
+ ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
+ if (ret < 0)
+ goto clk_notifier_unregister;
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
+ dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
+ dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
+ dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
+ i2c_imx->adapter.name);
+ dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
+
+ /* Init DMA config if supported */
+ i2c_imx_dma_request(i2c_imx, phy_addr);
+
+ return 0; /* Return OK */
+
+clk_notifier_unregister:
+ clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+ free_irq(irq, i2c_imx);
+rpm_disable:
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ clk_disable_unprepare(i2c_imx->clk);
+ return ret;
+}
+
+static int i2c_imx_remove(struct platform_device *pdev)
+{
+ struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
+ int irq, ret;
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ /* remove adapter */
+ dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
+ i2c_del_adapter(&i2c_imx->adapter);
+
+ if (i2c_imx->dma)
+ i2c_imx_dma_free(i2c_imx);
+
+ /* setup chip registers to defaults */
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
+
+ clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0)
+ free_irq(irq, i2c_imx);
+ clk_disable_unprepare(i2c_imx->clk);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_imx_runtime_suspend(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+
+ clk_disable(i2c_imx->clk);
+
+ return 0;
+}
+
+static int i2c_imx_runtime_resume(struct device *dev)
+{
+ struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(i2c_imx->clk);
+ if (ret)
+ dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
+
+ return ret;
+}
+
+static const struct dev_pm_ops i2c_imx_pm_ops = {
+ SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
+ i2c_imx_runtime_resume, NULL)
+};
+#define I2C_IMX_PM_OPS (&i2c_imx_pm_ops)
+#else
+#define I2C_IMX_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver i2c_imx_driver = {
+ .probe = i2c_imx_probe,
+ .remove = i2c_imx_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = I2C_IMX_PM_OPS,
+ .of_match_table = i2c_imx_dt_ids,
+ },
+ .id_table = imx_i2c_devtype,
+};
+
+static int __init i2c_adap_imx_init(void)
+{
+ return platform_driver_register(&i2c_imx_driver);
+}
+subsys_initcall(i2c_adap_imx_init);
+
+static void __exit i2c_adap_imx_exit(void)
+{
+ platform_driver_unregister(&i2c_imx_driver);
+}
+module_exit(i2c_adap_imx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Darius Augulis");
+MODULE_DESCRIPTION("I2C adapter driver for IMX I2C bus");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
new file mode 100644
index 000000000..d4fe7cccc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -0,0 +1,523 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx & IXP46x */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ * <Peter dot Milne at D hyphen TACQ dot com>
+ *
+ * With acknowledgements to i2c-algo-ibm_ocp.c by
+ * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
+ *
+ * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
+ *
+ * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
+ *
+ * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
+ *
+ * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005:
+ *
+ * - Use driver model to pass per-chip info instead of hardcoding and #ifdefs
+ * - Use ioremap/__raw_readl/__raw_writel instead of direct dereference
+ * - Make it work with IXP46x chips
+ * - Cleanup function names, coding style, etc
+ *
+ * - writing to slave address causes latchup on iop331.
+ * fix: driver refuses to address self.
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include "i2c-iop3xx.h"
+
+/* global unit counter */
+static int i2c_id;
+
+static inline unsigned char
+iic_cook_addr(struct i2c_msg *msg)
+{
+ unsigned char addr;
+
+ addr = i2c_8bit_addr_from_msg(msg);
+
+ return addr;
+}
+
+static void
+iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ /* Follows devman 9.3 */
+ __raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET);
+ __raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET);
+ __raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+static void
+iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
+
+ /*
+ * Every time unit enable is asserted, GPOD needs to be cleared
+ * on IOP3XX to avoid data corruption on the bus.
+ */
+#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
+ if (iop3xx_adap->id == 0) {
+ gpio_set_value(7, 0);
+ gpio_set_value(6, 0);
+ } else {
+ gpio_set_value(5, 0);
+ gpio_set_value(4, 0);
+ }
+#endif
+ /* NB SR bits not same position as CR IE bits :-( */
+ iop3xx_adap->SR_enabled =
+ IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
+ IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY;
+
+ cr |= IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+ IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE;
+
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+static void
+iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+
+ cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE |
+ IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN);
+
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+/*
+ * NB: the handler has to clear the source of the interrupt!
+ * Then it passes the SR flags of interest to BH via adap data
+ */
+static irqreturn_t
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
+ u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
+
+ if ((sr &= iop3xx_adap->SR_enabled)) {
+ __raw_writel(sr, iop3xx_adap->ioaddr + SR_OFFSET);
+ iop3xx_adap->SR_received |= sr;
+ wake_up_interruptible(&iop3xx_adap->waitq);
+ }
+ return IRQ_HANDLED;
+}
+
+/* check all error conditions, clear them , report most important */
+static int
+iop3xx_i2c_error(u32 sr)
+{
+ int rc = 0;
+
+ if ((sr & IOP3XX_ISR_BERRD)) {
+ if ( !rc ) rc = -I2C_ERR_BERR;
+ }
+ if ((sr & IOP3XX_ISR_ALD)) {
+ if ( !rc ) rc = -I2C_ERR_ALD;
+ }
+ return rc;
+}
+
+static inline u32
+iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+ unsigned long flags;
+ u32 sr;
+
+ spin_lock_irqsave(&iop3xx_adap->lock, flags);
+ sr = iop3xx_adap->SR_received;
+ iop3xx_adap->SR_received = 0;
+ spin_unlock_irqrestore(&iop3xx_adap->lock, flags);
+
+ return sr;
+}
+
+/*
+ * sleep until interrupted, then recover and analyse the SR
+ * saved by handler
+ */
+typedef int (* compare_func)(unsigned test, unsigned mask);
+/* returns 1 on correct comparison */
+
+static int
+iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ unsigned flags, unsigned* status,
+ compare_func compare)
+{
+ unsigned sr = 0;
+ int interrupted;
+ int done;
+ int rc = 0;
+
+ do {
+ interrupted = wait_event_interruptible_timeout (
+ iop3xx_adap->waitq,
+ (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )),
+ 1 * HZ
+ );
+ if ((rc = iop3xx_i2c_error(sr)) < 0) {
+ *status = sr;
+ return rc;
+ } else if (!interrupted) {
+ *status = sr;
+ return -ETIMEDOUT;
+ }
+ } while(!done);
+
+ *status = sr;
+
+ return 0;
+}
+
+/*
+ * Concrete compare_funcs
+ */
+static int
+all_bits_clear(unsigned test, unsigned mask)
+{
+ return (test & mask) == 0;
+}
+
+static int
+any_bits_set(unsigned test, unsigned mask)
+{
+ return (test & mask) != 0;
+}
+
+static int
+iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_i2c_wait_event(
+ iop3xx_adap,
+ IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
+ status, any_bits_set);
+}
+
+static int
+iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_i2c_wait_event(
+ iop3xx_adap,
+ IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
+ status, any_bits_set);
+}
+
+static int
+iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+ return iop3xx_i2c_wait_event(
+ iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear);
+}
+
+static int
+iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
+ struct i2c_msg* msg)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+ int status;
+ int rc;
+
+ /* avoid writing to my slave address (hangs on 80331),
+ * forbidden in Intel developer manual
+ */
+ if (msg->addr == MYSAR) {
+ return -EBUSY;
+ }
+
+ __raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
+
+ cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
+ cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE;
+
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+ rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
+
+ return rc;
+}
+
+static int
+iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
+ int stop)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+ int status;
+ int rc = 0;
+
+ __raw_writel(byte, iop3xx_adap->ioaddr + DBR_OFFSET);
+ cr &= ~IOP3XX_ICR_MSTART;
+ if (stop) {
+ cr |= IOP3XX_ICR_MSTOP;
+ } else {
+ cr &= ~IOP3XX_ICR_MSTOP;
+ }
+ cr |= IOP3XX_ICR_TBYTE;
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+ rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
+
+ return rc;
+}
+
+static int
+iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
+ int stop)
+{
+ unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+ int status;
+ int rc = 0;
+
+ cr &= ~IOP3XX_ICR_MSTART;
+
+ if (stop) {
+ cr |= IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK;
+ } else {
+ cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
+ }
+ cr |= IOP3XX_ICR_TBYTE;
+ __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+
+ rc = iop3xx_i2c_wait_rx_done(iop3xx_adap, &status);
+
+ *byte = __raw_readl(iop3xx_adap->ioaddr + DBR_OFFSET);
+
+ return rc;
+}
+
+static int
+iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int ii;
+ int rc = 0;
+
+ for (ii = 0; rc == 0 && ii != count; ++ii)
+ rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
+ return rc;
+}
+
+static int
+iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int ii;
+ int rc = 0;
+
+ for (ii = 0; rc == 0 && ii != count; ++ii)
+ rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
+
+ return rc;
+}
+
+/*
+ * Description: This function implements combined transactions. Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * FROM THE SAME ADDRESS
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+static int
+iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int rc;
+
+ rc = iop3xx_i2c_send_target_addr(iop3xx_adap, pmsg);
+ if (rc < 0) {
+ return rc;
+ }
+
+ if ((pmsg->flags&I2C_M_RD)) {
+ return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len);
+ } else {
+ return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len);
+ }
+}
+
+/*
+ * master_xfer() - main read/write entry
+ */
+static int
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+ int im = 0;
+ int ret = 0;
+ int status;
+
+ iop3xx_i2c_wait_idle(iop3xx_adap, &status);
+ iop3xx_i2c_reset(iop3xx_adap);
+ iop3xx_i2c_enable(iop3xx_adap);
+
+ for (im = 0; ret == 0 && im != num; im++) {
+ ret = iop3xx_i2c_handle_msg(i2c_adap, &msgs[im]);
+ }
+
+ iop3xx_i2c_transaction_cleanup(iop3xx_adap);
+
+ if(ret)
+ return ret;
+
+ return im;
+}
+
+static u32
+iop3xx_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm iop3xx_i2c_algo = {
+ .master_xfer = iop3xx_i2c_master_xfer,
+ .functionality = iop3xx_i2c_func,
+};
+
+static int
+iop3xx_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *padapter = platform_get_drvdata(pdev);
+ struct i2c_algo_iop3xx_data *adapter_data =
+ (struct i2c_algo_iop3xx_data *)padapter->algo_data;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
+
+ /*
+ * Disable the actual HW unit
+ */
+ cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+ IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE);
+ __raw_writel(cr, adapter_data->ioaddr + CR_OFFSET);
+
+ iounmap(adapter_data->ioaddr);
+ release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
+ kfree(adapter_data);
+ kfree(padapter);
+
+ return 0;
+}
+
+static int
+iop3xx_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret, irq;
+ struct i2c_adapter *new_adapter;
+ struct i2c_algo_iop3xx_data *adapter_data;
+
+ new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!new_adapter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL);
+ if (!adapter_data) {
+ ret = -ENOMEM;
+ goto free_adapter;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto free_both;
+ }
+
+ if (!request_mem_region(res->start, IOP3XX_I2C_IO_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto free_both;
+ }
+
+ /* set the adapter enumeration # */
+ adapter_data->id = i2c_id++;
+
+ adapter_data->ioaddr = ioremap(res->start, IOP3XX_I2C_IO_SIZE);
+ if (!adapter_data->ioaddr) {
+ ret = -ENOMEM;
+ goto release_region;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto unmap;
+ }
+ ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
+ pdev->name, adapter_data);
+
+ if (ret)
+ goto unmap;
+
+ memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
+ new_adapter->owner = THIS_MODULE;
+ new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ new_adapter->dev.parent = &pdev->dev;
+ new_adapter->nr = pdev->id;
+
+ /*
+ * Default values...should these come in from board code?
+ */
+ new_adapter->timeout = HZ;
+ new_adapter->algo = &iop3xx_i2c_algo;
+
+ init_waitqueue_head(&adapter_data->waitq);
+ spin_lock_init(&adapter_data->lock);
+
+ iop3xx_i2c_reset(adapter_data);
+ iop3xx_i2c_enable(adapter_data);
+
+ platform_set_drvdata(pdev, new_adapter);
+ new_adapter->algo_data = adapter_data;
+
+ i2c_add_numbered_adapter(new_adapter);
+
+ return 0;
+
+unmap:
+ iounmap(adapter_data->ioaddr);
+
+release_region:
+ release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
+
+free_both:
+ kfree(adapter_data);
+
+free_adapter:
+ kfree(new_adapter);
+
+out:
+ return ret;
+}
+
+
+static struct platform_driver iop3xx_i2c_driver = {
+ .probe = iop3xx_i2c_probe,
+ .remove = iop3xx_i2c_remove,
+ .driver = {
+ .name = "IOP3xx-I2C",
+ },
+};
+
+module_platform_driver(iop3xx_i2c_driver);
+
+MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
+MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IOP3xx-I2C");
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
new file mode 100644
index 000000000..2d6929c2b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -0,0 +1,103 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ * <Peter dot Milne at D hyphen TACQ dot com>
+
+ 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 in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details. */
+/* ------------------------------------------------------------------------- */
+
+
+#ifndef I2C_IOP3XX_H
+#define I2C_IOP3XX_H 1
+
+/*
+ * iop321 hardware bit definitions
+ */
+#define IOP3XX_ICR_FAST_MODE 0x8000 /* 1=400kBps, 0=100kBps */
+#define IOP3XX_ICR_UNIT_RESET 0x4000 /* 1=RESET */
+#define IOP3XX_ICR_SAD_IE 0x2000 /* 1=Slave Detect Interrupt Enable */
+#define IOP3XX_ICR_ALD_IE 0x1000 /* 1=Arb Loss Detect Interrupt Enable */
+#define IOP3XX_ICR_SSD_IE 0x0800 /* 1=Slave STOP Detect Interrupt Enable */
+#define IOP3XX_ICR_BERR_IE 0x0400 /* 1=Bus Error Interrupt Enable */
+#define IOP3XX_ICR_RXFULL_IE 0x0200 /* 1=Receive Full Interrupt Enable */
+#define IOP3XX_ICR_TXEMPTY_IE 0x0100 /* 1=Transmit Empty Interrupt Enable */
+#define IOP3XX_ICR_GCD 0x0080 /* 1=General Call Disable */
+/*
+ * IOP3XX_ICR_GCD: 1 disables response as slave. "This bit must be set
+ * when sending a master mode general call message from the I2C unit"
+ */
+#define IOP3XX_ICR_UE 0x0040 /* 1=Unit Enable */
+/*
+ * "NOTE: To avoid I2C bus integrity problems,
+ * the user needs to ensure that the GPIO Output Data Register -
+ * GPOD bits associated with an I2C port are cleared prior to setting
+ * the enable bit for that I2C serial port.
+ * The user prepares to enable I2C port 0 and
+ * I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively.
+ */
+#define IOP3XX_ICR_SCLEN 0x0020 /* 1=SCL enable for master mode */
+#define IOP3XX_ICR_MABORT 0x0010 /* 1=Send a STOP with no data
+ * NB TBYTE must be clear */
+#define IOP3XX_ICR_TBYTE 0x0008 /* 1=Send/Receive a byte. i2c clears */
+#define IOP3XX_ICR_NACK 0x0004 /* 1=reply with NACK */
+#define IOP3XX_ICR_MSTOP 0x0002 /* 1=send a STOP after next data byte */
+#define IOP3XX_ICR_MSTART 0x0001 /* 1=initiate a START */
+
+
+#define IOP3XX_ISR_BERRD 0x0400 /* 1=BUS ERROR Detected */
+#define IOP3XX_ISR_SAD 0x0200 /* 1=Slave ADdress Detected */
+#define IOP3XX_ISR_GCAD 0x0100 /* 1=General Call Address Detected */
+#define IOP3XX_ISR_RXFULL 0x0080 /* 1=Receive Full */
+#define IOP3XX_ISR_TXEMPTY 0x0040 /* 1=Transmit Empty */
+#define IOP3XX_ISR_ALD 0x0020 /* 1=Arbitration Loss Detected */
+#define IOP3XX_ISR_SSD 0x0010 /* 1=Slave STOP Detected */
+#define IOP3XX_ISR_BBUSY 0x0008 /* 1=Bus BUSY */
+#define IOP3XX_ISR_UNITBUSY 0x0004 /* 1=Unit Busy */
+#define IOP3XX_ISR_NACK 0x0002 /* 1=Unit Rx or Tx a NACK */
+#define IOP3XX_ISR_RXREAD 0x0001 /* 1=READ 0=WRITE (R/W bit of slave addr */
+
+#define IOP3XX_ISR_CLEARBITS 0x07f0
+
+#define IOP3XX_ISAR_SAMASK 0x007f
+
+#define IOP3XX_IDBR_MASK 0x00ff
+
+#define IOP3XX_IBMR_SCL 0x0002
+#define IOP3XX_IBMR_SDA 0x0001
+
+#define IOP3XX_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
+#define IOP3XX_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
+
+#define MYSAR 0 /* default slave address */
+
+#define I2C_ERR 321
+#define I2C_ERR_BERR (I2C_ERR+0)
+#define I2C_ERR_ALD (I2C_ERR+1)
+
+
+#define CR_OFFSET 0
+#define SR_OFFSET 0x4
+#define SAR_OFFSET 0x8
+#define DBR_OFFSET 0xc
+#define CCR_OFFSET 0x10
+#define BMR_OFFSET 0x14
+
+#define IOP3XX_I2C_IO_SIZE 0x18
+
+struct i2c_algo_iop3xx_data {
+ void __iomem *ioaddr;
+ wait_queue_head_t waitq;
+ spinlock_t lock;
+ u32 SR_enabled, SR_received;
+ int id;
+};
+
+#endif /* I2C_IOP3XX_H */
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
new file mode 100644
index 000000000..5c754bf65
--- /dev/null
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -0,0 +1,320 @@
+/*
+ i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus
+ - Based on i2c-piix4.c
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+ - Intel SCH support
+ Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ Supports:
+ Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L)
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+
+/* SCH SMBus address offsets */
+#define SMBHSTCNT (0 + sch_smba)
+#define SMBHSTSTS (1 + sch_smba)
+#define SMBHSTCLK (2 + sch_smba)
+#define SMBHSTADD (4 + sch_smba) /* TSA */
+#define SMBHSTCMD (5 + sch_smba)
+#define SMBHSTDAT0 (6 + sch_smba)
+#define SMBHSTDAT1 (7 + sch_smba)
+#define SMBBLKDAT (0x20 + sch_smba)
+
+/* Other settings */
+#define MAX_RETRIES 5000
+
+/* I2C constants */
+#define SCH_QUICK 0x00
+#define SCH_BYTE 0x01
+#define SCH_BYTE_DATA 0x02
+#define SCH_WORD_DATA 0x03
+#define SCH_BLOCK_DATA 0x05
+
+static unsigned short sch_smba;
+static struct i2c_adapter sch_adapter;
+static int backbone_speed = 33000; /* backbone speed in kHz */
+module_param(backbone_speed, int, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)");
+
+/*
+ * Start the i2c transaction -- the i2c_access will prepare the transaction
+ * and this function will execute it.
+ * return 0 for success and others for failure.
+ */
+static int sch_transaction(void)
+{
+ int temp;
+ int result = 0;
+ int retries = 0;
+
+ dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
+ inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
+ inb(SMBHSTDAT1));
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ temp = inb(SMBHSTSTS) & 0x0f;
+ if (temp) {
+ /* Can not be busy since we checked it in sch_access */
+ if (temp & 0x01) {
+ dev_dbg(&sch_adapter.dev, "Completion (%02x). "
+ "Clear...\n", temp);
+ }
+ if (temp & 0x06) {
+ dev_dbg(&sch_adapter.dev, "SMBus error (%02x). "
+ "Resetting...\n", temp);
+ }
+ outb(temp, SMBHSTSTS);
+ temp = inb(SMBHSTSTS) & 0x0f;
+ if (temp) {
+ dev_err(&sch_adapter.dev,
+ "SMBus is not ready: (%02x)\n", temp);
+ return -EAGAIN;
+ }
+ }
+
+ /* start the transaction by setting bit 4 */
+ outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
+
+ do {
+ usleep_range(100, 200);
+ temp = inb(SMBHSTSTS) & 0x0f;
+ } while ((temp & 0x08) && (retries++ < MAX_RETRIES));
+
+ /* If the SMBus is still busy, we give up */
+ if (retries > MAX_RETRIES) {
+ dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+ if (temp & 0x04) {
+ result = -EIO;
+ dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
+ "locked until next hard reset. (sorry!)\n");
+ /* Clock stops and slave is stuck in mid-transmission */
+ } else if (temp & 0x02) {
+ result = -EIO;
+ dev_err(&sch_adapter.dev, "Error: no response!\n");
+ } else if (temp & 0x01) {
+ dev_dbg(&sch_adapter.dev, "Post complete!\n");
+ outb(temp, SMBHSTSTS);
+ temp = inb(SMBHSTSTS) & 0x07;
+ if (temp & 0x06) {
+ /* Completion clear failed */
+ dev_dbg(&sch_adapter.dev, "Failed reset at end of "
+ "transaction (%02x), Bus error!\n", temp);
+ }
+ } else {
+ result = -ENXIO;
+ dev_dbg(&sch_adapter.dev, "No such address.\n");
+ }
+ dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
+ inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
+ inb(SMBHSTDAT1));
+ return result;
+}
+
+/*
+ * This is the main access entry for i2c-sch access
+ * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write
+ * (0 for read and 1 for write), size is i2c transaction type and data is the
+ * union of transaction for data to be transferred or data read from bus.
+ * return 0 for success and others for failure.
+ */
+static s32 sch_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ int i, len, temp, rc;
+
+ /* Make sure the SMBus host is not busy */
+ temp = inb(SMBHSTSTS) & 0x0f;
+ if (temp & 0x08) {
+ dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp);
+ return -EAGAIN;
+ }
+ temp = inw(SMBHSTCLK);
+ if (!temp) {
+ /*
+ * We can't determine if we have 33 or 25 MHz clock for
+ * SMBus, so expect 33 MHz and calculate a bus clock of
+ * 100 kHz. If we actually run at 25 MHz the bus will be
+ * run ~75 kHz instead which should do no harm.
+ */
+ dev_notice(&sch_adapter.dev,
+ "Clock divider uninitialized. Setting defaults\n");
+ outw(backbone_speed / (4 * 100), SMBHSTCLK);
+ }
+
+ dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size,
+ (read_write)?"READ":"WRITE");
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ size = SCH_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb(command, SMBHSTCMD);
+ size = SCH_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ outb(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb(data->byte, SMBHSTDAT0);
+ size = SCH_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ outb(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb(data->word & 0xff, SMBHSTDAT0);
+ outb((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = SCH_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb((addr << 1) | read_write, SMBHSTADD);
+ outb(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ outb(len, SMBHSTDAT0);
+ for (i = 1; i <= len; i++)
+ outb(data->block[i], SMBBLKDAT+i-1);
+ }
+ size = SCH_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+ dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
+ outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT);
+
+ rc = sch_transaction();
+ if (rc) /* Error in transaction */
+ return rc;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == SCH_QUICK))
+ return 0;
+
+ switch (size) {
+ case SCH_BYTE:
+ case SCH_BYTE_DATA:
+ data->byte = inb(SMBHSTDAT0);
+ break;
+ case SCH_WORD_DATA:
+ data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8);
+ break;
+ case SCH_BLOCK_DATA:
+ data->block[0] = inb(SMBHSTDAT0);
+ if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb(SMBBLKDAT+i-1);
+ break;
+ }
+ return 0;
+}
+
+static u32 sch_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sch_access,
+ .functionality = sch_func,
+};
+
+static struct i2c_adapter sch_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static int smbus_sch_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ int retval;
+
+ res = platform_get_resource(dev, IORESOURCE_IO, 0);
+ if (!res)
+ return -EBUSY;
+
+ if (!devm_request_region(&dev->dev, res->start, resource_size(res),
+ dev->name)) {
+ dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
+ sch_smba);
+ return -EBUSY;
+ }
+
+ sch_smba = res->start;
+
+ dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
+
+ /* set up the sysfs linkage to our parent device */
+ sch_adapter.dev.parent = &dev->dev;
+
+ snprintf(sch_adapter.name, sizeof(sch_adapter.name),
+ "SMBus SCH adapter at %04x", sch_smba);
+
+ retval = i2c_add_adapter(&sch_adapter);
+ if (retval)
+ sch_smba = 0;
+
+ return retval;
+}
+
+static int smbus_sch_remove(struct platform_device *pdev)
+{
+ if (sch_smba) {
+ i2c_del_adapter(&sch_adapter);
+ sch_smba = 0;
+ }
+
+ return 0;
+}
+
+static struct platform_driver smbus_sch_driver = {
+ .driver = {
+ .name = "isch_smbus",
+ },
+ .probe = smbus_sch_probe,
+ .remove = smbus_sch_remove,
+};
+
+module_platform_driver(smbus_sch_driver);
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
+MODULE_DESCRIPTION("Intel SCH SMBus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:isch_smbus");
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
new file mode 100644
index 000000000..807960611
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -0,0 +1,973 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Supports the SMBus Message Transport (SMT) in the Intel Atom Processor
+ * S12xx Product Family.
+ *
+ * Features supported by this driver:
+ * Hardware PEC yes
+ * Block buffer yes
+ * Block process call transaction no
+ * Slave mode no
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+/* PCI Address Constants */
+#define SMBBAR 0
+
+/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */
+#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59
+#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a
+#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac
+#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15
+
+#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */
+#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */
+#define ISMT_LOG_ENTRIES 3 /* number of interrupt cause log entries */
+
+/* Hardware Descriptor Constants - Control Field */
+#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */
+#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */
+#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */
+#define ISMT_DESC_PEC 0x10 /* Packet Error Code */
+#define ISMT_DESC_I2C 0x20 /* I2C Enable */
+#define ISMT_DESC_INT 0x40 /* Interrupt */
+#define ISMT_DESC_SOE 0x80 /* Stop On Error */
+
+/* Hardware Descriptor Constants - Status Field */
+#define ISMT_DESC_SCS 0x01 /* Success */
+#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */
+#define ISMT_DESC_NAK 0x08 /* NAK Received */
+#define ISMT_DESC_CRC 0x10 /* CRC Error */
+#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */
+#define ISMT_DESC_COL 0x40 /* Collisions */
+#define ISMT_DESC_LPR 0x80 /* Large Packet Received */
+
+/* Macros */
+#define ISMT_DESC_ADDR_RW(addr, rw) (((addr) << 1) | (rw))
+
+/* iSMT General Register address offsets (SMBBAR + <addr>) */
+#define ISMT_GR_GCTRL 0x000 /* General Control */
+#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */
+#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */
+#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */
+#define ISMT_GR_ERRSTS 0x018 /* Error Status */
+#define ISMT_GR_ERRINFO 0x01c /* Error Information */
+
+/* iSMT Master Registers */
+#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */
+#define ISMT_MSTR_MCTRL 0x108 /* Master Control */
+#define ISMT_MSTR_MSTS 0x10c /* Master Status */
+#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */
+#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */
+
+/* iSMT Miscellaneous Registers */
+#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */
+
+/* General Control Register (GCTRL) bit definitions */
+#define ISMT_GCTRL_TRST 0x04 /* Target Reset */
+#define ISMT_GCTRL_KILL 0x08 /* Kill */
+#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */
+
+/* Master Control Register (MCTRL) bit definitions */
+#define ISMT_MCTRL_SS 0x01 /* Start/Stop */
+#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */
+#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */
+
+/* Master Status Register (MSTS) bit definitions */
+#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */
+#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */
+#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */
+#define ISMT_MSTS_IP 0x01 /* In Progress */
+
+/* Master Descriptor Size (MDS) bit definitions */
+#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */
+
+/* SMBus PHY Global Timing Register (SPGT) bit definitions */
+#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */
+#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */
+#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */
+#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */
+#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */
+
+
+/* MSI Control Register (MSICTL) bit definitions */
+#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */
+
+/* iSMT Hardware Descriptor */
+struct ismt_desc {
+ u8 tgtaddr_rw; /* target address & r/w bit */
+ u8 wr_len_cmd; /* write length in bytes or a command */
+ u8 rd_len; /* read length */
+ u8 control; /* control bits */
+ u8 status; /* status bits */
+ u8 retry; /* collision retry and retry count */
+ u8 rxbytes; /* received bytes */
+ u8 txbytes; /* transmitted bytes */
+ u32 dptr_low; /* lower 32 bit of the data pointer */
+ u32 dptr_high; /* upper 32 bit of the data pointer */
+} __packed;
+
+struct ismt_priv {
+ struct i2c_adapter adapter;
+ void __iomem *smba; /* PCI BAR */
+ struct pci_dev *pci_dev;
+ struct ismt_desc *hw; /* descriptor virt base addr */
+ dma_addr_t io_rng_dma; /* descriptor HW base addr */
+ u8 head; /* ring buffer head pointer */
+ struct completion cmp; /* interrupt completion */
+ u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */
+ dma_addr_t log_dma;
+ u32 *log;
+};
+
+/**
+ * ismt_ids - PCI device IDs supported by this driver
+ */
+static const struct pci_device_id ismt_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ismt_ids);
+
+/* Bus speed control bits for slow debuggers - refer to the docs for usage */
+static unsigned int bus_speed;
+module_param(bus_speed, uint, S_IRUGO);
+MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (0 = BIOS default)");
+
+/**
+ * __ismt_desc_dump() - dump the contents of a specific descriptor
+ */
+static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc)
+{
+
+ dev_dbg(dev, "Descriptor struct: %p\n", desc);
+ dev_dbg(dev, "\ttgtaddr_rw=0x%02X\n", desc->tgtaddr_rw);
+ dev_dbg(dev, "\twr_len_cmd=0x%02X\n", desc->wr_len_cmd);
+ dev_dbg(dev, "\trd_len= 0x%02X\n", desc->rd_len);
+ dev_dbg(dev, "\tcontrol= 0x%02X\n", desc->control);
+ dev_dbg(dev, "\tstatus= 0x%02X\n", desc->status);
+ dev_dbg(dev, "\tretry= 0x%02X\n", desc->retry);
+ dev_dbg(dev, "\trxbytes= 0x%02X\n", desc->rxbytes);
+ dev_dbg(dev, "\ttxbytes= 0x%02X\n", desc->txbytes);
+ dev_dbg(dev, "\tdptr_low= 0x%08X\n", desc->dptr_low);
+ dev_dbg(dev, "\tdptr_high= 0x%08X\n", desc->dptr_high);
+}
+/**
+ * ismt_desc_dump() - dump the contents of a descriptor for debug purposes
+ * @priv: iSMT private data
+ */
+static void ismt_desc_dump(struct ismt_priv *priv)
+{
+ struct device *dev = &priv->pci_dev->dev;
+ struct ismt_desc *desc = &priv->hw[priv->head];
+
+ dev_dbg(dev, "Dump of the descriptor struct: 0x%X\n", priv->head);
+ __ismt_desc_dump(dev, desc);
+}
+
+/**
+ * ismt_gen_reg_dump() - dump the iSMT General Registers
+ * @priv: iSMT private data
+ */
+static void ismt_gen_reg_dump(struct ismt_priv *priv)
+{
+ struct device *dev = &priv->pci_dev->dev;
+
+ dev_dbg(dev, "Dump of the iSMT General Registers\n");
+ dev_dbg(dev, " GCTRL.... : (0x%p)=0x%X\n",
+ priv->smba + ISMT_GR_GCTRL,
+ readl(priv->smba + ISMT_GR_GCTRL));
+ dev_dbg(dev, " SMTICL... : (0x%p)=0x%016llX\n",
+ priv->smba + ISMT_GR_SMTICL,
+ (long long unsigned int)readq(priv->smba + ISMT_GR_SMTICL));
+ dev_dbg(dev, " ERRINTMSK : (0x%p)=0x%X\n",
+ priv->smba + ISMT_GR_ERRINTMSK,
+ readl(priv->smba + ISMT_GR_ERRINTMSK));
+ dev_dbg(dev, " ERRAERMSK : (0x%p)=0x%X\n",
+ priv->smba + ISMT_GR_ERRAERMSK,
+ readl(priv->smba + ISMT_GR_ERRAERMSK));
+ dev_dbg(dev, " ERRSTS... : (0x%p)=0x%X\n",
+ priv->smba + ISMT_GR_ERRSTS,
+ readl(priv->smba + ISMT_GR_ERRSTS));
+ dev_dbg(dev, " ERRINFO.. : (0x%p)=0x%X\n",
+ priv->smba + ISMT_GR_ERRINFO,
+ readl(priv->smba + ISMT_GR_ERRINFO));
+}
+
+/**
+ * ismt_mstr_reg_dump() - dump the iSMT Master Registers
+ * @priv: iSMT private data
+ */
+static void ismt_mstr_reg_dump(struct ismt_priv *priv)
+{
+ struct device *dev = &priv->pci_dev->dev;
+
+ dev_dbg(dev, "Dump of the iSMT Master Registers\n");
+ dev_dbg(dev, " MDBA..... : (0x%p)=0x%016llX\n",
+ priv->smba + ISMT_MSTR_MDBA,
+ (long long unsigned int)readq(priv->smba + ISMT_MSTR_MDBA));
+ dev_dbg(dev, " MCTRL.... : (0x%p)=0x%X\n",
+ priv->smba + ISMT_MSTR_MCTRL,
+ readl(priv->smba + ISMT_MSTR_MCTRL));
+ dev_dbg(dev, " MSTS..... : (0x%p)=0x%X\n",
+ priv->smba + ISMT_MSTR_MSTS,
+ readl(priv->smba + ISMT_MSTR_MSTS));
+ dev_dbg(dev, " MDS...... : (0x%p)=0x%X\n",
+ priv->smba + ISMT_MSTR_MDS,
+ readl(priv->smba + ISMT_MSTR_MDS));
+ dev_dbg(dev, " RPOLICY.. : (0x%p)=0x%X\n",
+ priv->smba + ISMT_MSTR_RPOLICY,
+ readl(priv->smba + ISMT_MSTR_RPOLICY));
+ dev_dbg(dev, " SPGT..... : (0x%p)=0x%X\n",
+ priv->smba + ISMT_SPGT,
+ readl(priv->smba + ISMT_SPGT));
+}
+
+/**
+ * ismt_submit_desc() - add a descriptor to the ring
+ * @priv: iSMT private data
+ */
+static void ismt_submit_desc(struct ismt_priv *priv)
+{
+ uint fmhp;
+ uint val;
+
+ ismt_desc_dump(priv);
+ ismt_gen_reg_dump(priv);
+ ismt_mstr_reg_dump(priv);
+
+ /* Set the FMHP (Firmware Master Head Pointer)*/
+ fmhp = ((priv->head + 1) % ISMT_DESC_ENTRIES) << 16;
+ val = readl(priv->smba + ISMT_MSTR_MCTRL);
+ writel((val & ~ISMT_MCTRL_FMHP) | fmhp,
+ priv->smba + ISMT_MSTR_MCTRL);
+
+ /* Set the start bit */
+ val = readl(priv->smba + ISMT_MSTR_MCTRL);
+ writel(val | ISMT_MCTRL_SS,
+ priv->smba + ISMT_MSTR_MCTRL);
+}
+
+/**
+ * ismt_process_desc() - handle the completion of the descriptor
+ * @desc: the iSMT hardware descriptor
+ * @data: data buffer from the upper layer
+ * @priv: ismt_priv struct holding our dma buffer
+ * @size: SMBus transaction type
+ * @read_write: flag to indicate if this is a read or write
+ */
+static int ismt_process_desc(const struct ismt_desc *desc,
+ union i2c_smbus_data *data,
+ struct ismt_priv *priv, int size,
+ char read_write)
+{
+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
+
+ dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n");
+ __ismt_desc_dump(&priv->pci_dev->dev, desc);
+ ismt_gen_reg_dump(priv);
+ ismt_mstr_reg_dump(priv);
+
+ if (desc->status & ISMT_DESC_SCS) {
+ if (read_write == I2C_SMBUS_WRITE &&
+ size != I2C_SMBUS_PROC_CALL)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = dma_buffer[0];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = dma_buffer[0] | (dma_buffer[1] << 8);
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (desc->rxbytes != dma_buffer[0] + 1)
+ return -EMSGSIZE;
+
+ memcpy(data->block, dma_buffer, desc->rxbytes);
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ memcpy(&data->block[1], dma_buffer, desc->rxbytes);
+ data->block[0] = desc->rxbytes;
+ break;
+ }
+ return 0;
+ }
+
+ if (likely(desc->status & ISMT_DESC_NAK))
+ return -ENXIO;
+
+ if (desc->status & ISMT_DESC_CRC)
+ return -EBADMSG;
+
+ if (desc->status & ISMT_DESC_COL)
+ return -EAGAIN;
+
+ if (desc->status & ISMT_DESC_LPR)
+ return -EPROTO;
+
+ if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO))
+ return -ETIMEDOUT;
+
+ return -EIO;
+}
+
+/**
+ * ismt_access() - process an SMBus command
+ * @adap: the i2c host adapter
+ * @addr: address of the i2c/SMBus target
+ * @flags: command options
+ * @read_write: read from or write to device
+ * @command: the i2c/SMBus command to issue
+ * @size: SMBus transaction type
+ * @data: read/write data buffer
+ */
+static int ismt_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int ret;
+ unsigned long time_left;
+ dma_addr_t dma_addr = 0; /* address of the data buffer */
+ u8 dma_size = 0;
+ enum dma_data_direction dma_direction = 0;
+ struct ismt_desc *desc;
+ struct ismt_priv *priv = i2c_get_adapdata(adap);
+ struct device *dev = &priv->pci_dev->dev;
+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
+
+ desc = &priv->hw[priv->head];
+
+ /* Initialize the DMA buffer */
+ memset(priv->buffer, 0, sizeof(priv->buffer));
+
+ /* Initialize the descriptor */
+ memset(desc, 0, sizeof(struct ismt_desc));
+ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
+
+ /* Always clear the log entries */
+ memset(priv->log, 0, ISMT_LOG_ENTRIES * sizeof(u32));
+
+ /* Initialize common control bits */
+ if (likely(pci_dev_msi_enabled(priv->pci_dev)))
+ desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
+ else
+ desc->control = ISMT_DESC_FAIR;
+
+ if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK)
+ && (size != I2C_SMBUS_I2C_BLOCK_DATA))
+ desc->control |= ISMT_DESC_PEC;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ dev_dbg(dev, "I2C_SMBUS_QUICK\n");
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE) {
+ /*
+ * Send Byte
+ * The command field contains the write data
+ */
+ dev_dbg(dev, "I2C_SMBUS_BYTE: WRITE\n");
+ desc->control |= ISMT_DESC_CWRL;
+ desc->wr_len_cmd = command;
+ } else {
+ /* Receive Byte */
+ dev_dbg(dev, "I2C_SMBUS_BYTE: READ\n");
+ dma_size = 1;
+ dma_direction = DMA_FROM_DEVICE;
+ desc->rd_len = 1;
+ }
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_WRITE) {
+ /*
+ * Write Byte
+ * Command plus 1 data byte
+ */
+ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: WRITE\n");
+ desc->wr_len_cmd = 2;
+ dma_size = 2;
+ dma_direction = DMA_TO_DEVICE;
+ dma_buffer[0] = command;
+ dma_buffer[1] = data->byte;
+ } else {
+ /* Read Byte */
+ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n");
+ desc->control |= ISMT_DESC_CWRL;
+ desc->wr_len_cmd = command;
+ desc->rd_len = 1;
+ dma_size = 1;
+ dma_direction = DMA_FROM_DEVICE;
+ }
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* Write Word */
+ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: WRITE\n");
+ desc->wr_len_cmd = 3;
+ dma_size = 3;
+ dma_direction = DMA_TO_DEVICE;
+ dma_buffer[0] = command;
+ dma_buffer[1] = data->word & 0xff;
+ dma_buffer[2] = data->word >> 8;
+ } else {
+ /* Read Word */
+ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n");
+ desc->wr_len_cmd = command;
+ desc->control |= ISMT_DESC_CWRL;
+ desc->rd_len = 2;
+ dma_size = 2;
+ dma_direction = DMA_FROM_DEVICE;
+ }
+ break;
+
+ case I2C_SMBUS_PROC_CALL:
+ dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n");
+ desc->wr_len_cmd = 3;
+ desc->rd_len = 2;
+ dma_size = 3;
+ dma_direction = DMA_BIDIRECTIONAL;
+ dma_buffer[0] = command;
+ dma_buffer[1] = data->word & 0xff;
+ dma_buffer[2] = data->word >> 8;
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* Block Write */
+ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n");
+ dma_size = data->block[0] + 1;
+ dma_direction = DMA_TO_DEVICE;
+ desc->wr_len_cmd = dma_size;
+ desc->control |= ISMT_DESC_BLK;
+ dma_buffer[0] = command;
+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
+ } else {
+ /* Block Read */
+ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n");
+ dma_size = I2C_SMBUS_BLOCK_MAX;
+ dma_direction = DMA_FROM_DEVICE;
+ desc->rd_len = dma_size;
+ desc->wr_len_cmd = command;
+ desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL);
+ }
+ break;
+
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* Make sure the length is valid */
+ if (data->block[0] < 1)
+ data->block[0] = 1;
+
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* i2c Block Write */
+ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: WRITE\n");
+ dma_size = data->block[0] + 1;
+ dma_direction = DMA_TO_DEVICE;
+ desc->wr_len_cmd = dma_size;
+ desc->control |= ISMT_DESC_I2C;
+ dma_buffer[0] = command;
+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
+ } else {
+ /* i2c Block Read */
+ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n");
+ dma_size = data->block[0];
+ dma_direction = DMA_FROM_DEVICE;
+ desc->rd_len = dma_size;
+ desc->wr_len_cmd = command;
+ desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL);
+ /*
+ * Per the "Table 15-15. I2C Commands",
+ * in the External Design Specification (EDS),
+ * (Document Number: 508084, Revision: 2.0),
+ * the _rw bit must be 0
+ */
+ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0);
+ }
+ break;
+
+ default:
+ dev_err(dev, "Unsupported transaction %d\n",
+ size);
+ return -EOPNOTSUPP;
+ }
+
+ /* map the data buffer */
+ if (dma_size != 0) {
+ dev_dbg(dev, " dev=%p\n", dev);
+ dev_dbg(dev, " data=%p\n", data);
+ dev_dbg(dev, " dma_buffer=%p\n", dma_buffer);
+ dev_dbg(dev, " dma_size=%d\n", dma_size);
+ dev_dbg(dev, " dma_direction=%d\n", dma_direction);
+
+ dma_addr = dma_map_single(dev,
+ dma_buffer,
+ dma_size,
+ dma_direction);
+
+ if (dma_mapping_error(dev, dma_addr)) {
+ dev_err(dev, "Error in mapping dma buffer %p\n",
+ dma_buffer);
+ return -EIO;
+ }
+
+ dev_dbg(dev, " dma_addr = %pad\n", &dma_addr);
+
+ desc->dptr_low = lower_32_bits(dma_addr);
+ desc->dptr_high = upper_32_bits(dma_addr);
+ }
+
+ reinit_completion(&priv->cmp);
+
+ /* Add the descriptor */
+ ismt_submit_desc(priv);
+
+ /* Now we wait for interrupt completion, 1s */
+ time_left = wait_for_completion_timeout(&priv->cmp, HZ*1);
+
+ /* unmap the data buffer */
+ if (dma_size != 0)
+ dma_unmap_single(dev, dma_addr, dma_size, dma_direction);
+
+ if (unlikely(!time_left)) {
+ dev_err(dev, "completion wait timed out\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ /* do any post processing of the descriptor here */
+ ret = ismt_process_desc(desc, data, priv, size, read_write);
+
+out:
+ /* Update the ring pointer */
+ priv->head++;
+ priv->head %= ISMT_DESC_ENTRIES;
+
+ return ret;
+}
+
+/**
+ * ismt_func() - report which i2c commands are supported by this adapter
+ * @adap: the i2c host adapter
+ */
+static u32 ismt_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_QUICK |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK |
+ I2C_FUNC_SMBUS_PEC;
+}
+
+/**
+ * smbus_algorithm - the adapter algorithm and supported functionality
+ * @smbus_xfer: the adapter algorithm
+ * @functionality: functionality supported by the adapter
+ */
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = ismt_access,
+ .functionality = ismt_func,
+};
+
+/**
+ * ismt_handle_isr() - interrupt handler bottom half
+ * @priv: iSMT private data
+ */
+static irqreturn_t ismt_handle_isr(struct ismt_priv *priv)
+{
+ complete(&priv->cmp);
+
+ return IRQ_HANDLED;
+}
+
+
+/**
+ * ismt_do_interrupt() - IRQ interrupt handler
+ * @vec: interrupt vector
+ * @data: iSMT private data
+ */
+static irqreturn_t ismt_do_interrupt(int vec, void *data)
+{
+ u32 val;
+ struct ismt_priv *priv = data;
+
+ /*
+ * check to see it's our interrupt, return IRQ_NONE if not ours
+ * since we are sharing interrupt
+ */
+ val = readl(priv->smba + ISMT_MSTR_MSTS);
+
+ if (!(val & (ISMT_MSTS_MIS | ISMT_MSTS_MEIS)))
+ return IRQ_NONE;
+ else
+ writel(val | ISMT_MSTS_MIS | ISMT_MSTS_MEIS,
+ priv->smba + ISMT_MSTR_MSTS);
+
+ return ismt_handle_isr(priv);
+}
+
+/**
+ * ismt_do_msi_interrupt() - MSI interrupt handler
+ * @vec: interrupt vector
+ * @data: iSMT private data
+ */
+static irqreturn_t ismt_do_msi_interrupt(int vec, void *data)
+{
+ return ismt_handle_isr(data);
+}
+
+/**
+ * ismt_hw_init() - initialize the iSMT hardware
+ * @priv: iSMT private data
+ */
+static void ismt_hw_init(struct ismt_priv *priv)
+{
+ u32 val;
+ struct device *dev = &priv->pci_dev->dev;
+
+ /* initialize the Master Descriptor Base Address (MDBA) */
+ writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA);
+
+ writeq(priv->log_dma, priv->smba + ISMT_GR_SMTICL);
+
+ /* initialize the Master Control Register (MCTRL) */
+ writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL);
+
+ /* initialize the Master Status Register (MSTS) */
+ writel(0, priv->smba + ISMT_MSTR_MSTS);
+
+ /* initialize the Master Descriptor Size (MDS) */
+ val = readl(priv->smba + ISMT_MSTR_MDS);
+ writel((val & ~ISMT_MDS_MASK) | (ISMT_DESC_ENTRIES - 1),
+ priv->smba + ISMT_MSTR_MDS);
+
+ /*
+ * Set the SMBus speed (could use this for slow HW debuggers)
+ */
+
+ val = readl(priv->smba + ISMT_SPGT);
+
+ switch (bus_speed) {
+ case 0:
+ break;
+
+ case 80:
+ dev_dbg(dev, "Setting SMBus clock to 80 kHz\n");
+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_80K),
+ priv->smba + ISMT_SPGT);
+ break;
+
+ case 100:
+ dev_dbg(dev, "Setting SMBus clock to 100 kHz\n");
+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_100K),
+ priv->smba + ISMT_SPGT);
+ break;
+
+ case 400:
+ dev_dbg(dev, "Setting SMBus clock to 400 kHz\n");
+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_400K),
+ priv->smba + ISMT_SPGT);
+ break;
+
+ case 1000:
+ dev_dbg(dev, "Setting SMBus clock to 1000 kHz\n");
+ writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_1M),
+ priv->smba + ISMT_SPGT);
+ break;
+
+ default:
+ dev_warn(dev, "Invalid SMBus clock speed, only 0, 80, 100, 400, and 1000 are valid\n");
+ break;
+ }
+
+ val = readl(priv->smba + ISMT_SPGT);
+
+ switch (val & ISMT_SPGT_SPD_MASK) {
+ case ISMT_SPGT_SPD_80K:
+ bus_speed = 80;
+ break;
+ case ISMT_SPGT_SPD_100K:
+ bus_speed = 100;
+ break;
+ case ISMT_SPGT_SPD_400K:
+ bus_speed = 400;
+ break;
+ case ISMT_SPGT_SPD_1M:
+ bus_speed = 1000;
+ break;
+ }
+ dev_dbg(dev, "SMBus clock is running at %d kHz\n", bus_speed);
+}
+
+/**
+ * ismt_dev_init() - initialize the iSMT data structures
+ * @priv: iSMT private data
+ */
+static int ismt_dev_init(struct ismt_priv *priv)
+{
+ /* allocate memory for the descriptor */
+ priv->hw = dmam_alloc_coherent(&priv->pci_dev->dev,
+ (ISMT_DESC_ENTRIES
+ * sizeof(struct ismt_desc)),
+ &priv->io_rng_dma,
+ GFP_KERNEL);
+ if (!priv->hw)
+ return -ENOMEM;
+
+ memset(priv->hw, 0, (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc)));
+
+ priv->head = 0;
+ init_completion(&priv->cmp);
+
+ priv->log = dmam_alloc_coherent(&priv->pci_dev->dev,
+ ISMT_LOG_ENTRIES * sizeof(u32),
+ &priv->log_dma, GFP_KERNEL);
+ if (!priv->log)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * ismt_int_init() - initialize interrupts
+ * @priv: iSMT private data
+ */
+static int ismt_int_init(struct ismt_priv *priv)
+{
+ int err;
+
+ /* Try using MSI interrupts */
+ err = pci_enable_msi(priv->pci_dev);
+ if (err)
+ goto intx;
+
+ err = devm_request_irq(&priv->pci_dev->dev,
+ priv->pci_dev->irq,
+ ismt_do_msi_interrupt,
+ 0,
+ "ismt-msi",
+ priv);
+ if (err) {
+ pci_disable_msi(priv->pci_dev);
+ goto intx;
+ }
+
+ return 0;
+
+ /* Try using legacy interrupts */
+intx:
+ dev_warn(&priv->pci_dev->dev,
+ "Unable to use MSI interrupts, falling back to legacy\n");
+
+ err = devm_request_irq(&priv->pci_dev->dev,
+ priv->pci_dev->irq,
+ ismt_do_interrupt,
+ IRQF_SHARED,
+ "ismt-intx",
+ priv);
+ if (err) {
+ dev_err(&priv->pci_dev->dev, "no usable interrupts\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static struct pci_driver ismt_driver;
+
+/**
+ * ismt_probe() - probe for iSMT devices
+ * @pdev: PCI-Express device
+ * @id: PCI-Express device ID
+ */
+static int
+ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int err;
+ struct ismt_priv *priv;
+ unsigned long start, len;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, priv);
+
+ i2c_set_adapdata(&priv->adapter, priv);
+ priv->adapter.owner = THIS_MODULE;
+ priv->adapter.class = I2C_CLASS_HWMON;
+ priv->adapter.algo = &smbus_algorithm;
+ priv->adapter.dev.parent = &pdev->dev;
+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
+ priv->adapter.retries = ISMT_MAX_RETRIES;
+
+ priv->pci_dev = pdev;
+
+ err = pcim_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n",
+ err);
+ return err;
+ }
+
+ /* enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Determine the address of the SMBus area */
+ start = pci_resource_start(pdev, SMBBAR);
+ len = pci_resource_len(pdev, SMBBAR);
+ if (!start || !len) {
+ dev_err(&pdev->dev,
+ "SMBus base address uninitialized, upgrade BIOS\n");
+ return -ENODEV;
+ }
+
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+ "SMBus iSMT adapter at %lx", start);
+
+ dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start);
+ dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len);
+
+ err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]);
+ if (err) {
+ dev_err(&pdev->dev, "ACPI resource conflict!\n");
+ return err;
+ }
+
+ err = pci_request_region(pdev, SMBBAR, ismt_driver.name);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to request SMBus region 0x%lx-0x%lx\n",
+ start, start + len);
+ return err;
+ }
+
+ priv->smba = pcim_iomap(pdev, SMBBAR, len);
+ if (!priv->smba) {
+ dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n");
+ return -ENODEV;
+ }
+
+ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) ||
+ (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) {
+ if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) ||
+ (pci_set_consistent_dma_mask(pdev,
+ DMA_BIT_MASK(32)) != 0)) {
+ dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n",
+ pdev);
+ return -ENODEV;
+ }
+ }
+
+ err = ismt_dev_init(priv);
+ if (err)
+ return err;
+
+ ismt_hw_init(priv);
+
+ err = ismt_int_init(priv);
+ if (err)
+ return err;
+
+ err = i2c_add_adapter(&priv->adapter);
+ if (err)
+ return -ENODEV;
+ return 0;
+}
+
+/**
+ * ismt_remove() - release driver resources
+ * @pdev: PCI-Express device
+ */
+static void ismt_remove(struct pci_dev *pdev)
+{
+ struct ismt_priv *priv = pci_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adapter);
+}
+
+static struct pci_driver ismt_driver = {
+ .name = "ismt_smbus",
+ .id_table = ismt_ids,
+ .probe = ismt_probe,
+ .remove = ismt_remove,
+};
+
+module_pci_driver(ismt_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Bill E. Brown <bill.e.brown@intel.com>");
+MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver");
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
new file mode 100644
index 000000000..4dd800c0d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -0,0 +1,805 @@
+/*
+ * Ingenic JZ4780 I2C bus driver
+ *
+ * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#define JZ4780_I2C_CTRL 0x00
+#define JZ4780_I2C_TAR 0x04
+#define JZ4780_I2C_SAR 0x08
+#define JZ4780_I2C_DC 0x10
+#define JZ4780_I2C_SHCNT 0x14
+#define JZ4780_I2C_SLCNT 0x18
+#define JZ4780_I2C_FHCNT 0x1C
+#define JZ4780_I2C_FLCNT 0x20
+#define JZ4780_I2C_INTST 0x2C
+#define JZ4780_I2C_INTM 0x30
+#define JZ4780_I2C_RXTL 0x38
+#define JZ4780_I2C_TXTL 0x3C
+#define JZ4780_I2C_CINTR 0x40
+#define JZ4780_I2C_CRXUF 0x44
+#define JZ4780_I2C_CRXOF 0x48
+#define JZ4780_I2C_CTXOF 0x4C
+#define JZ4780_I2C_CRXREQ 0x50
+#define JZ4780_I2C_CTXABRT 0x54
+#define JZ4780_I2C_CRXDONE 0x58
+#define JZ4780_I2C_CACT 0x5C
+#define JZ4780_I2C_CSTP 0x60
+#define JZ4780_I2C_CSTT 0x64
+#define JZ4780_I2C_CGC 0x68
+#define JZ4780_I2C_ENB 0x6C
+#define JZ4780_I2C_STA 0x70
+#define JZ4780_I2C_TXABRT 0x80
+#define JZ4780_I2C_DMACR 0x88
+#define JZ4780_I2C_DMATDLR 0x8C
+#define JZ4780_I2C_DMARDLR 0x90
+#define JZ4780_I2C_SDASU 0x94
+#define JZ4780_I2C_ACKGC 0x98
+#define JZ4780_I2C_ENSTA 0x9C
+#define JZ4780_I2C_SDAHD 0xD0
+
+#define JZ4780_I2C_CTRL_STPHLD BIT(7)
+#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
+#define JZ4780_I2C_CTRL_REST BIT(5)
+#define JZ4780_I2C_CTRL_MATP BIT(4)
+#define JZ4780_I2C_CTRL_SATP BIT(3)
+#define JZ4780_I2C_CTRL_SPDF BIT(2)
+#define JZ4780_I2C_CTRL_SPDS BIT(1)
+#define JZ4780_I2C_CTRL_MD BIT(0)
+
+#define JZ4780_I2C_STA_SLVACT BIT(6)
+#define JZ4780_I2C_STA_MSTACT BIT(5)
+#define JZ4780_I2C_STA_RFF BIT(4)
+#define JZ4780_I2C_STA_RFNE BIT(3)
+#define JZ4780_I2C_STA_TFE BIT(2)
+#define JZ4780_I2C_STA_TFNF BIT(1)
+#define JZ4780_I2C_STA_ACT BIT(0)
+
+#define JZ4780_I2C_INTST_IGC BIT(11)
+#define JZ4780_I2C_INTST_ISTT BIT(10)
+#define JZ4780_I2C_INTST_ISTP BIT(9)
+#define JZ4780_I2C_INTST_IACT BIT(8)
+#define JZ4780_I2C_INTST_RXDN BIT(7)
+#define JZ4780_I2C_INTST_TXABT BIT(6)
+#define JZ4780_I2C_INTST_RDREQ BIT(5)
+#define JZ4780_I2C_INTST_TXEMP BIT(4)
+#define JZ4780_I2C_INTST_TXOF BIT(3)
+#define JZ4780_I2C_INTST_RXFL BIT(2)
+#define JZ4780_I2C_INTST_RXOF BIT(1)
+#define JZ4780_I2C_INTST_RXUF BIT(0)
+
+#define JZ4780_I2C_INTM_MIGC BIT(11)
+#define JZ4780_I2C_INTM_MISTT BIT(10)
+#define JZ4780_I2C_INTM_MISTP BIT(9)
+#define JZ4780_I2C_INTM_MIACT BIT(8)
+#define JZ4780_I2C_INTM_MRXDN BIT(7)
+#define JZ4780_I2C_INTM_MTXABT BIT(6)
+#define JZ4780_I2C_INTM_MRDREQ BIT(5)
+#define JZ4780_I2C_INTM_MTXEMP BIT(4)
+#define JZ4780_I2C_INTM_MTXOF BIT(3)
+#define JZ4780_I2C_INTM_MRXFL BIT(2)
+#define JZ4780_I2C_INTM_MRXOF BIT(1)
+#define JZ4780_I2C_INTM_MRXUF BIT(0)
+
+#define JZ4780_I2C_DC_READ BIT(8)
+
+#define JZ4780_I2C_SDAHD_HDENB BIT(8)
+
+#define JZ4780_I2C_ENB_I2C BIT(0)
+
+#define JZ4780_I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
+#define JZ4780_I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
+#define JZ4780_I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
+#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
+
+#define JZ4780_I2C_FIFO_LEN 16
+#define TX_LEVEL 3
+#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1)
+
+#define JZ4780_I2C_TIMEOUT 300
+
+#define BUFSIZE 200
+
+struct jz4780_i2c {
+ void __iomem *iomem;
+ int irq;
+ struct clk *clk;
+ struct i2c_adapter adap;
+
+ /* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
+ spinlock_t lock;
+
+ /* beginning of lock scope */
+ unsigned char *rbuf;
+ int rd_total_len;
+ int rd_data_xfered;
+ int rd_cmd_xfered;
+
+ unsigned char *wbuf;
+ int wt_len;
+
+ int is_write;
+ int stop_hold;
+ int speed;
+
+ int data_buf[BUFSIZE];
+ int cmd_buf[BUFSIZE];
+ int cmd;
+
+ /* end of lock scope */
+ struct completion trans_waitq;
+};
+
+static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c,
+ unsigned long offset)
+{
+ return readw(i2c->iomem + offset);
+}
+
+static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c,
+ unsigned long offset, unsigned short val)
+{
+ writew(val, i2c->iomem + offset);
+}
+
+static int jz4780_i2c_disable(struct jz4780_i2c *i2c)
+{
+ unsigned short regval;
+ unsigned long loops = 5;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0);
+
+ do {
+ regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
+ if (!(regval & JZ4780_I2C_ENB_I2C))
+ return 0;
+
+ usleep_range(5000, 15000);
+ } while (--loops);
+
+ dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval);
+ return -ETIMEDOUT;
+}
+
+static int jz4780_i2c_enable(struct jz4780_i2c *i2c)
+{
+ unsigned short regval;
+ unsigned long loops = 5;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1);
+
+ do {
+ regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
+ if (regval & JZ4780_I2C_ENB_I2C)
+ return 0;
+
+ usleep_range(5000, 15000);
+ } while (--loops);
+
+ dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval);
+ return -ETIMEDOUT;
+}
+
+static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
+{
+ unsigned short regval;
+ unsigned long loops = 5;
+
+ do {
+ regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+ if ((regval & JZ4780_I2C_STA_TFE) &&
+ !(regval & JZ4780_I2C_STA_MSTACT))
+ break;
+
+ usleep_range(5000, 15000);
+ } while (--loops);
+
+ if (loops) {
+ jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address);
+ return 0;
+ }
+
+ dev_err(&i2c->adap.dev,
+ "set device to address 0x%02x failed, STA=0x%04x\n",
+ address, regval);
+
+ return -ENXIO;
+}
+
+static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
+{
+ int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
+ int cnt_high = 0; /* HIGH period count of the SCL clock */
+ int cnt_low = 0; /* LOW period count of the SCL clock */
+ int cnt_period = 0; /* period count of the SCL clock */
+ int setup_time = 0;
+ int hold_time = 0;
+ unsigned short tmp = 0;
+ int i2c_clk = i2c->speed;
+
+ if (jz4780_i2c_disable(i2c))
+ dev_dbg(&i2c->adap.dev, "i2c not disabled\n");
+
+ /*
+ * 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk)
+ * standard mode, min LOW and HIGH period are 4700 ns and 4000 ns
+ * fast mode, min LOW and HIGH period are 1300 ns and 600 ns
+ */
+ cnt_period = dev_clk_khz / i2c_clk;
+
+ if (i2c_clk <= 100)
+ cnt_high = (cnt_period * 4000) / (4700 + 4000);
+ else
+ cnt_high = (cnt_period * 600) / (1300 + 600);
+
+ cnt_low = cnt_period - cnt_high;
+
+ /*
+ * NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because
+ * normal read are 2 messages, we cannot disable i2c controller
+ * between these two messages, this means that we must always set
+ * JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL
+ *
+ */
+ if (i2c_clk <= 100) {
+ tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST
+ | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT,
+ JZ4780_I2CSHCNT_ADJUST(cnt_high));
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT,
+ JZ4780_I2CSLCNT_ADJUST(cnt_low));
+ } else {
+ tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST
+ | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT,
+ JZ4780_I2CFHCNT_ADJUST(cnt_high));
+ jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT,
+ JZ4780_I2CFLCNT_ADJUST(cnt_low));
+ }
+
+ /*
+ * a i2c device must internally provide a hold time at least 300ns
+ * tHD:DAT
+ * Standard Mode: min=300ns, max=3450ns
+ * Fast Mode: min=0ns, max=900ns
+ * tSU:DAT
+ * Standard Mode: min=250ns, max=infinite
+ * Fast Mode: min=100(250ns is recommended), max=infinite
+ *
+ * 1i2c_clk = 10^6 / dev_clk_khz
+ * on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns
+ * on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns
+ *
+ * The actual hold time is (SDAHD + 1) * (i2c_clk period).
+ *
+ * Length of setup time calculated using (SDASU - 1) * (ic_clk_period)
+ *
+ */
+ if (i2c_clk <= 100) { /* standard mode */
+ setup_time = 300;
+ hold_time = 400;
+ } else {
+ setup_time = 450;
+ hold_time = 450;
+ }
+
+ hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1;
+ setup_time = ((setup_time * dev_clk_khz) / 1000000) + 1;
+
+ if (setup_time > 255)
+ setup_time = 255;
+
+ if (setup_time <= 0)
+ setup_time = 1;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time);
+
+ if (hold_time > 255)
+ hold_time = 255;
+
+ if (hold_time >= 0) {
+ /*i2c hold time enable */
+ hold_time |= JZ4780_I2C_SDAHD_HDENB;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
+ } else {
+ /* disable hold time */
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
+ }
+
+ return 0;
+}
+
+static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
+{
+ int ret;
+ unsigned long flags;
+ unsigned short tmp;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ /* can send stop now if need */
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ /* disable all interrupts first */
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
+
+ /* then clear all interrupts */
+ jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT);
+ jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR);
+
+ /* then disable the controller */
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_ENB_I2C;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+ udelay(10);
+ tmp |= JZ4780_I2C_ENB_I2C;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ ret = jz4780_i2c_disable(i2c);
+ if (ret)
+ dev_err(&i2c->adap.dev,
+ "unable to disable device during cleanup!\n");
+
+ if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM)
+ & jz4780_i2c_readw(i2c, JZ4780_I2C_INTST)))
+ dev_err(&i2c->adap.dev,
+ "device has interrupts after a complete cleanup!\n");
+
+ return ret;
+}
+
+static int jz4780_i2c_prepare(struct jz4780_i2c *i2c)
+{
+ jz4780_i2c_set_speed(i2c);
+ return jz4780_i2c_enable(i2c);
+}
+
+static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count)
+{
+ int i;
+
+ for (i = 0; i < cmd_count; i++)
+ jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
+}
+
+static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c)
+{
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
+ complete(&i2c->trans_waitq);
+}
+
+static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
+{
+ unsigned short tmp;
+ unsigned short intst;
+ unsigned short intmsk;
+ struct jz4780_i2c *i2c = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
+ intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST);
+
+ intst &= intmsk;
+
+ if (intst & JZ4780_I2C_INTST_TXABT) {
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+
+ if (intst & JZ4780_I2C_INTST_RXOF) {
+ dev_dbg(&i2c->adap.dev, "received fifo overflow!\n");
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+
+ /*
+ * When reading, always drain RX FIFO before we send more Read
+ * Commands to avoid fifo overrun
+ */
+ if (i2c->is_write == 0) {
+ int rd_left;
+
+ while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA)
+ & JZ4780_I2C_STA_RFNE)) {
+ *(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC)
+ & 0xff;
+ i2c->rd_data_xfered++;
+ if (i2c->rd_data_xfered == i2c->rd_total_len) {
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+ }
+
+ rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
+
+ if (rd_left <= JZ4780_I2C_FIFO_LEN)
+ jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
+ }
+
+ if (intst & JZ4780_I2C_INTST_TXEMP) {
+ if (i2c->is_write == 0) {
+ int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
+ int max_send = (JZ4780_I2C_FIFO_LEN - 1)
+ - (i2c->rd_cmd_xfered
+ - i2c->rd_data_xfered);
+ int cmd_to_send = min(cmd_left, max_send);
+
+ if (i2c->rd_cmd_xfered != 0)
+ cmd_to_send = min(cmd_to_send,
+ JZ4780_I2C_FIFO_LEN
+ - TX_LEVEL - 1);
+
+ if (cmd_to_send) {
+ jz4780_i2c_send_rcmd(i2c, cmd_to_send);
+ i2c->rd_cmd_xfered += cmd_to_send;
+ }
+
+ cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
+ if (cmd_left == 0) {
+ intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
+ intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+ }
+ } else {
+ unsigned short data;
+ unsigned short i2c_sta;
+
+ i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+
+ while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
+ (i2c->wt_len > 0)) {
+ i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+ data = *i2c->wbuf;
+ data &= ~JZ4780_I2C_DC_READ;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
+ data);
+ i2c->wbuf++;
+ i2c->wt_len--;
+ }
+
+ if (i2c->wt_len == 0) {
+ if (!i2c->stop_hold) {
+ tmp = jz4780_i2c_readw(i2c,
+ JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
+ tmp);
+ }
+
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+ }
+ }
+
+done:
+ spin_unlock_irqrestore(&i2c->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
+{
+ dev_dbg(&i2c->adap.dev, "txabrt: 0x%08x, cmd: %d, send: %d, recv: %d\n",
+ src, i2c->cmd, i2c->cmd_buf[i2c->cmd], i2c->data_buf[i2c->cmd]);
+}
+
+static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
+ unsigned char *buf, int len, int cnt,
+ int idx)
+{
+ int ret = 0;
+ long timeout;
+ int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
+ unsigned short tmp;
+ unsigned long flags;
+
+ memset(buf, 0, len);
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ i2c->stop_hold = 0;
+ i2c->is_write = 0;
+ i2c->rbuf = buf;
+ i2c->rd_total_len = len;
+ i2c->rd_data_xfered = 0;
+ i2c->rd_cmd_xfered = 0;
+
+ if (len <= JZ4780_I2C_FIFO_LEN)
+ jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
+ else
+ jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM,
+ JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
+ | JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp |= JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ timeout = wait_for_completion_timeout(&i2c->trans_waitq,
+ msecs_to_jiffies(wait_time));
+
+ if (!timeout) {
+ dev_err(&i2c->adap.dev, "irq read timeout\n");
+ dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n",
+ i2c->cmd, i2c->cmd_buf[i2c->cmd]);
+ dev_dbg(&i2c->adap.dev, "receive data count:%d %d\n",
+ i2c->cmd, i2c->data_buf[i2c->cmd]);
+ ret = -EIO;
+ }
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
+ if (tmp) {
+ jz4780_i2c_txabrt(i2c, tmp);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
+ unsigned char *buf, int len,
+ int cnt, int idx)
+{
+ int ret = 0;
+ int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
+ long timeout;
+ unsigned short tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ if (idx < (cnt - 1))
+ i2c->stop_hold = 1;
+ else
+ i2c->stop_hold = 0;
+
+ i2c->is_write = 1;
+ i2c->wbuf = buf;
+ i2c->wt_len = len;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
+ | JZ4780_I2C_INTM_MTXABT);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp |= JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ timeout = wait_for_completion_timeout(&i2c->trans_waitq,
+ msecs_to_jiffies(wait_time));
+ if (timeout && !i2c->stop_hold) {
+ unsigned short i2c_sta;
+ int write_in_process;
+
+ timeout = JZ4780_I2C_TIMEOUT * 100;
+ for (; timeout > 0; timeout--) {
+ i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+
+ write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) ||
+ !(i2c_sta & JZ4780_I2C_STA_TFE);
+ if (!write_in_process)
+ break;
+ udelay(10);
+ }
+ }
+
+ if (!timeout) {
+ dev_err(&i2c->adap.dev, "write wait timeout\n");
+ ret = -EIO;
+ }
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
+ if (tmp) {
+ jz4780_i2c_txabrt(i2c, tmp);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int count)
+{
+ int i = -EIO;
+ int ret = 0;
+ struct jz4780_i2c *i2c = adap->algo_data;
+
+ ret = jz4780_i2c_prepare(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "I2C prepare failed\n");
+ goto out;
+ }
+
+ if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) {
+ ret = jz4780_i2c_set_target(i2c, msg->addr);
+ if (ret)
+ goto out;
+ }
+ for (i = 0; i < count; i++, msg++) {
+ if (msg->flags & I2C_M_RD)
+ ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len,
+ count, i);
+ else
+ ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len,
+ count, i);
+
+ if (ret)
+ goto out;
+ }
+
+ ret = i;
+
+out:
+ jz4780_i2c_cleanup(i2c);
+ return ret;
+}
+
+static u32 jz4780_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm jz4780_i2c_algorithm = {
+ .master_xfer = jz4780_i2c_xfer,
+ .functionality = jz4780_i2c_functionality,
+};
+
+static const struct of_device_id jz4780_i2c_of_matches[] = {
+ { .compatible = "ingenic,jz4780-i2c", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches);
+
+static int jz4780_i2c_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ unsigned int clk_freq = 0;
+ unsigned short tmp;
+ struct resource *r;
+ struct jz4780_i2c *i2c;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &jz4780_i2c_algorithm;
+ i2c->adap.algo_data = i2c;
+ i2c->adap.retries = 5;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+ sprintf(i2c->adap.name, "%s", pdev->name);
+
+ init_completion(&i2c->trans_waitq);
+ spin_lock_init(&i2c->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->iomem = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(i2c->iomem))
+ return PTR_ERR(i2c->iomem);
+
+ platform_set_drvdata(pdev, i2c);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk))
+ return PTR_ERR(i2c->clk);
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &clk_freq);
+ if (ret) {
+ dev_err(&pdev->dev, "clock-frequency not specified in DT\n");
+ goto err;
+ }
+
+ i2c->speed = clk_freq / 1000;
+ if (i2c->speed == 0) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "clock-frequency minimum is 1000\n");
+ goto err;
+ }
+ jz4780_i2c_set_speed(i2c);
+
+ dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto err;
+ i2c->irq = ret;
+ ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
+ dev_name(&pdev->dev), i2c);
+ if (ret)
+ goto err;
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int jz4780_i2c_remove(struct platform_device *pdev)
+{
+ struct jz4780_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2c->clk);
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+}
+
+static struct platform_driver jz4780_i2c_driver = {
+ .probe = jz4780_i2c_probe,
+ .remove = jz4780_i2c_remove,
+ .driver = {
+ .name = "jz4780-i2c",
+ .of_match_table = of_match_ptr(jz4780_i2c_of_matches),
+ },
+};
+
+module_platform_driver(jz4780_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ztyan<ztyan@ingenic.cn>");
+MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs");
diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c
new file mode 100644
index 000000000..1c874aaa0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-kempld.c
@@ -0,0 +1,408 @@
+/*
+ * I2C bus driver for Kontron COM modules
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * The driver is based on the i2c-ocores driver by Peter Korsgaard.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/mfd/kempld.h>
+
+#define KEMPLD_I2C_PRELOW 0x0b
+#define KEMPLD_I2C_PREHIGH 0x0c
+#define KEMPLD_I2C_DATA 0x0e
+
+#define KEMPLD_I2C_CTRL 0x0d
+#define I2C_CTRL_IEN 0x40
+#define I2C_CTRL_EN 0x80
+
+#define KEMPLD_I2C_STAT 0x0f
+#define I2C_STAT_IF 0x01
+#define I2C_STAT_TIP 0x02
+#define I2C_STAT_ARBLOST 0x20
+#define I2C_STAT_BUSY 0x40
+#define I2C_STAT_NACK 0x80
+
+#define KEMPLD_I2C_CMD 0x0f
+#define I2C_CMD_START 0x91
+#define I2C_CMD_STOP 0x41
+#define I2C_CMD_READ 0x21
+#define I2C_CMD_WRITE 0x11
+#define I2C_CMD_READ_ACK 0x21
+#define I2C_CMD_READ_NACK 0x29
+#define I2C_CMD_IACK 0x01
+
+#define KEMPLD_I2C_FREQ_MAX 2700 /* 2.7 mHz */
+#define KEMPLD_I2C_FREQ_STD 100 /* 100 kHz */
+
+enum {
+ STATE_DONE = 0,
+ STATE_INIT,
+ STATE_ADDR,
+ STATE_ADDR10,
+ STATE_START,
+ STATE_WRITE,
+ STATE_READ,
+ STATE_ERROR,
+};
+
+struct kempld_i2c_data {
+ struct device *dev;
+ struct kempld_device_data *pld;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state;
+ bool was_active;
+};
+
+static unsigned int bus_frequency = KEMPLD_I2C_FREQ_STD;
+module_param(bus_frequency, uint, 0);
+MODULE_PARM_DESC(bus_frequency, "Set I2C bus frequency in kHz (default="
+ __MODULE_STRING(KEMPLD_I2C_FREQ_STD)")");
+
+static int i2c_bus = -1;
+module_param(i2c_bus, int, 0);
+MODULE_PARM_DESC(i2c_bus, "Set I2C bus number (default=-1 for dynamic assignment)");
+
+static bool i2c_gpio_mux;
+module_param(i2c_gpio_mux, bool, 0);
+MODULE_PARM_DESC(i2c_gpio_mux, "Enable I2C port on GPIO out (default=false)");
+
+/*
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static int kempld_i2c_process(struct kempld_i2c_data *i2c)
+{
+ struct kempld_device_data *pld = i2c->pld;
+ u8 stat = kempld_read8(pld, KEMPLD_I2C_STAT);
+ struct i2c_msg *msg = i2c->msg;
+ u8 addr;
+
+ /* Ready? */
+ if (stat & I2C_STAT_TIP)
+ return -EBUSY;
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
+ /* Stop has been sent */
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
+ if (i2c->state == STATE_ERROR)
+ return -EIO;
+ return 0;
+ }
+
+ /* Error? */
+ if (stat & I2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return -EAGAIN;
+ }
+
+ if (i2c->state == STATE_INIT) {
+ if (stat & I2C_STAT_BUSY)
+ return -EBUSY;
+
+ i2c->state = STATE_ADDR;
+ }
+
+ if (i2c->state == STATE_ADDR) {
+ /* 10 bit address? */
+ if (i2c->msg->flags & I2C_M_TEN) {
+ addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
+ /* Set read bit if necessary */
+ addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
+ i2c->state = STATE_ADDR10;
+ } else {
+ addr = i2c_8bit_addr_from_msg(i2c->msg);
+ i2c->state = STATE_START;
+ }
+
+ kempld_write8(pld, KEMPLD_I2C_DATA, addr);
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);
+
+ return 0;
+ }
+
+ /* Second part of 10 bit addressing */
+ if (i2c->state == STATE_ADDR10) {
+ kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
+
+ i2c->state = STATE_START;
+ return 0;
+ }
+
+ if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
+ i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & I2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return -ENXIO;
+ }
+ } else {
+ msg->buf[i2c->pos++] = kempld_read8(pld, KEMPLD_I2C_DATA);
+ }
+
+ if (i2c->pos >= msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) {
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ i2c->state = STATE_ADDR;
+ return 0;
+ } else {
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ }
+ } else {
+ i2c->state = STATE_DONE;
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return 0;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ kempld_write8(pld, KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
+ I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
+ } else {
+ kempld_write8(pld, KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
+ }
+
+ return 0;
+}
+
+static int kempld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct kempld_i2c_data *i2c = i2c_get_adapdata(adap);
+ struct kempld_device_data *pld = i2c->pld;
+ unsigned long timeout = jiffies + HZ;
+ int ret;
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_INIT;
+
+ /* Handle the transfer */
+ while (time_before(jiffies, timeout)) {
+ kempld_get_mutex(pld);
+ ret = kempld_i2c_process(i2c);
+ kempld_release_mutex(pld);
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR)
+ return (i2c->state == STATE_DONE) ? num : ret;
+
+ if (ret == 0)
+ timeout = jiffies + HZ;
+
+ usleep_range(5, 15);
+ }
+
+ i2c->state = STATE_ERROR;
+
+ return -ETIMEDOUT;
+}
+
+/*
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
+{
+ struct kempld_device_data *pld = i2c->pld;
+ u16 prescale_corr;
+ long prescale;
+ u8 ctrl;
+ u8 stat;
+ u8 cfg;
+
+ /* Make sure the device is disabled */
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+ ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+
+ if (bus_frequency > KEMPLD_I2C_FREQ_MAX)
+ bus_frequency = KEMPLD_I2C_FREQ_MAX;
+
+ if (pld->info.spec_major == 1)
+ prescale = pld->pld_clock / (bus_frequency * 5) - 1000;
+ else
+ prescale = pld->pld_clock / (bus_frequency * 4) - 3000;
+
+ if (prescale < 0)
+ prescale = 0;
+
+ /* Round to the best matching value */
+ prescale_corr = prescale / 1000;
+ if (prescale % 1000 >= 500)
+ prescale_corr++;
+
+ kempld_write8(pld, KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
+ kempld_write8(pld, KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
+
+ /* Activate I2C bus output on GPIO pins */
+ cfg = kempld_read8(pld, KEMPLD_CFG);
+ if (i2c_gpio_mux)
+ cfg |= KEMPLD_CFG_GPIO_I2C_MUX;
+ else
+ cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
+ kempld_write8(pld, KEMPLD_CFG, cfg);
+
+ /* Enable the device */
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
+ ctrl |= I2C_CTRL_EN;
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+
+ stat = kempld_read8(pld, KEMPLD_I2C_STAT);
+ if (stat & I2C_STAT_BUSY)
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+}
+
+static u32 kempld_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm kempld_i2c_algorithm = {
+ .master_xfer = kempld_i2c_xfer,
+ .functionality = kempld_i2c_func,
+};
+
+static const struct i2c_adapter kempld_i2c_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-kempld",
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &kempld_i2c_algorithm,
+};
+
+static int kempld_i2c_probe(struct platform_device *pdev)
+{
+ struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
+ struct kempld_i2c_data *i2c;
+ int ret;
+ u8 ctrl;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->pld = pld;
+ i2c->dev = &pdev->dev;
+ i2c->adap = kempld_i2c_adapter;
+ i2c->adap.dev.parent = i2c->dev;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ kempld_get_mutex(pld);
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+
+ if (ctrl & I2C_CTRL_EN)
+ i2c->was_active = true;
+
+ kempld_i2c_device_init(i2c);
+ kempld_release_mutex(pld);
+
+ /* Add I2C adapter to I2C tree */
+ if (i2c_bus >= -1)
+ i2c->adap.nr = i2c_bus;
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret)
+ return ret;
+
+ dev_info(i2c->dev, "I2C bus initialized at %dkHz\n",
+ bus_frequency);
+
+ return 0;
+}
+
+static int kempld_i2c_remove(struct platform_device *pdev)
+{
+ struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
+ struct kempld_device_data *pld = i2c->pld;
+ u8 ctrl;
+
+ kempld_get_mutex(pld);
+ /*
+ * Disable I2C logic if it was not activated before the
+ * driver loaded
+ */
+ if (!i2c->was_active) {
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+ ctrl &= ~I2C_CTRL_EN;
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+ }
+ kempld_release_mutex(pld);
+
+ i2c_del_adapter(&i2c->adap);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
+ struct kempld_device_data *pld = i2c->pld;
+ u8 ctrl;
+
+ kempld_get_mutex(pld);
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+ ctrl &= ~I2C_CTRL_EN;
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+
+static int kempld_i2c_resume(struct platform_device *pdev)
+{
+ struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
+ struct kempld_device_data *pld = i2c->pld;
+
+ kempld_get_mutex(pld);
+ kempld_i2c_device_init(i2c);
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+#else
+#define kempld_i2c_suspend NULL
+#define kempld_i2c_resume NULL
+#endif
+
+static struct platform_driver kempld_i2c_driver = {
+ .driver = {
+ .name = "kempld-i2c",
+ },
+ .probe = kempld_i2c_probe,
+ .remove = kempld_i2c_remove,
+ .suspend = kempld_i2c_suspend,
+ .resume = kempld_i2c_resume,
+};
+
+module_platform_driver(kempld_i2c_driver);
+
+MODULE_DESCRIPTION("KEM PLD I2C Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld_i2c");
diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c
new file mode 100644
index 000000000..59167c018
--- /dev/null
+++ b/drivers/i2c/busses/i2c-lpc2k.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2011 NXP Semiconductors
+ *
+ * Code portions referenced from the i2x-pxa and i2c-pnx drivers
+ *
+ * Make SMBus byte and word transactions work on LPC178x/7x
+ * Copyright (c) 2012
+ * Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com
+ * Anton Protopopov, Emcraft Systems, antonp@emcraft.com
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+
+/* LPC24xx register offsets and bits */
+#define LPC24XX_I2CONSET 0x00
+#define LPC24XX_I2STAT 0x04
+#define LPC24XX_I2DAT 0x08
+#define LPC24XX_I2ADDR 0x0c
+#define LPC24XX_I2SCLH 0x10
+#define LPC24XX_I2SCLL 0x14
+#define LPC24XX_I2CONCLR 0x18
+
+#define LPC24XX_AA BIT(2)
+#define LPC24XX_SI BIT(3)
+#define LPC24XX_STO BIT(4)
+#define LPC24XX_STA BIT(5)
+#define LPC24XX_I2EN BIT(6)
+
+#define LPC24XX_STO_AA (LPC24XX_STO | LPC24XX_AA)
+#define LPC24XX_CLEAR_ALL (LPC24XX_AA | LPC24XX_SI | LPC24XX_STO | \
+ LPC24XX_STA | LPC24XX_I2EN)
+
+/* I2C SCL clock has different duty cycle depending on mode */
+#define I2C_STD_MODE_DUTY 46
+#define I2C_FAST_MODE_DUTY 36
+#define I2C_FAST_MODE_PLUS_DUTY 38
+
+/*
+ * 26 possible I2C status codes, but codes applicable only
+ * to master are listed here and used in this driver
+ */
+enum {
+ M_BUS_ERROR = 0x00,
+ M_START = 0x08,
+ M_REPSTART = 0x10,
+ MX_ADDR_W_ACK = 0x18,
+ MX_ADDR_W_NACK = 0x20,
+ MX_DATA_W_ACK = 0x28,
+ MX_DATA_W_NACK = 0x30,
+ M_DATA_ARB_LOST = 0x38,
+ MR_ADDR_R_ACK = 0x40,
+ MR_ADDR_R_NACK = 0x48,
+ MR_DATA_R_ACK = 0x50,
+ MR_DATA_R_NACK = 0x58,
+ M_I2C_IDLE = 0xf8,
+};
+
+struct lpc2k_i2c {
+ void __iomem *base;
+ struct clk *clk;
+ int irq;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int msg_idx;
+ int msg_status;
+ int is_last;
+};
+
+static void i2c_lpc2k_reset(struct lpc2k_i2c *i2c)
+{
+ /* Will force clear all statuses */
+ writel(LPC24XX_CLEAR_ALL, i2c->base + LPC24XX_I2CONCLR);
+ writel(0, i2c->base + LPC24XX_I2ADDR);
+ writel(LPC24XX_I2EN, i2c->base + LPC24XX_I2CONSET);
+}
+
+static int i2c_lpc2k_clear_arb(struct lpc2k_i2c *i2c)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+ /*
+ * If the transfer needs to abort for some reason, we'll try to
+ * force a stop condition to clear any pending bus conditions
+ */
+ writel(LPC24XX_STO, i2c->base + LPC24XX_I2CONSET);
+
+ /* Wait for status change */
+ while (readl(i2c->base + LPC24XX_I2STAT) != M_I2C_IDLE) {
+ if (time_after(jiffies, timeout)) {
+ /* Bus was not idle, try to reset adapter */
+ i2c_lpc2k_reset(i2c);
+ return -EBUSY;
+ }
+
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c)
+{
+ unsigned char data;
+ u32 status;
+
+ /*
+ * I2C in the LPC2xxx series is basically a state machine.
+ * Just run through the steps based on the current status.
+ */
+ status = readl(i2c->base + LPC24XX_I2STAT);
+
+ switch (status) {
+ case M_START:
+ case M_REPSTART:
+ /* Start bit was just sent out, send out addr and dir */
+ data = i2c_8bit_addr_from_msg(i2c->msg);
+
+ writel(data, i2c->base + LPC24XX_I2DAT);
+ writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR);
+ break;
+
+ case MX_ADDR_W_ACK:
+ case MX_DATA_W_ACK:
+ /*
+ * Address or data was sent out with an ACK. If there is more
+ * data to send, send it now
+ */
+ if (i2c->msg_idx < i2c->msg->len) {
+ writel(i2c->msg->buf[i2c->msg_idx],
+ i2c->base + LPC24XX_I2DAT);
+ } else if (i2c->is_last) {
+ /* Last message, send stop */
+ writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET);
+ writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR);
+ i2c->msg_status = 0;
+ disable_irq_nosync(i2c->irq);
+ } else {
+ i2c->msg_status = 0;
+ disable_irq_nosync(i2c->irq);
+ }
+
+ i2c->msg_idx++;
+ break;
+
+ case MR_ADDR_R_ACK:
+ /* Receive first byte from slave */
+ if (i2c->msg->len == 1) {
+ /* Last byte, return NACK */
+ writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR);
+ } else {
+ /* Not last byte, return ACK */
+ writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET);
+ }
+
+ writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR);
+ break;
+
+ case MR_DATA_R_NACK:
+ /*
+ * The I2C shows NACK status on reads, so we need to accept
+ * the NACK as an ACK here. This should be ok, as the real
+ * BACK would of been caught on the address write.
+ */
+ case MR_DATA_R_ACK:
+ /* Data was received */
+ if (i2c->msg_idx < i2c->msg->len) {
+ i2c->msg->buf[i2c->msg_idx] =
+ readl(i2c->base + LPC24XX_I2DAT);
+ }
+
+ /* If transfer is done, send STOP */
+ if (i2c->msg_idx >= i2c->msg->len - 1 && i2c->is_last) {
+ writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET);
+ writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR);
+ i2c->msg_status = 0;
+ }
+
+ /* Message is done */
+ if (i2c->msg_idx >= i2c->msg->len - 1) {
+ i2c->msg_status = 0;
+ disable_irq_nosync(i2c->irq);
+ }
+
+ /*
+ * One pre-last data input, send NACK to tell the slave that
+ * this is going to be the last data byte to be transferred.
+ */
+ if (i2c->msg_idx >= i2c->msg->len - 2) {
+ /* One byte left to receive - NACK */
+ writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR);
+ } else {
+ /* More than one byte left to receive - ACK */
+ writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET);
+ }
+
+ writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR);
+ i2c->msg_idx++;
+ break;
+
+ case MX_ADDR_W_NACK:
+ case MX_DATA_W_NACK:
+ case MR_ADDR_R_NACK:
+ /* NACK processing is done */
+ writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET);
+ i2c->msg_status = -ENXIO;
+ disable_irq_nosync(i2c->irq);
+ break;
+
+ case M_DATA_ARB_LOST:
+ /* Arbitration lost */
+ i2c->msg_status = -EAGAIN;
+
+ /* Release the I2C bus */
+ writel(LPC24XX_STA | LPC24XX_STO, i2c->base + LPC24XX_I2CONCLR);
+ disable_irq_nosync(i2c->irq);
+ break;
+
+ default:
+ /* Unexpected statuses */
+ i2c->msg_status = -EIO;
+ disable_irq_nosync(i2c->irq);
+ break;
+ }
+
+ /* Exit on failure or all bytes transferred */
+ if (i2c->msg_status != -EBUSY)
+ wake_up(&i2c->wait);
+
+ /*
+ * If `msg_status` is zero, then `lpc2k_process_msg()`
+ * is responsible for clearing the SI flag.
+ */
+ if (i2c->msg_status != 0)
+ writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR);
+}
+
+static int lpc2k_process_msg(struct lpc2k_i2c *i2c, int msgidx)
+{
+ /* A new transfer is kicked off by initiating a start condition */
+ if (!msgidx) {
+ writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET);
+ } else {
+ /*
+ * A multi-message I2C transfer continues where the
+ * previous I2C transfer left off and uses the
+ * current condition of the I2C adapter.
+ */
+ if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) {
+ WARN_ON(i2c->msg->len == 0);
+
+ if (!(i2c->msg->flags & I2C_M_RD)) {
+ /* Start transmit of data */
+ writel(i2c->msg->buf[0],
+ i2c->base + LPC24XX_I2DAT);
+ i2c->msg_idx++;
+ }
+ } else {
+ /* Start or repeated start */
+ writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET);
+ }
+
+ writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR);
+ }
+
+ enable_irq(i2c->irq);
+
+ /* Wait for transfer completion */
+ if (wait_event_timeout(i2c->wait, i2c->msg_status != -EBUSY,
+ msecs_to_jiffies(1000)) == 0) {
+ disable_irq_nosync(i2c->irq);
+
+ return -ETIMEDOUT;
+ }
+
+ return i2c->msg_status;
+}
+
+static int i2c_lpc2k_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int msg_num)
+{
+ struct lpc2k_i2c *i2c = i2c_get_adapdata(adap);
+ int ret, i;
+ u32 stat;
+
+ /* Check for bus idle condition */
+ stat = readl(i2c->base + LPC24XX_I2STAT);
+ if (stat != M_I2C_IDLE) {
+ /* Something is holding the bus, try to clear it */
+ return i2c_lpc2k_clear_arb(i2c);
+ }
+
+ /* Process a single message at a time */
+ for (i = 0; i < msg_num; i++) {
+ /* Save message pointer and current message data index */
+ i2c->msg = &msgs[i];
+ i2c->msg_idx = 0;
+ i2c->msg_status = -EBUSY;
+ i2c->is_last = (i == (msg_num - 1));
+
+ ret = lpc2k_process_msg(i2c, i);
+ if (ret)
+ return ret;
+ }
+
+ return msg_num;
+}
+
+static irqreturn_t i2c_lpc2k_handler(int irq, void *dev_id)
+{
+ struct lpc2k_i2c *i2c = dev_id;
+
+ if (readl(i2c->base + LPC24XX_I2CONSET) & LPC24XX_SI) {
+ i2c_lpc2k_pump_msg(i2c);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static u32 i2c_lpc2k_functionality(struct i2c_adapter *adap)
+{
+ /* Only emulated SMBus for now */
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm i2c_lpc2k_algorithm = {
+ .master_xfer = i2c_lpc2k_xfer,
+ .functionality = i2c_lpc2k_functionality,
+};
+
+static int i2c_lpc2k_probe(struct platform_device *pdev)
+{
+ struct lpc2k_i2c *i2c;
+ struct resource *res;
+ u32 bus_clk_rate;
+ u32 scl_high;
+ u32 clkrate;
+ int ret;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ i2c->irq = platform_get_irq(pdev, 0);
+ if (i2c->irq < 0) {
+ dev_err(&pdev->dev, "can't get interrupt resource\n");
+ return i2c->irq;
+ }
+
+ init_waitqueue_head(&i2c->wait);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "error getting clock\n");
+ return PTR_ERR(i2c->clk);
+ }
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable clock.\n");
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev, i2c->irq, i2c_lpc2k_handler, 0,
+ dev_name(&pdev->dev), i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't request interrupt.\n");
+ goto fail_clk;
+ }
+
+ disable_irq_nosync(i2c->irq);
+
+ /* Place controller is a known state */
+ i2c_lpc2k_reset(i2c);
+
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &bus_clk_rate);
+ if (ret)
+ bus_clk_rate = 100000; /* 100 kHz default clock rate */
+
+ clkrate = clk_get_rate(i2c->clk);
+ if (clkrate == 0) {
+ dev_err(&pdev->dev, "can't get I2C base clock\n");
+ ret = -EINVAL;
+ goto fail_clk;
+ }
+
+ /* Setup I2C dividers to generate clock with proper duty cycle */
+ clkrate = clkrate / bus_clk_rate;
+ if (bus_clk_rate <= 100000)
+ scl_high = (clkrate * I2C_STD_MODE_DUTY) / 100;
+ else if (bus_clk_rate <= 400000)
+ scl_high = (clkrate * I2C_FAST_MODE_DUTY) / 100;
+ else
+ scl_high = (clkrate * I2C_FAST_MODE_PLUS_DUTY) / 100;
+
+ writel(scl_high, i2c->base + LPC24XX_I2SCLH);
+ writel(clkrate - scl_high, i2c->base + LPC24XX_I2SCLL);
+
+ platform_set_drvdata(pdev, i2c);
+
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.owner = THIS_MODULE;
+ strlcpy(i2c->adap.name, "LPC2K I2C adapter", sizeof(i2c->adap.name));
+ i2c->adap.algo = &i2c_lpc2k_algorithm;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0)
+ goto fail_clk;
+
+ dev_info(&pdev->dev, "LPC2K I2C adapter\n");
+
+ return 0;
+
+fail_clk:
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int i2c_lpc2k_remove(struct platform_device *dev)
+{
+ struct lpc2k_i2c *i2c = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_lpc2k_suspend(struct device *dev)
+{
+ struct lpc2k_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_disable(i2c->clk);
+
+ return 0;
+}
+
+static int i2c_lpc2k_resume(struct device *dev)
+{
+ struct lpc2k_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_enable(i2c->clk);
+ i2c_lpc2k_reset(i2c);
+
+ return 0;
+}
+
+static const struct dev_pm_ops i2c_lpc2k_dev_pm_ops = {
+ .suspend_noirq = i2c_lpc2k_suspend,
+ .resume_noirq = i2c_lpc2k_resume,
+};
+
+#define I2C_LPC2K_DEV_PM_OPS (&i2c_lpc2k_dev_pm_ops)
+#else
+#define I2C_LPC2K_DEV_PM_OPS NULL
+#endif
+
+static const struct of_device_id lpc2k_i2c_match[] = {
+ { .compatible = "nxp,lpc1788-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lpc2k_i2c_match);
+
+static struct platform_driver i2c_lpc2k_driver = {
+ .probe = i2c_lpc2k_probe,
+ .remove = i2c_lpc2k_remove,
+ .driver = {
+ .name = "lpc2k-i2c",
+ .pm = I2C_LPC2K_DEV_PM_OPS,
+ .of_match_table = lpc2k_i2c_match,
+ },
+};
+module_platform_driver(i2c_lpc2k_driver);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_DESCRIPTION("I2C driver for LPC2xxx devices");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc2k-i2c");
diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
new file mode 100644
index 000000000..f48e637f1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -0,0 +1,505 @@
+/*
+ * I2C bus driver for Amlogic Meson SoCs
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.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/bitfield.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* Meson I2C register map */
+#define REG_CTRL 0x00
+#define REG_SLAVE_ADDR 0x04
+#define REG_TOK_LIST0 0x08
+#define REG_TOK_LIST1 0x0c
+#define REG_TOK_WDATA0 0x10
+#define REG_TOK_WDATA1 0x14
+#define REG_TOK_RDATA0 0x18
+#define REG_TOK_RDATA1 0x1c
+
+/* Control register fields */
+#define REG_CTRL_START BIT(0)
+#define REG_CTRL_ACK_IGNORE BIT(1)
+#define REG_CTRL_STATUS BIT(2)
+#define REG_CTRL_ERROR BIT(3)
+#define REG_CTRL_CLKDIV GENMASK(21, 12)
+#define REG_CTRL_CLKDIVEXT GENMASK(29, 28)
+
+#define REG_SLV_ADDR GENMASK(7, 0)
+#define REG_SLV_SDA_FILTER GENMASK(10, 8)
+#define REG_SLV_SCL_FILTER GENMASK(13, 11)
+#define REG_SLV_SCL_LOW GENMASK(27, 16)
+#define REG_SLV_SCL_LOW_EN BIT(28)
+
+#define I2C_TIMEOUT_MS 500
+#define FILTER_DELAY 15
+
+enum {
+ TOKEN_END = 0,
+ TOKEN_START,
+ TOKEN_SLAVE_ADDR_WRITE,
+ TOKEN_SLAVE_ADDR_READ,
+ TOKEN_DATA,
+ TOKEN_DATA_LAST,
+ TOKEN_STOP,
+};
+
+enum {
+ STATE_IDLE,
+ STATE_READ,
+ STATE_WRITE,
+};
+
+struct meson_i2c_data {
+ unsigned char div_factor;
+};
+
+/**
+ * struct meson_i2c - Meson I2C device private data
+ *
+ * @adap: I2C adapter instance
+ * @dev: Pointer to device structure
+ * @regs: Base address of the device memory mapped registers
+ * @clk: Pointer to clock structure
+ * @msg: Pointer to the current I2C message
+ * @state: Current state in the driver state machine
+ * @last: Flag set for the last message in the transfer
+ * @count: Number of bytes to be sent/received in current transfer
+ * @pos: Current position in the send/receive buffer
+ * @error: Flag set when an error is received
+ * @lock: To avoid race conditions between irq handler and xfer code
+ * @done: Completion used to wait for transfer termination
+ * @tokens: Sequence of tokens to be written to the device
+ * @num_tokens: Number of tokens
+ * @data: Pointer to the controlller's platform data
+ */
+struct meson_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+
+ struct i2c_msg *msg;
+ int state;
+ bool last;
+ int count;
+ int pos;
+ int error;
+
+ spinlock_t lock;
+ struct completion done;
+ u32 tokens[2];
+ int num_tokens;
+
+ const struct meson_i2c_data *data;
+};
+
+static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask,
+ u32 val)
+{
+ u32 data;
+
+ data = readl(i2c->regs + reg);
+ data &= ~mask;
+ data |= val & mask;
+ writel(data, i2c->regs + reg);
+}
+
+static void meson_i2c_reset_tokens(struct meson_i2c *i2c)
+{
+ i2c->tokens[0] = 0;
+ i2c->tokens[1] = 0;
+ i2c->num_tokens = 0;
+}
+
+static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
+{
+ if (i2c->num_tokens < 8)
+ i2c->tokens[0] |= (token & 0xf) << (i2c->num_tokens * 4);
+ else
+ i2c->tokens[1] |= (token & 0xf) << ((i2c->num_tokens % 8) * 4);
+
+ i2c->num_tokens++;
+}
+
+static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
+{
+ unsigned long clk_rate = clk_get_rate(i2c->clk);
+ unsigned int div;
+
+ div = DIV_ROUND_UP(clk_rate, freq);
+ div -= FILTER_DELAY;
+ div = DIV_ROUND_UP(div, i2c->data->div_factor);
+
+ /* clock divider has 12 bits */
+ if (div > GENMASK(11, 0)) {
+ dev_err(i2c->dev, "requested bus frequency too low\n");
+ div = GENMASK(11, 0);
+ }
+
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
+ FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
+
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
+ FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
+
+ /* Disable HIGH/LOW mode */
+ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
+
+ dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
+ clk_rate, freq, div);
+}
+
+static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len)
+{
+ u32 rdata0, rdata1;
+ int i;
+
+ rdata0 = readl(i2c->regs + REG_TOK_RDATA0);
+ rdata1 = readl(i2c->regs + REG_TOK_RDATA1);
+
+ dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__,
+ rdata0, rdata1, len);
+
+ for (i = 0; i < min(4, len); i++)
+ *buf++ = (rdata0 >> i * 8) & 0xff;
+
+ for (i = 4; i < min(8, len); i++)
+ *buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
+}
+
+static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len)
+{
+ u32 wdata0 = 0, wdata1 = 0;
+ int i;
+
+ for (i = 0; i < min(4, len); i++)
+ wdata0 |= *buf++ << (i * 8);
+
+ for (i = 4; i < min(8, len); i++)
+ wdata1 |= *buf++ << ((i - 4) * 8);
+
+ writel(wdata0, i2c->regs + REG_TOK_WDATA0);
+ writel(wdata1, i2c->regs + REG_TOK_WDATA1);
+
+ dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__,
+ wdata0, wdata1, len);
+}
+
+static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
+{
+ bool write = !(i2c->msg->flags & I2C_M_RD);
+ int i;
+
+ i2c->count = min(i2c->msg->len - i2c->pos, 8);
+
+ for (i = 0; i < i2c->count - 1; i++)
+ meson_i2c_add_token(i2c, TOKEN_DATA);
+
+ if (i2c->count) {
+ if (write || i2c->pos + i2c->count < i2c->msg->len)
+ meson_i2c_add_token(i2c, TOKEN_DATA);
+ else
+ meson_i2c_add_token(i2c, TOKEN_DATA_LAST);
+ }
+
+ if (write)
+ meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
+
+ if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len)
+ meson_i2c_add_token(i2c, TOKEN_STOP);
+
+ writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0);
+ writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
+}
+
+static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
+{
+ struct meson_i2c *i2c = dev_id;
+ unsigned int ctrl;
+
+ spin_lock(&i2c->lock);
+
+ meson_i2c_reset_tokens(i2c);
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
+ ctrl = readl(i2c->regs + REG_CTRL);
+
+ dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n",
+ i2c->state, i2c->pos, i2c->count, ctrl);
+
+ if (i2c->state == STATE_IDLE) {
+ spin_unlock(&i2c->lock);
+ return IRQ_NONE;
+ }
+
+ if (ctrl & REG_CTRL_ERROR) {
+ /*
+ * The bit is set when the IGNORE_NAK bit is cleared
+ * and the device didn't respond. In this case, the
+ * I2C controller automatically generates a STOP
+ * condition.
+ */
+ dev_dbg(i2c->dev, "error bit set\n");
+ i2c->error = -ENXIO;
+ i2c->state = STATE_IDLE;
+ complete(&i2c->done);
+ goto out;
+ }
+
+ if (i2c->state == STATE_READ && i2c->count)
+ meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
+
+ i2c->pos += i2c->count;
+
+ if (i2c->pos >= i2c->msg->len) {
+ i2c->state = STATE_IDLE;
+ complete(&i2c->done);
+ goto out;
+ }
+
+ /* Restart the processing */
+ meson_i2c_prepare_xfer(i2c);
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
+out:
+ spin_unlock(&i2c->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
+{
+ int token;
+
+ token = (msg->flags & I2C_M_RD) ? TOKEN_SLAVE_ADDR_READ :
+ TOKEN_SLAVE_ADDR_WRITE;
+
+
+ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
+ FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
+
+ meson_i2c_add_token(i2c, TOKEN_START);
+ meson_i2c_add_token(i2c, token);
+}
+
+static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
+ int last)
+{
+ unsigned long time_left, flags;
+ int ret = 0;
+
+ i2c->msg = msg;
+ i2c->last = last;
+ i2c->pos = 0;
+ i2c->count = 0;
+ i2c->error = 0;
+
+ meson_i2c_reset_tokens(i2c);
+
+ flags = (msg->flags & I2C_M_IGNORE_NAK) ? REG_CTRL_ACK_IGNORE : 0;
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_ACK_IGNORE, flags);
+
+ if (!(msg->flags & I2C_M_NOSTART))
+ meson_i2c_do_start(i2c, msg);
+
+ i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+ meson_i2c_prepare_xfer(i2c);
+ reinit_completion(&i2c->done);
+
+ /* Start the transfer */
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
+
+ time_left = msecs_to_jiffies(I2C_TIMEOUT_MS);
+ time_left = wait_for_completion_timeout(&i2c->done, time_left);
+
+ /*
+ * Protect access to i2c struct and registers from interrupt
+ * handlers triggered by a transfer terminated after the
+ * timeout period
+ */
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ /* Abort any active operation */
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
+
+ if (!time_left) {
+ i2c->state = STATE_IDLE;
+ ret = -ETIMEDOUT;
+ }
+
+ if (i2c->error)
+ ret = i2c->error;
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ return ret;
+}
+
+static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct meson_i2c *i2c = adap->algo_data;
+ int i, ret = 0;
+
+ clk_enable(i2c->clk);
+
+ for (i = 0; i < num; i++) {
+ ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1);
+ if (ret)
+ break;
+ }
+
+ clk_disable(i2c->clk);
+
+ return ret ?: i;
+}
+
+static u32 meson_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm meson_i2c_algorithm = {
+ .master_xfer = meson_i2c_xfer,
+ .functionality = meson_i2c_func,
+};
+
+static int meson_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct meson_i2c *i2c;
+ struct resource *mem;
+ struct i2c_timings timings;
+ int irq, ret = 0;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c_parse_fw_timings(&pdev->dev, &timings, true);
+
+ i2c->dev = &pdev->dev;
+ platform_set_drvdata(pdev, i2c);
+
+ spin_lock_init(&i2c->lock);
+ init_completion(&i2c->done);
+
+ i2c->data = (const struct meson_i2c_data *)
+ of_device_get_match_data(&pdev->dev);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "can't get device clock\n");
+ return PTR_ERR(i2c->clk);
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "can't find IRQ\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't request IRQ\n");
+ return ret;
+ }
+
+ ret = clk_prepare(i2c->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't prepare clock\n");
+ return ret;
+ }
+
+ strlcpy(i2c->adap.name, "Meson I2C adapter",
+ sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &meson_i2c_algorithm;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = np;
+ i2c->adap.algo_data = i2c;
+
+ /*
+ * A transfer is triggered when START bit changes from 0 to 1.
+ * Ensure that the bit is set to 0 after probe
+ */
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0) {
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+
+ /* Disable filtering */
+ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
+ REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
+
+ meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
+
+ return 0;
+}
+
+static int meson_i2c_remove(struct platform_device *pdev)
+{
+ struct meson_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static const struct meson_i2c_data i2c_meson6_data = {
+ .div_factor = 4,
+};
+
+static const struct meson_i2c_data i2c_gxbb_data = {
+ .div_factor = 4,
+};
+
+static const struct meson_i2c_data i2c_axg_data = {
+ .div_factor = 3,
+};
+
+static const struct of_device_id meson_i2c_match[] = {
+ { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data },
+ { .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data },
+ { .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, meson_i2c_match);
+
+static struct platform_driver meson_i2c_driver = {
+ .probe = meson_i2c_probe,
+ .remove = meson_i2c_remove,
+ .driver = {
+ .name = "meson-i2c",
+ .of_match_table = meson_i2c_match,
+ },
+};
+
+module_platform_driver(meson_i2c_driver);
+
+MODULE_DESCRIPTION("Amlogic Meson I2C Bus driver");
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c
new file mode 100644
index 000000000..71d7bae2c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mlxcpld.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+/* General defines */
+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000
+#define MLXCPLD_I2C_DEVICE_NAME "i2c_mlxcpld"
+#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD)
+#define MLXCPLD_I2C_BUS_NUM 1
+#define MLXCPLD_I2C_DATA_REG_SZ 36
+#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5)
+#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5)
+#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7)
+#define MLXCPLD_I2C_MAX_ADDR_LEN 4
+#define MLXCPLD_I2C_RETR_NUM 2
+#define MLXCPLD_I2C_XFER_TO 500000 /* usec */
+#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */
+
+/* LPC I2C registers */
+#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0
+#define MLXCPLD_LPCI2C_CTRL_REG 0x1
+#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4
+#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5
+#define MLXCPLD_LPCI2C_CMD_REG 0x6
+#define MLXCPLD_LPCI2C_NUM_DAT_REG 0x7
+#define MLXCPLD_LPCI2C_NUM_ADDR_REG 0x8
+#define MLXCPLD_LPCI2C_STATUS_REG 0x9
+#define MLXCPLD_LPCI2C_DATA_REG 0xa
+
+/* LPC I2C masks and parametres */
+#define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1
+#define MLXCPLD_LPCI2C_TRANS_END 0x1
+#define MLXCPLD_LPCI2C_STATUS_NACK 0x10
+#define MLXCPLD_LPCI2C_NO_IND 0
+#define MLXCPLD_LPCI2C_ACK_IND 1
+#define MLXCPLD_LPCI2C_NACK_IND 2
+
+struct mlxcpld_i2c_curr_xfer {
+ u8 cmd;
+ u8 addr_width;
+ u8 data_len;
+ u8 msg_num;
+ struct i2c_msg *msg;
+};
+
+struct mlxcpld_i2c_priv {
+ struct i2c_adapter adap;
+ u32 base_addr;
+ struct mutex lock;
+ struct mlxcpld_i2c_curr_xfer xfer;
+ struct device *dev;
+ bool smbus_block;
+};
+
+static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr)
+{
+ int i;
+
+ for (i = 0; i < len - len % 4; i += 4)
+ outl(*(u32 *)(data + i), addr + i);
+ for (; i < len; ++i)
+ outb(*(data + i), addr + i);
+}
+
+static void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr)
+{
+ int i;
+
+ for (i = 0; i < len - len % 4; i += 4)
+ *(u32 *)(data + i) = inl(addr + i);
+ for (; i < len; ++i)
+ *(data + i) = inb(addr + i);
+}
+
+static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs,
+ u8 *data, u8 datalen)
+{
+ u32 addr = priv->base_addr + offs;
+
+ switch (datalen) {
+ case 1:
+ *(data) = inb(addr);
+ break;
+ case 2:
+ *((u16 *)data) = inw(addr);
+ break;
+ case 3:
+ *((u16 *)data) = inw(addr);
+ *(data + 2) = inb(addr + 2);
+ break;
+ case 4:
+ *((u32 *)data) = inl(addr);
+ break;
+ default:
+ mlxcpld_i2c_lpc_read_buf(data, datalen, addr);
+ break;
+ }
+}
+
+static void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs,
+ u8 *data, u8 datalen)
+{
+ u32 addr = priv->base_addr + offs;
+
+ switch (datalen) {
+ case 1:
+ outb(*(data), addr);
+ break;
+ case 2:
+ outw(*((u16 *)data), addr);
+ break;
+ case 3:
+ outw(*((u16 *)data), addr);
+ outb(*(data + 2), addr + 2);
+ break;
+ case 4:
+ outl(*((u32 *)data), addr);
+ break;
+ default:
+ mlxcpld_i2c_lpc_write_buf(data, datalen, addr);
+ break;
+ }
+}
+
+/*
+ * Check validity of received i2c messages parameters.
+ * Returns 0 if OK, other - in case of invalid parameters.
+ */
+static int mlxcpld_i2c_check_msg_params(struct mlxcpld_i2c_priv *priv,
+ struct i2c_msg *msgs, int num)
+{
+ int i;
+
+ if (!num) {
+ dev_err(priv->dev, "Incorrect 0 num of messages\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(msgs[0].addr > 0x7f)) {
+ dev_err(priv->dev, "Invalid address 0x%03x\n",
+ msgs[0].addr);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num; ++i) {
+ if (unlikely(!msgs[i].buf)) {
+ dev_err(priv->dev, "Invalid buf in msg[%d]\n",
+ i);
+ return -EINVAL;
+ }
+ if (unlikely(msgs[0].addr != msgs[i].addr)) {
+ dev_err(priv->dev, "Invalid addr in msg[%d]\n",
+ i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Check if transfer is completed and status of operation.
+ * Returns 0 - transfer completed (both ACK or NACK),
+ * negative - transfer isn't finished.
+ */
+static int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status)
+{
+ u8 val;
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1);
+
+ if (val & MLXCPLD_LPCI2C_TRANS_END) {
+ if (val & MLXCPLD_LPCI2C_STATUS_NACK)
+ /*
+ * The slave is unable to accept the data. No such
+ * slave, command not understood, or unable to accept
+ * any more data.
+ */
+ *status = MLXCPLD_LPCI2C_NACK_IND;
+ else
+ *status = MLXCPLD_LPCI2C_ACK_IND;
+ return 0;
+ }
+ *status = MLXCPLD_LPCI2C_NO_IND;
+
+ return -EIO;
+}
+
+static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv,
+ struct i2c_msg *msgs, int num,
+ u8 comm_len)
+{
+ priv->xfer.msg = msgs;
+ priv->xfer.msg_num = num;
+
+ /*
+ * All upper layers currently are never use transfer with more than
+ * 2 messages. Actually, it's also not so relevant in Mellanox systems
+ * because of HW limitation. Max size of transfer is not more than 32
+ * or 68 bytes in the current x86 LPCI2C bridge.
+ */
+ priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD;
+
+ if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) {
+ priv->xfer.addr_width = msgs[0].len;
+ priv->xfer.data_len = comm_len - priv->xfer.addr_width;
+ } else {
+ priv->xfer.addr_width = 0;
+ priv->xfer.data_len = comm_len;
+ }
+}
+
+/* Reset CPLD LPCI2C block */
+static void mlxcpld_i2c_reset(struct mlxcpld_i2c_priv *priv)
+{
+ u8 val;
+
+ mutex_lock(&priv->lock);
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1);
+ val &= ~MLXCPLD_LPCI2C_RST_SEL_MASK;
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1);
+
+ mutex_unlock(&priv->lock);
+}
+
+/* Make sure the CPLD is ready to start transmitting. */
+static int mlxcpld_i2c_check_busy(struct mlxcpld_i2c_priv *priv)
+{
+ u8 val;
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1);
+
+ if (val & MLXCPLD_LPCI2C_TRANS_END)
+ return 0;
+
+ return -EIO;
+}
+
+static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv)
+{
+ int timeout = 0;
+
+ do {
+ if (!mlxcpld_i2c_check_busy(priv))
+ break;
+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
+ timeout += MLXCPLD_I2C_POLL_TIME;
+ } while (timeout <= MLXCPLD_I2C_XFER_TO);
+
+ if (timeout > MLXCPLD_I2C_XFER_TO)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/*
+ * Wait for master transfer to complete.
+ * It puts current process to sleep until we get interrupt or timeout expires.
+ * Returns the number of transferred or read bytes or error (<0).
+ */
+static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
+{
+ int status, i, timeout = 0;
+ u8 datalen, val;
+
+ do {
+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
+ if (!mlxcpld_i2c_check_status(priv, &status))
+ break;
+ timeout += MLXCPLD_I2C_POLL_TIME;
+ } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO);
+
+ switch (status) {
+ case MLXCPLD_LPCI2C_NO_IND:
+ return -ETIMEDOUT;
+
+ case MLXCPLD_LPCI2C_ACK_IND:
+ if (priv->xfer.cmd != I2C_M_RD)
+ return (priv->xfer.addr_width + priv->xfer.data_len);
+
+ if (priv->xfer.msg_num == 1)
+ i = 0;
+ else
+ i = 1;
+
+ if (!priv->xfer.msg[i].buf)
+ return -EINVAL;
+
+ /*
+ * Actual read data len will be always the same as
+ * requested len. 0xff (line pull-up) will be returned
+ * if slave has no data to return. Thus don't read
+ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of
+ * SMBus block read transaction data len can be different,
+ * check this case.
+ */
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val,
+ 1);
+ if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) {
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
+ &datalen, 1);
+ if (unlikely(datalen > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(priv->dev, "Incorrect smbus block read message len\n");
+ return -EPROTO;
+ }
+ } else {
+ datalen = priv->xfer.data_len;
+ }
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
+ priv->xfer.msg[i].buf, datalen);
+
+ return datalen;
+
+ case MLXCPLD_LPCI2C_NACK_IND:
+ return -ENXIO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv)
+{
+ int i, len = 0;
+ u8 cmd, val;
+
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
+ &priv->xfer.data_len, 1);
+
+ val = priv->xfer.addr_width;
+ /* Notify HW about SMBus block read transaction */
+ if (priv->smbus_block && priv->xfer.msg_num >= 2 &&
+ priv->xfer.msg[1].len == 1 &&
+ (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) &&
+ (priv->xfer.msg[1].flags & I2C_M_RD))
+ val |= MLXCPLD_I2C_SMBUS_BLK_BIT;
+
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1);
+
+ for (i = 0; i < priv->xfer.msg_num; i++) {
+ if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) {
+ /* Don't write to CPLD buffer in read transaction */
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_DATA_REG +
+ len, priv->xfer.msg[i].buf,
+ priv->xfer.msg[i].len);
+ len += priv->xfer.msg[i].len;
+ }
+ }
+
+ /*
+ * Set target slave address with command for master transfer.
+ * It should be latest executed function before CPLD transaction.
+ */
+ cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd;
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CMD_REG, &cmd, 1);
+}
+
+/*
+ * Generic lpc-i2c transfer.
+ * Returns the number of processed messages or error (<0).
+ */
+static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
+ u8 comm_len = 0;
+ int i, err;
+
+ err = mlxcpld_i2c_check_msg_params(priv, msgs, num);
+ if (err) {
+ dev_err(priv->dev, "Incorrect message\n");
+ return err;
+ }
+
+ for (i = 0; i < num; ++i)
+ comm_len += msgs[i].len;
+
+ /* Check bus state */
+ if (mlxcpld_i2c_wait_for_free(priv)) {
+ dev_err(priv->dev, "LPCI2C bridge is busy\n");
+
+ /*
+ * Usually it means something serious has happened.
+ * We can not have unfinished previous transfer
+ * so it doesn't make any sense to try to stop it.
+ * Probably we were not able to recover from the
+ * previous error.
+ * The only reasonable thing - is soft reset.
+ */
+ mlxcpld_i2c_reset(priv);
+ if (mlxcpld_i2c_check_busy(priv)) {
+ dev_err(priv->dev, "LPCI2C bridge is busy after reset\n");
+ return -EIO;
+ }
+ }
+
+ mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len);
+
+ mutex_lock(&priv->lock);
+
+ /* Do real transfer. Can't fail */
+ mlxcpld_i2c_xfer_msg(priv);
+
+ /* Wait for transaction complete */
+ err = mlxcpld_i2c_wait_for_tc(priv);
+
+ mutex_unlock(&priv->lock);
+
+ return err < 0 ? err : num;
+}
+
+static u32 mlxcpld_i2c_func(struct i2c_adapter *adap)
+{
+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (priv->smbus_block)
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA;
+ else
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm mlxcpld_i2c_algo = {
+ .master_xfer = mlxcpld_i2c_xfer,
+ .functionality = mlxcpld_i2c_func
+};
+
+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN,
+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ,
+ .max_comb_1st_msg_len = 4,
+};
+
+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN,
+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2,
+ .max_comb_1st_msg_len = 4,
+};
+
+static struct i2c_adapter mlxcpld_i2c_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-mlxcpld",
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &mlxcpld_i2c_algo,
+ .quirks = &mlxcpld_i2c_quirks,
+ .retries = MLXCPLD_I2C_RETR_NUM,
+ .nr = MLXCPLD_I2C_BUS_NUM,
+};
+
+static int mlxcpld_i2c_probe(struct platform_device *pdev)
+{
+ struct mlxcpld_i2c_priv *priv;
+ int err;
+ u8 val;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_init(&priv->lock);
+ platform_set_drvdata(pdev, priv);
+
+ priv->dev = &pdev->dev;
+ priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
+
+ /* Register with i2c layer */
+ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
+ /* Read capability register */
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1);
+ /* Check support for extended transaction length */
+ if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT)
+ mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext;
+ /* Check support for smbus block transaction */
+ if (val & MLXCPLD_I2C_SMBUS_BLK_BIT)
+ priv->smbus_block = true;
+ if (pdev->id >= -1)
+ mlxcpld_i2c_adapter.nr = pdev->id;
+ priv->adap = mlxcpld_i2c_adapter;
+ priv->adap.dev.parent = &pdev->dev;
+ i2c_set_adapdata(&priv->adap, priv);
+
+ err = i2c_add_numbered_adapter(&priv->adap);
+ if (err)
+ mutex_destroy(&priv->lock);
+
+ return err;
+}
+
+static int mlxcpld_i2c_remove(struct platform_device *pdev)
+{
+ struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ mutex_destroy(&priv->lock);
+
+ return 0;
+}
+
+static struct platform_driver mlxcpld_i2c_driver = {
+ .probe = mlxcpld_i2c_probe,
+ .remove = mlxcpld_i2c_remove,
+ .driver = {
+ .name = MLXCPLD_I2C_DEVICE_NAME,
+ },
+};
+
+module_platform_driver(mlxcpld_i2c_driver);
+
+MODULE_AUTHOR("Michael Shych <michaels@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:i2c-mlxcpld");
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
new file mode 100644
index 000000000..8de8296d2
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -0,0 +1,955 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx).
+ *
+ * Release 0.8
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched/signal.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc85xx.h>
+#include <sysdev/fsl_soc.h>
+
+#define DRV_NAME "mpc-i2c"
+
+#define MPC_I2C_CLOCK_LEGACY 0
+#define MPC_I2C_CLOCK_PRESERVE (~0U)
+
+#define MPC_I2C_FDR 0x04
+#define MPC_I2C_CR 0x08
+#define MPC_I2C_SR 0x0c
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN 0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX 0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+#define CCR_RSVD 0x02
+
+#define CSR_MCF 0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB 0x20
+#define CSR_MAL 0x10
+#define CSR_SRW 0x04
+#define CSR_MIF 0x02
+#define CSR_RXAK 0x01
+
+struct mpc_i2c {
+ struct device *dev;
+ void __iomem *base;
+ u32 interrupt;
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ int irq;
+ u32 real_clk;
+#ifdef CONFIG_PM_SLEEP
+ u8 fdr, dfsrr;
+#endif
+ struct clk *clk_per;
+ bool has_errata_A004447;
+};
+
+struct mpc_i2c_divider {
+ u16 divider;
+ u16 fdr; /* including dfsrr */
+};
+
+struct mpc_i2c_data {
+ void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock);
+};
+
+static inline void writeccr(struct mpc_i2c *i2c, u32 x)
+{
+ writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+{
+ struct mpc_i2c *i2c = dev_id;
+ if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+ /* Read again to allow register to stabilise */
+ i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ wake_up(&i2c->queue);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the 9 pulses, each with a START then ending with STOP, so it's all OK.
+ */
+static void mpc_i2c_fixup(struct mpc_i2c *i2c)
+{
+ int k;
+ unsigned long flags;
+
+ for (k = 9; k; k--) {
+ writeccr(i2c, 0);
+ writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */
+ writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */
+ readb(i2c->base + MPC_I2C_DR); /* init xfer */
+ udelay(15); /* let it hit the bus */
+ local_irq_save(flags); /* should not be delayed further */
+ writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */
+ readb(i2c->base + MPC_I2C_DR);
+ if (k != 1)
+ udelay(5);
+ local_irq_restore(flags);
+ }
+ writeccr(i2c, CCR_MEN); /* Initiate STOP */
+ readb(i2c->base + MPC_I2C_DR);
+ udelay(15); /* Let STOP propagate */
+ writeccr(i2c, 0);
+}
+
+static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
+{
+ unsigned long orig_jiffies = jiffies;
+ u32 cmd_err;
+ int result = 0;
+
+ if (!i2c->irq) {
+ while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+ schedule();
+ if (time_after(jiffies, orig_jiffies + timeout)) {
+ dev_dbg(i2c->dev, "timeout\n");
+ writeccr(i2c, 0);
+ result = -ETIMEDOUT;
+ break;
+ }
+ }
+ cmd_err = readb(i2c->base + MPC_I2C_SR);
+ writeb(0, i2c->base + MPC_I2C_SR);
+ } else {
+ /* Interrupt mode */
+ result = wait_event_timeout(i2c->queue,
+ (i2c->interrupt & CSR_MIF), timeout);
+
+ if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+ dev_dbg(i2c->dev, "wait timeout\n");
+ writeccr(i2c, 0);
+ result = -ETIMEDOUT;
+ }
+
+ cmd_err = i2c->interrupt;
+ i2c->interrupt = 0;
+ }
+
+ if (result < 0)
+ return result;
+
+ if (!(cmd_err & CSR_MCF)) {
+ dev_dbg(i2c->dev, "unfinished\n");
+ return -EIO;
+ }
+
+ if (cmd_err & CSR_MAL) {
+ dev_dbg(i2c->dev, "MAL\n");
+ return -EAGAIN;
+ }
+
+ if (writing && (cmd_err & CSR_RXAK)) {
+ dev_dbg(i2c->dev, "No RXAK\n");
+ /* generate stop */
+ writeccr(i2c, CCR_MEN);
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask)
+{
+ void __iomem *addr = i2c->base + MPC_I2C_SR;
+ u8 val;
+
+ return readb_poll_timeout(addr, val, val & mask, 0, 100);
+}
+
+/*
+ * Workaround for Erratum A004447. From the P2040CE Rev Q
+ *
+ * 1. Set up the frequency divider and sampling rate.
+ * 2. I2CCR - a0h
+ * 3. Poll for I2CSR[MBB] to get set.
+ * 4. If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to
+ * step 5. If MAL is not set, then go to step 13.
+ * 5. I2CCR - 00h
+ * 6. I2CCR - 22h
+ * 7. I2CCR - a2h
+ * 8. Poll for I2CSR[MBB] to get set.
+ * 9. Issue read to I2CDR.
+ * 10. Poll for I2CSR[MIF] to be set.
+ * 11. I2CCR - 82h
+ * 12. Workaround complete. Skip the next steps.
+ * 13. Issue read to I2CDR.
+ * 14. Poll for I2CSR[MIF] to be set.
+ * 15. I2CCR - 80h
+ */
+static void mpc_i2c_fixup_A004447(struct mpc_i2c *i2c)
+{
+ int ret;
+ u32 val;
+
+ writeccr(i2c, CCR_MEN | CCR_MSTA);
+ ret = i2c_mpc_wait_sr(i2c, CSR_MBB);
+ if (ret) {
+ dev_err(i2c->dev, "timeout waiting for CSR_MBB\n");
+ return;
+ }
+
+ val = readb(i2c->base + MPC_I2C_SR);
+
+ if (val & CSR_MAL) {
+ writeccr(i2c, 0x00);
+ writeccr(i2c, CCR_MSTA | CCR_RSVD);
+ writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSVD);
+ ret = i2c_mpc_wait_sr(i2c, CSR_MBB);
+ if (ret) {
+ dev_err(i2c->dev, "timeout waiting for CSR_MBB\n");
+ return;
+ }
+ val = readb(i2c->base + MPC_I2C_DR);
+ ret = i2c_mpc_wait_sr(i2c, CSR_MIF);
+ if (ret) {
+ dev_err(i2c->dev, "timeout waiting for CSR_MIF\n");
+ return;
+ }
+ writeccr(i2c, CCR_MEN | CCR_RSVD);
+ } else {
+ val = readb(i2c->base + MPC_I2C_DR);
+ ret = i2c_mpc_wait_sr(i2c, CSR_MIF);
+ if (ret) {
+ dev_err(i2c->dev, "timeout waiting for CSR_MIF\n");
+ return;
+ }
+ writeccr(i2c, CCR_MEN);
+ }
+}
+
+#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
+ {20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
+ {28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
+ {36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28},
+ {52, 0x63}, {56, 0x29}, {60, 0x41}, {64, 0x2a},
+ {68, 0x07}, {72, 0x2b}, {80, 0x2c}, {88, 0x09},
+ {96, 0x2d}, {104, 0x0a}, {112, 0x2e}, {120, 0x81},
+ {128, 0x2f}, {136, 0x47}, {144, 0x0c}, {160, 0x30},
+ {176, 0x49}, {192, 0x31}, {208, 0x4a}, {224, 0x32},
+ {240, 0x0f}, {256, 0x33}, {272, 0x87}, {288, 0x10},
+ {320, 0x34}, {352, 0x89}, {384, 0x35}, {416, 0x8a},
+ {448, 0x36}, {480, 0x13}, {512, 0x37}, {576, 0x14},
+ {640, 0x38}, {768, 0x39}, {896, 0x3a}, {960, 0x17},
+ {1024, 0x3b}, {1152, 0x18}, {1280, 0x3c}, {1536, 0x3d},
+ {1792, 0x3e}, {1920, 0x1b}, {2048, 0x3f}, {2304, 0x1c},
+ {2560, 0x1d}, {3072, 0x1e}, {3584, 0x7e}, {3840, 0x1f},
+ {4096, 0x7f}, {4608, 0x5c}, {5120, 0x5d}, {6144, 0x5e},
+ {7168, 0xbe}, {7680, 0x5f}, {8192, 0xbf}, {9216, 0x9c},
+ {10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
+};
+
+static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+ u32 *real_clk)
+{
+ const struct mpc_i2c_divider *div = NULL;
+ unsigned int pvr = mfspr(SPRN_PVR);
+ u32 divider;
+ int i;
+
+ if (clock == MPC_I2C_CLOCK_LEGACY) {
+ /* see below - default fdr = 0x3f -> div = 2048 */
+ *real_clk = mpc5xxx_get_bus_frequency(node) / 2048;
+ return -EINVAL;
+ }
+
+ /* Determine divider value */
+ divider = mpc5xxx_get_bus_frequency(node) / clock;
+
+ /*
+ * We want to choose an FDR/DFSR that generates an I2C bus speed that
+ * is equal to or lower than the requested speed.
+ */
+ for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_52xx); i++) {
+ div = &mpc_i2c_dividers_52xx[i];
+ /* Old MPC5200 rev A CPUs do not support the high bits */
+ if (div->fdr & 0xc0 && pvr == 0x80822011)
+ continue;
+ if (div->divider >= divider)
+ break;
+ }
+
+ *real_clk = mpc5xxx_get_bus_frequency(node) / div->divider;
+ return (int)div->fdr;
+}
+
+static void mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock)
+{
+ int ret, fdr;
+
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using fdr %d\n",
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
+ ret = mpc_i2c_get_fdr_52xx(node, clock, &i2c->real_clk);
+ fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
+
+ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+
+ if (ret >= 0)
+ dev_info(i2c->dev, "clock %u Hz (fdr=%d)\n", i2c->real_clk,
+ fdr);
+}
+#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
+static void mpc_i2c_setup_52xx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock)
+{
+}
+#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_PPC_MPC512x
+static void mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock)
+{
+ struct device_node *node_ctrl;
+ void __iomem *ctrl;
+ const u32 *pval;
+ u32 idx;
+
+ /* Enable I2C interrupts for mpc5121 */
+ node_ctrl = of_find_compatible_node(NULL, NULL,
+ "fsl,mpc5121-i2c-ctrl");
+ if (node_ctrl) {
+ ctrl = of_iomap(node_ctrl, 0);
+ if (ctrl) {
+ /* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */
+ pval = of_get_property(node, "reg", NULL);
+ idx = (*pval & 0xff) / 0x20;
+ setbits32(ctrl, 1 << (24 + idx * 2));
+ iounmap(ctrl);
+ }
+ of_node_put(node_ctrl);
+ }
+
+ /* The clock setup for the 52xx works also fine for the 512x */
+ mpc_i2c_setup_52xx(node, i2c, clock);
+}
+#else /* CONFIG_PPC_MPC512x */
+static void mpc_i2c_setup_512x(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock)
+{
+}
+#endif /* CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_FSL_SOC
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
+ {160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123},
+ {288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102},
+ {416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127},
+ {544, 0x0b03}, {576, 0x0104}, {608, 0x1603}, {640, 0x0105},
+ {672, 0x2003}, {704, 0x0b05}, {736, 0x2b03}, {768, 0x0106},
+ {800, 0x3603}, {832, 0x0b06}, {896, 0x012a}, {960, 0x0107},
+ {1024, 0x012b}, {1088, 0x1607}, {1152, 0x0108}, {1216, 0x2b07},
+ {1280, 0x0109}, {1408, 0x1609}, {1536, 0x010a}, {1664, 0x160a},
+ {1792, 0x012e}, {1920, 0x010b}, {2048, 0x012f}, {2176, 0x2b0b},
+ {2304, 0x010c}, {2560, 0x010d}, {2816, 0x2b0d}, {3072, 0x010e},
+ {3328, 0x2b0e}, {3584, 0x0132}, {3840, 0x010f}, {4096, 0x0133},
+ {4608, 0x0110}, {5120, 0x0111}, {6144, 0x0112}, {7168, 0x0136},
+ {7680, 0x0113}, {8192, 0x0137}, {9216, 0x0114}, {10240, 0x0115},
+ {12288, 0x0116}, {14336, 0x013a}, {15360, 0x0117}, {16384, 0x013b},
+ {18432, 0x0118}, {20480, 0x0119}, {24576, 0x011a}, {28672, 0x013e},
+ {30720, 0x011b}, {32768, 0x013f}, {36864, 0x011c}, {40960, 0x011d},
+ {49152, 0x011e}, {61440, 0x011f}
+};
+
+static u32 mpc_i2c_get_sec_cfg_8xxx(void)
+{
+ struct device_node *node;
+ u32 __iomem *reg;
+ u32 val = 0;
+
+ node = of_find_node_by_name(NULL, "global-utilities");
+ if (node) {
+ const u32 *prop = of_get_property(node, "reg", NULL);
+ if (prop) {
+ /*
+ * Map and check POR Device Status Register 2
+ * (PORDEVSR2) at 0xE0014. Note than while MPC8533
+ * and MPC8544 indicate SEC frequency ratio
+ * configuration as bit 26 in PORDEVSR2, other MPC8xxx
+ * parts may store it differently or may not have it
+ * at all.
+ */
+ reg = ioremap(get_immrbase() + *prop + 0x14, 0x4);
+ if (!reg)
+ printk(KERN_ERR
+ "Error: couldn't map PORDEVSR2\n");
+ else
+ val = in_be32(reg) & 0x00000020; /* sec-cfg */
+ iounmap(reg);
+ }
+ }
+ of_node_put(node);
+
+ return val;
+}
+
+static u32 mpc_i2c_get_prescaler_8xxx(void)
+{
+ /*
+ * According to the AN2919 all MPC824x have prescaler 1, while MPC83xx
+ * may have prescaler 1, 2, or 3, depending on the power-on
+ * configuration.
+ */
+ u32 prescaler = 1;
+
+ /* mpc85xx */
+ if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2)
+ || pvr_version_is(PVR_VER_E500MC)
+ || pvr_version_is(PVR_VER_E5500)
+ || pvr_version_is(PVR_VER_E6500)) {
+ unsigned int svr = mfspr(SPRN_SVR);
+
+ if ((SVR_SOC_VER(svr) == SVR_8540)
+ || (SVR_SOC_VER(svr) == SVR_8541)
+ || (SVR_SOC_VER(svr) == SVR_8560)
+ || (SVR_SOC_VER(svr) == SVR_8555)
+ || (SVR_SOC_VER(svr) == SVR_8610))
+ /* the above 85xx SoCs have prescaler 1 */
+ prescaler = 1;
+ else if ((SVR_SOC_VER(svr) == SVR_8533)
+ || (SVR_SOC_VER(svr) == SVR_8544))
+ /* the above 85xx SoCs have prescaler 3 or 2 */
+ prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
+ else
+ /* all the other 85xx have prescaler 2 */
+ prescaler = 2;
+ }
+
+ return prescaler;
+}
+
+static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+ u32 *real_clk)
+{
+ const struct mpc_i2c_divider *div = NULL;
+ u32 prescaler = mpc_i2c_get_prescaler_8xxx();
+ u32 divider;
+ int i;
+
+ if (clock == MPC_I2C_CLOCK_LEGACY) {
+ /* see below - default fdr = 0x1031 -> div = 16 * 3072 */
+ *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072);
+ return -EINVAL;
+ }
+
+ divider = fsl_get_sys_freq() / clock / prescaler;
+
+ pr_debug("I2C: src_clock=%d clock=%d divider=%d\n",
+ fsl_get_sys_freq(), clock, divider);
+
+ /*
+ * We want to choose an FDR/DFSR that generates an I2C bus speed that
+ * is equal to or lower than the requested speed.
+ */
+ for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_8xxx); i++) {
+ div = &mpc_i2c_dividers_8xxx[i];
+ if (div->divider >= divider)
+ break;
+ }
+
+ *real_clk = fsl_get_sys_freq() / prescaler / div->divider;
+ return div ? (int)div->fdr : -EINVAL;
+}
+
+static void mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock)
+{
+ int ret, fdr;
+
+ if (clock == MPC_I2C_CLOCK_PRESERVE) {
+ dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n",
+ readb(i2c->base + MPC_I2C_DFSRR),
+ readb(i2c->base + MPC_I2C_FDR));
+ return;
+ }
+
+ ret = mpc_i2c_get_fdr_8xxx(node, clock, &i2c->real_clk);
+ fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
+
+ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+ writeb((fdr >> 8) & 0xff, i2c->base + MPC_I2C_DFSRR);
+
+ if (ret >= 0)
+ dev_info(i2c->dev, "clock %d Hz (dfsrr=%d fdr=%d)\n",
+ i2c->real_clk, fdr >> 8, fdr & 0xff);
+}
+
+#else /* !CONFIG_FSL_SOC */
+static void mpc_i2c_setup_8xxx(struct device_node *node,
+ struct mpc_i2c *i2c,
+ u32 clock)
+{
+}
+#endif /* CONFIG_FSL_SOC */
+
+static void mpc_i2c_start(struct mpc_i2c *i2c)
+{
+ /* Clear arbitration */
+ writeb(0, i2c->base + MPC_I2C_SR);
+ /* Start with MEN */
+ writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_stop(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_write(struct mpc_i2c *i2c, int target,
+ const u8 *data, int length, int restart)
+{
+ int i, result;
+ unsigned timeout = i2c->adap.timeout;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Start as master */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target byte */
+ writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+ result = i2c_wait(i2c, timeout, 1);
+ if (result < 0)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ /* Write data byte */
+ writeb(data[i], i2c->base + MPC_I2C_DR);
+
+ result = i2c_wait(i2c, timeout, 1);
+ if (result < 0)
+ return result;
+ }
+
+ return 0;
+}
+
+static int mpc_read(struct mpc_i2c *i2c, int target,
+ u8 *data, int length, int restart, bool recv_len)
+{
+ unsigned timeout = i2c->adap.timeout;
+ int i, result;
+ u32 flags = restart ? CCR_RSTA : 0;
+
+ /* Switch to read - restart */
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+ /* Write target address byte - this time with the read flag set */
+ writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+ result = i2c_wait(i2c, timeout, 1);
+ if (result < 0)
+ return result;
+
+ if (length) {
+ if (length == 1 && !recv_len)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+ else
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+ /* Dummy read */
+ readb(i2c->base + MPC_I2C_DR);
+ }
+
+ for (i = 0; i < length; i++) {
+ u8 byte;
+
+ result = i2c_wait(i2c, timeout, 0);
+ if (result < 0)
+ return result;
+
+ /*
+ * For block reads, we have to know the total length (1st byte)
+ * before we can determine if we are done.
+ */
+ if (i || !recv_len) {
+ /* Generate txack on next to last byte */
+ if (i == length - 2)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+ | CCR_TXAK);
+ /* Do not generate stop on last byte */
+ if (i == length - 1)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+ | CCR_MTX);
+ }
+
+ byte = readb(i2c->base + MPC_I2C_DR);
+
+ /*
+ * Adjust length if first received byte is length.
+ * The length is 1 length byte plus actually data length
+ */
+ if (i == 0 && recv_len) {
+ if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ length += byte;
+ /*
+ * For block reads, generate txack here if data length
+ * is 1 byte (total length is 2 bytes).
+ */
+ if (length == 2)
+ writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+ | CCR_TXAK);
+ }
+ data[i] = byte;
+ }
+
+ return length;
+}
+
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int i;
+ int ret = 0;
+ unsigned long orig_jiffies = jiffies;
+ struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+ mpc_i2c_start(i2c);
+
+ /* Allow bus up to 1s to become not busy */
+ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+ if (signal_pending(current)) {
+ dev_dbg(i2c->dev, "Interrupted\n");
+ writeccr(i2c, 0);
+ return -EINTR;
+ }
+ if (time_after(jiffies, orig_jiffies + HZ)) {
+ u8 status = readb(i2c->base + MPC_I2C_SR);
+
+ dev_dbg(i2c->dev, "timeout\n");
+ if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+ writeb(status & ~CSR_MAL,
+ i2c->base + MPC_I2C_SR);
+ i2c_recover_bus(&i2c->adap);
+ }
+ return -EIO;
+ }
+ schedule();
+ }
+
+ for (i = 0; ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ dev_dbg(i2c->dev,
+ "Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+ pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->len, pmsg->addr, i + 1, num);
+ if (pmsg->flags & I2C_M_RD) {
+ bool recv_len = pmsg->flags & I2C_M_RECV_LEN;
+
+ ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i,
+ recv_len);
+ if (recv_len && ret > 0)
+ pmsg->len = ret;
+ } else {
+ ret =
+ mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+ }
+ }
+ mpc_i2c_stop(i2c); /* Initiate STOP */
+ orig_jiffies = jiffies;
+ /* Wait until STOP is seen, allow up to 1 s */
+ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+ if (time_after(jiffies, orig_jiffies + HZ)) {
+ u8 status = readb(i2c->base + MPC_I2C_SR);
+
+ dev_dbg(i2c->dev, "timeout\n");
+ if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+ writeb(status & ~CSR_MAL,
+ i2c->base + MPC_I2C_SR);
+ i2c_recover_bus(&i2c->adap);
+ }
+ return -EIO;
+ }
+ cond_resched();
+ }
+ return (ret < 0) ? ret : num;
+}
+
+static u32 mpc_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static int fsl_i2c_bus_recovery(struct i2c_adapter *adap)
+{
+ struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+ if (i2c->has_errata_A004447)
+ mpc_i2c_fixup_A004447(i2c);
+ else
+ mpc_i2c_fixup(i2c);
+
+ return 0;
+}
+
+static const struct i2c_algorithm mpc_algo = {
+ .master_xfer = mpc_xfer,
+ .functionality = mpc_functionality,
+};
+
+static struct i2c_adapter mpc_ops = {
+ .owner = THIS_MODULE,
+ .algo = &mpc_algo,
+ .timeout = HZ,
+};
+
+static struct i2c_bus_recovery_info fsl_i2c_recovery_info = {
+ .recover_bus = fsl_i2c_bus_recovery,
+};
+
+static const struct of_device_id mpc_i2c_of_match[];
+static int fsl_i2c_probe(struct platform_device *op)
+{
+ const struct of_device_id *match;
+ struct mpc_i2c *i2c;
+ const u32 *prop;
+ u32 clock = MPC_I2C_CLOCK_LEGACY;
+ int result = 0;
+ int plen;
+ struct resource res;
+ struct clk *clk;
+ int err;
+
+ match = of_match_device(mpc_i2c_of_match, &op->dev);
+ if (!match)
+ return -EINVAL;
+
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->dev = &op->dev; /* for debug and error output */
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->base = of_iomap(op->dev.of_node, 0);
+ if (!i2c->base) {
+ dev_err(i2c->dev, "failed to map controller\n");
+ result = -ENOMEM;
+ goto fail_map;
+ }
+
+ i2c->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ if (i2c->irq) { /* no i2c->irq implies polling */
+ result = request_irq(i2c->irq, mpc_i2c_isr,
+ IRQF_SHARED, "i2c-mpc", i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto fail_request;
+ }
+ }
+
+ /*
+ * enable clock for the I2C peripheral (non fatal),
+ * keep a reference upon successful allocation
+ */
+ clk = devm_clk_get(&op->dev, NULL);
+ if (!IS_ERR(clk)) {
+ err = clk_prepare_enable(clk);
+ if (err) {
+ dev_err(&op->dev, "failed to enable clock\n");
+ goto fail_request;
+ } else {
+ i2c->clk_per = clk;
+ }
+ }
+
+ if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) {
+ clock = MPC_I2C_CLOCK_PRESERVE;
+ } else {
+ prop = of_get_property(op->dev.of_node, "clock-frequency",
+ &plen);
+ if (prop && plen == sizeof(u32))
+ clock = *prop;
+ }
+
+ if (match->data) {
+ const struct mpc_i2c_data *data = match->data;
+ data->setup(op->dev.of_node, i2c, clock);
+ } else {
+ /* Backwards compatibility */
+ if (of_get_property(op->dev.of_node, "dfsrr", NULL))
+ mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock);
+ }
+
+ prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen);
+ if (prop && plen == sizeof(u32)) {
+ mpc_ops.timeout = *prop * HZ / 1000000;
+ if (mpc_ops.timeout < 5)
+ mpc_ops.timeout = 5;
+ }
+ dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
+
+ platform_set_drvdata(op, i2c);
+ if (of_property_read_bool(op->dev.of_node, "fsl,i2c-erratum-a004447"))
+ i2c->has_errata_A004447 = true;
+
+ i2c->adap = mpc_ops;
+ of_address_to_resource(op->dev.of_node, 0, &res);
+ scnprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "MPC adapter at 0x%llx", (unsigned long long)res.start);
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &op->dev;
+ i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
+ i2c->adap.bus_recovery_info = &fsl_i2c_recovery_info;
+
+ result = i2c_add_adapter(&i2c->adap);
+ if (result < 0)
+ goto fail_add;
+
+ return result;
+
+ fail_add:
+ if (i2c->clk_per)
+ clk_disable_unprepare(i2c->clk_per);
+ free_irq(i2c->irq, i2c);
+ fail_request:
+ irq_dispose_mapping(i2c->irq);
+ iounmap(i2c->base);
+ fail_map:
+ kfree(i2c);
+ return result;
+};
+
+static int fsl_i2c_remove(struct platform_device *op)
+{
+ struct mpc_i2c *i2c = platform_get_drvdata(op);
+
+ i2c_del_adapter(&i2c->adap);
+
+ if (i2c->clk_per)
+ clk_disable_unprepare(i2c->clk_per);
+
+ if (i2c->irq)
+ free_irq(i2c->irq, i2c);
+
+ irq_dispose_mapping(i2c->irq);
+ iounmap(i2c->base);
+ kfree(i2c);
+ return 0;
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int mpc_i2c_suspend(struct device *dev)
+{
+ struct mpc_i2c *i2c = dev_get_drvdata(dev);
+
+ i2c->fdr = readb(i2c->base + MPC_I2C_FDR);
+ i2c->dfsrr = readb(i2c->base + MPC_I2C_DFSRR);
+
+ return 0;
+}
+
+static int mpc_i2c_resume(struct device *dev)
+{
+ struct mpc_i2c *i2c = dev_get_drvdata(dev);
+
+ writeb(i2c->fdr, i2c->base + MPC_I2C_FDR);
+ writeb(i2c->dfsrr, i2c->base + MPC_I2C_DFSRR);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
+#define MPC_I2C_PM_OPS (&mpc_i2c_pm_ops)
+#else
+#define MPC_I2C_PM_OPS NULL
+#endif
+
+static const struct mpc_i2c_data mpc_i2c_data_512x = {
+ .setup = mpc_i2c_setup_512x,
+};
+
+static const struct mpc_i2c_data mpc_i2c_data_52xx = {
+ .setup = mpc_i2c_setup_52xx,
+};
+
+static const struct mpc_i2c_data mpc_i2c_data_8313 = {
+ .setup = mpc_i2c_setup_8xxx,
+};
+
+static const struct mpc_i2c_data mpc_i2c_data_8543 = {
+ .setup = mpc_i2c_setup_8xxx,
+};
+
+static const struct mpc_i2c_data mpc_i2c_data_8544 = {
+ .setup = mpc_i2c_setup_8xxx,
+};
+
+static const struct of_device_id mpc_i2c_of_match[] = {
+ {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+ {.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, },
+ {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
+ {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
+ {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
+ /* Backward compatibility */
+ {.compatible = "fsl-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
+
+/* Structure for a device driver */
+static struct platform_driver mpc_i2c_driver = {
+ .probe = fsl_i2c_probe,
+ .remove = fsl_i2c_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = mpc_i2c_of_match,
+ .pm = MPC_I2C_PM_OPS,
+ },
+};
+
+module_platform_driver(mpc_i2c_driver);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
+ "MPC824x/83xx/85xx/86xx/512x/52xx processors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
new file mode 100644
index 000000000..e09b065a6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Xudong Chen <xudong.chen@mediatek.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#define I2C_RS_TRANSFER (1 << 4)
+#define I2C_HS_NACKERR (1 << 2)
+#define I2C_ACKERR (1 << 1)
+#define I2C_TRANSAC_COMP (1 << 0)
+#define I2C_TRANSAC_START (1 << 0)
+#define I2C_RS_MUL_CNFG (1 << 15)
+#define I2C_RS_MUL_TRIG (1 << 14)
+#define I2C_DCM_DISABLE 0x0000
+#define I2C_IO_CONFIG_OPEN_DRAIN 0x0003
+#define I2C_IO_CONFIG_PUSH_PULL 0x0000
+#define I2C_SOFT_RST 0x0001
+#define I2C_FIFO_ADDR_CLR 0x0001
+#define I2C_DELAY_LEN 0x0002
+#define I2C_ST_START_CON 0x8001
+#define I2C_FS_START_CON 0x1800
+#define I2C_TIME_CLR_VALUE 0x0000
+#define I2C_TIME_DEFAULT_VALUE 0x0003
+#define I2C_WRRD_TRANAC_VALUE 0x0002
+#define I2C_RD_TRANAC_VALUE 0x0001
+
+#define I2C_DMA_CON_TX 0x0000
+#define I2C_DMA_CON_RX 0x0001
+#define I2C_DMA_START_EN 0x0001
+#define I2C_DMA_INT_FLAG_NONE 0x0000
+#define I2C_DMA_CLR_FLAG 0x0000
+#define I2C_DMA_HARD_RST 0x0002
+#define I2C_DMA_4G_MODE 0x0001
+
+#define I2C_DEFAULT_CLK_DIV 5
+#define I2C_DEFAULT_SPEED 100000 /* hz */
+#define MAX_FS_MODE_SPEED 400000
+#define MAX_HS_MODE_SPEED 3400000
+#define MAX_SAMPLE_CNT_DIV 8
+#define MAX_STEP_CNT_DIV 64
+#define MAX_HS_STEP_CNT_DIV 8
+
+#define I2C_CONTROL_RS (0x1 << 1)
+#define I2C_CONTROL_DMA_EN (0x1 << 2)
+#define I2C_CONTROL_CLK_EXT_EN (0x1 << 3)
+#define I2C_CONTROL_DIR_CHANGE (0x1 << 4)
+#define I2C_CONTROL_ACKERR_DET_EN (0x1 << 5)
+#define I2C_CONTROL_TRANSFER_LEN_CHANGE (0x1 << 6)
+#define I2C_CONTROL_WRAPPER (0x1 << 0)
+
+#define I2C_DRV_NAME "i2c-mt65xx"
+
+enum DMA_REGS_OFFSET {
+ OFFSET_INT_FLAG = 0x0,
+ OFFSET_INT_EN = 0x04,
+ OFFSET_EN = 0x08,
+ OFFSET_RST = 0x0c,
+ OFFSET_CON = 0x18,
+ OFFSET_TX_MEM_ADDR = 0x1c,
+ OFFSET_RX_MEM_ADDR = 0x20,
+ OFFSET_TX_LEN = 0x24,
+ OFFSET_RX_LEN = 0x28,
+ OFFSET_TX_4G_MODE = 0x54,
+ OFFSET_RX_4G_MODE = 0x58,
+};
+
+enum i2c_trans_st_rs {
+ I2C_TRANS_STOP = 0,
+ I2C_TRANS_REPEATED_START,
+};
+
+enum mtk_trans_op {
+ I2C_MASTER_WR = 1,
+ I2C_MASTER_RD,
+ I2C_MASTER_WRRD,
+};
+
+enum I2C_REGS_OFFSET {
+ OFFSET_DATA_PORT = 0x0,
+ OFFSET_SLAVE_ADDR = 0x04,
+ OFFSET_INTR_MASK = 0x08,
+ OFFSET_INTR_STAT = 0x0c,
+ OFFSET_CONTROL = 0x10,
+ OFFSET_TRANSFER_LEN = 0x14,
+ OFFSET_TRANSAC_LEN = 0x18,
+ OFFSET_DELAY_LEN = 0x1c,
+ OFFSET_TIMING = 0x20,
+ OFFSET_START = 0x24,
+ OFFSET_EXT_CONF = 0x28,
+ OFFSET_FIFO_STAT = 0x30,
+ OFFSET_FIFO_THRESH = 0x34,
+ OFFSET_FIFO_ADDR_CLR = 0x38,
+ OFFSET_IO_CONFIG = 0x40,
+ OFFSET_RSV_DEBUG = 0x44,
+ OFFSET_HS = 0x48,
+ OFFSET_SOFTRESET = 0x50,
+ OFFSET_DCM_EN = 0x54,
+ OFFSET_PATH_DIR = 0x60,
+ OFFSET_DEBUGSTAT = 0x64,
+ OFFSET_DEBUGCTRL = 0x68,
+ OFFSET_TRANSFER_LEN_AUX = 0x6c,
+ OFFSET_CLOCK_DIV = 0x70,
+};
+
+struct mtk_i2c_compatible {
+ const struct i2c_adapter_quirks *quirks;
+ unsigned char pmic_i2c: 1;
+ unsigned char dcm: 1;
+ unsigned char auto_restart: 1;
+ unsigned char aux_len_reg: 1;
+ unsigned char support_33bits: 1;
+ unsigned char timing_adjust: 1;
+};
+
+struct mtk_i2c {
+ struct i2c_adapter adap; /* i2c host adapter */
+ struct device *dev;
+ struct completion msg_complete;
+
+ /* set in i2c probe */
+ void __iomem *base; /* i2c base addr */
+ void __iomem *pdmabase; /* dma base address*/
+ struct clk *clk_main; /* main clock for i2c bus */
+ struct clk *clk_dma; /* DMA clock for i2c via DMA */
+ struct clk *clk_pmic; /* PMIC clock for i2c from PMIC */
+ bool have_pmic; /* can use i2c pins from PMIC */
+ bool use_push_pull; /* IO config push-pull mode */
+
+ u16 irq_stat; /* interrupt status */
+ unsigned int clk_src_div;
+ unsigned int speed_hz; /* The speed in transfer */
+ enum mtk_trans_op op;
+ u16 timing_reg;
+ u16 high_speed_reg;
+ unsigned char auto_restart;
+ bool ignore_restart_irq;
+ const struct mtk_i2c_compatible *dev_comp;
+};
+
+static const struct i2c_adapter_quirks mt6577_i2c_quirks = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+ .max_num_msgs = 1,
+ .max_write_len = 255,
+ .max_read_len = 255,
+ .max_comb_1st_msg_len = 255,
+ .max_comb_2nd_msg_len = 31,
+};
+
+static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
+ .max_num_msgs = 255,
+};
+
+static const struct mtk_i2c_compatible mt2712_compat = {
+ .pmic_i2c = 0,
+ .dcm = 1,
+ .auto_restart = 1,
+ .aux_len_reg = 1,
+ .support_33bits = 1,
+ .timing_adjust = 1,
+};
+
+static const struct mtk_i2c_compatible mt6577_compat = {
+ .quirks = &mt6577_i2c_quirks,
+ .pmic_i2c = 0,
+ .dcm = 1,
+ .auto_restart = 0,
+ .aux_len_reg = 0,
+ .support_33bits = 0,
+ .timing_adjust = 0,
+};
+
+static const struct mtk_i2c_compatible mt6589_compat = {
+ .quirks = &mt6577_i2c_quirks,
+ .pmic_i2c = 1,
+ .dcm = 0,
+ .auto_restart = 0,
+ .aux_len_reg = 0,
+ .support_33bits = 0,
+ .timing_adjust = 0,
+};
+
+static const struct mtk_i2c_compatible mt7622_compat = {
+ .quirks = &mt7622_i2c_quirks,
+ .pmic_i2c = 0,
+ .dcm = 1,
+ .auto_restart = 1,
+ .aux_len_reg = 1,
+ .support_33bits = 0,
+ .timing_adjust = 0,
+};
+
+static const struct mtk_i2c_compatible mt8173_compat = {
+ .pmic_i2c = 0,
+ .dcm = 1,
+ .auto_restart = 1,
+ .aux_len_reg = 1,
+ .support_33bits = 1,
+ .timing_adjust = 0,
+};
+
+static const struct of_device_id mtk_i2c_of_match[] = {
+ { .compatible = "mediatek,mt2712-i2c", .data = &mt2712_compat },
+ { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
+ { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
+ { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
+ { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mtk_i2c_of_match);
+
+static int mtk_i2c_clock_enable(struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = clk_prepare_enable(i2c->clk_dma);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(i2c->clk_main);
+ if (ret)
+ goto err_main;
+
+ if (i2c->have_pmic) {
+ ret = clk_prepare_enable(i2c->clk_pmic);
+ if (ret)
+ goto err_pmic;
+ }
+ return 0;
+
+err_pmic:
+ clk_disable_unprepare(i2c->clk_main);
+err_main:
+ clk_disable_unprepare(i2c->clk_dma);
+
+ return ret;
+}
+
+static void mtk_i2c_clock_disable(struct mtk_i2c *i2c)
+{
+ if (i2c->have_pmic)
+ clk_disable_unprepare(i2c->clk_pmic);
+
+ clk_disable_unprepare(i2c->clk_main);
+ clk_disable_unprepare(i2c->clk_dma);
+}
+
+static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
+{
+ u16 control_reg;
+
+ writew(I2C_SOFT_RST, i2c->base + OFFSET_SOFTRESET);
+
+ /* Set ioconfig */
+ if (i2c->use_push_pull)
+ writew(I2C_IO_CONFIG_PUSH_PULL, i2c->base + OFFSET_IO_CONFIG);
+ else
+ writew(I2C_IO_CONFIG_OPEN_DRAIN, i2c->base + OFFSET_IO_CONFIG);
+
+ if (i2c->dev_comp->dcm)
+ writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN);
+
+ if (i2c->dev_comp->timing_adjust)
+ writew(I2C_DEFAULT_CLK_DIV - 1, i2c->base + OFFSET_CLOCK_DIV);
+
+ writew(i2c->timing_reg, i2c->base + OFFSET_TIMING);
+ writew(i2c->high_speed_reg, i2c->base + OFFSET_HS);
+
+ /* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */
+ if (i2c->have_pmic)
+ writew(I2C_CONTROL_WRAPPER, i2c->base + OFFSET_PATH_DIR);
+
+ control_reg = I2C_CONTROL_ACKERR_DET_EN |
+ I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN;
+ writew(control_reg, i2c->base + OFFSET_CONTROL);
+ writew(I2C_DELAY_LEN, i2c->base + OFFSET_DELAY_LEN);
+
+ writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
+ udelay(50);
+ writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
+}
+
+/*
+ * Calculate i2c port speed
+ *
+ * Hardware design:
+ * i2c_bus_freq = parent_clk / (clock_div * 2 * sample_cnt * step_cnt)
+ * clock_div: fixed in hardware, but may be various in different SoCs
+ *
+ * The calculation want to pick the highest bus frequency that is still
+ * less than or equal to i2c->speed_hz. The calculation try to get
+ * sample_cnt and step_cn
+ */
+static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
+ unsigned int target_speed,
+ unsigned int *timing_step_cnt,
+ unsigned int *timing_sample_cnt)
+{
+ unsigned int step_cnt;
+ unsigned int sample_cnt;
+ unsigned int max_step_cnt;
+ unsigned int base_sample_cnt = MAX_SAMPLE_CNT_DIV;
+ unsigned int base_step_cnt;
+ unsigned int opt_div;
+ unsigned int best_mul;
+ unsigned int cnt_mul;
+
+ if (target_speed > MAX_HS_MODE_SPEED)
+ target_speed = MAX_HS_MODE_SPEED;
+
+ if (target_speed > MAX_FS_MODE_SPEED)
+ max_step_cnt = MAX_HS_STEP_CNT_DIV;
+ else
+ max_step_cnt = MAX_STEP_CNT_DIV;
+
+ base_step_cnt = max_step_cnt;
+ /* Find the best combination */
+ opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed);
+ best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt;
+
+ /* Search for the best pair (sample_cnt, step_cnt) with
+ * 0 < sample_cnt < MAX_SAMPLE_CNT_DIV
+ * 0 < step_cnt < max_step_cnt
+ * sample_cnt * step_cnt >= opt_div
+ * optimizing for sample_cnt * step_cnt being minimal
+ */
+ for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
+ step_cnt = DIV_ROUND_UP(opt_div, sample_cnt);
+ cnt_mul = step_cnt * sample_cnt;
+ if (step_cnt > max_step_cnt)
+ continue;
+
+ if (cnt_mul < best_mul) {
+ best_mul = cnt_mul;
+ base_sample_cnt = sample_cnt;
+ base_step_cnt = step_cnt;
+ if (best_mul == opt_div)
+ break;
+ }
+ }
+
+ sample_cnt = base_sample_cnt;
+ step_cnt = base_step_cnt;
+
+ if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) {
+ /* In this case, hardware can't support such
+ * low i2c_bus_freq
+ */
+ dev_dbg(i2c->dev, "Unsupported speed (%uhz)\n", target_speed);
+ return -EINVAL;
+ }
+
+ *timing_step_cnt = step_cnt - 1;
+ *timing_sample_cnt = sample_cnt - 1;
+
+ return 0;
+}
+
+static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
+{
+ unsigned int clk_src;
+ unsigned int step_cnt;
+ unsigned int sample_cnt;
+ unsigned int target_speed;
+ int ret;
+
+ clk_src = parent_clk / i2c->clk_src_div;
+ target_speed = i2c->speed_hz;
+
+ if (target_speed > MAX_FS_MODE_SPEED) {
+ /* Set master code speed register */
+ ret = mtk_i2c_calculate_speed(i2c, clk_src, MAX_FS_MODE_SPEED,
+ &step_cnt, &sample_cnt);
+ if (ret < 0)
+ return ret;
+
+ i2c->timing_reg = (sample_cnt << 8) | step_cnt;
+
+ /* Set the high speed mode register */
+ ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
+ &step_cnt, &sample_cnt);
+ if (ret < 0)
+ return ret;
+
+ i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
+ (sample_cnt << 12) | (step_cnt << 8);
+ } else {
+ ret = mtk_i2c_calculate_speed(i2c, clk_src, target_speed,
+ &step_cnt, &sample_cnt);
+ if (ret < 0)
+ return ret;
+
+ i2c->timing_reg = (sample_cnt << 8) | step_cnt;
+
+ /* Disable the high speed transaction */
+ i2c->high_speed_reg = I2C_TIME_CLR_VALUE;
+ }
+
+ return 0;
+}
+
+static inline u32 mtk_i2c_set_4g_mode(dma_addr_t addr)
+{
+ return (addr & BIT_ULL(32)) ? I2C_DMA_4G_MODE : I2C_DMA_CLR_FLAG;
+}
+
+static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
+ int num, int left_num)
+{
+ u16 addr_reg;
+ u16 start_reg;
+ u16 control_reg;
+ u16 restart_flag = 0;
+ u32 reg_4g_mode;
+ u8 *dma_rd_buf = NULL;
+ u8 *dma_wr_buf = NULL;
+ dma_addr_t rpaddr = 0;
+ dma_addr_t wpaddr = 0;
+ int ret;
+
+ i2c->irq_stat = 0;
+
+ if (i2c->auto_restart)
+ restart_flag = I2C_RS_TRANSFER;
+
+ reinit_completion(&i2c->msg_complete);
+
+ control_reg = readw(i2c->base + OFFSET_CONTROL) &
+ ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
+ if ((i2c->speed_hz > 400000) || (left_num >= 1))
+ control_reg |= I2C_CONTROL_RS;
+
+ if (i2c->op == I2C_MASTER_WRRD)
+ control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS;
+
+ writew(control_reg, i2c->base + OFFSET_CONTROL);
+
+ /* set start condition */
+ if (i2c->speed_hz <= 100000)
+ writew(I2C_ST_START_CON, i2c->base + OFFSET_EXT_CONF);
+ else
+ writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
+
+ addr_reg = i2c_8bit_addr_from_msg(msgs);
+ writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR);
+
+ /* Clear interrupt status */
+ writew(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
+ I2C_TRANSAC_COMP, i2c->base + OFFSET_INTR_STAT);
+ writew(I2C_FIFO_ADDR_CLR, i2c->base + OFFSET_FIFO_ADDR_CLR);
+
+ /* Enable interrupt */
+ writew(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
+ I2C_TRANSAC_COMP, i2c->base + OFFSET_INTR_MASK);
+
+ /* Set transfer and transaction len */
+ if (i2c->op == I2C_MASTER_WRRD) {
+ if (i2c->dev_comp->aux_len_reg) {
+ writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
+ writew((msgs + 1)->len, i2c->base +
+ OFFSET_TRANSFER_LEN_AUX);
+ } else {
+ writew(msgs->len | ((msgs + 1)->len) << 8,
+ i2c->base + OFFSET_TRANSFER_LEN);
+ }
+ writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
+ } else {
+ writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
+ writew(num, i2c->base + OFFSET_TRANSAC_LEN);
+ }
+
+ /* Prepare buffer data to start transfer */
+ if (i2c->op == I2C_MASTER_RD) {
+ writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
+ writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON);
+
+ dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
+ if (!dma_rd_buf)
+ return -ENOMEM;
+
+ rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
+ msgs->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(i2c->dev, rpaddr)) {
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
+
+ return -ENOMEM;
+ }
+
+ if (i2c->dev_comp->support_33bits) {
+ reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
+ writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
+ }
+
+ writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR);
+ writel(msgs->len, i2c->pdmabase + OFFSET_RX_LEN);
+ } else if (i2c->op == I2C_MASTER_WR) {
+ writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
+ writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON);
+
+ dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
+ if (!dma_wr_buf)
+ return -ENOMEM;
+
+ wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
+ msgs->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(i2c->dev, wpaddr)) {
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
+ return -ENOMEM;
+ }
+
+ if (i2c->dev_comp->support_33bits) {
+ reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
+ writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
+ }
+
+ writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR);
+ writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN);
+ } else {
+ writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
+ writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON);
+
+ dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
+ if (!dma_wr_buf)
+ return -ENOMEM;
+
+ wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
+ msgs->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(i2c->dev, wpaddr)) {
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
+ return -ENOMEM;
+ }
+
+ dma_rd_buf = i2c_get_dma_safe_msg_buf((msgs + 1), 1);
+ if (!dma_rd_buf) {
+ dma_unmap_single(i2c->dev, wpaddr,
+ msgs->len, DMA_TO_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
+ return -ENOMEM;
+ }
+
+ rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
+ (msgs + 1)->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(i2c->dev, rpaddr)) {
+ dma_unmap_single(i2c->dev, wpaddr,
+ msgs->len, DMA_TO_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
+
+ return -ENOMEM;
+ }
+
+ if (i2c->dev_comp->support_33bits) {
+ reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
+ writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
+
+ reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
+ writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
+ }
+
+ writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR);
+ writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR);
+ writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN);
+ writel((msgs + 1)->len, i2c->pdmabase + OFFSET_RX_LEN);
+ }
+
+ writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
+
+ if (!i2c->auto_restart) {
+ start_reg = I2C_TRANSAC_START;
+ } else {
+ start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
+ if (left_num >= 1)
+ start_reg |= I2C_RS_MUL_CNFG;
+ }
+ writew(start_reg, i2c->base + OFFSET_START);
+
+ ret = wait_for_completion_timeout(&i2c->msg_complete,
+ i2c->adap.timeout);
+
+ /* Clear interrupt mask */
+ writew(~(restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
+ I2C_TRANSAC_COMP), i2c->base + OFFSET_INTR_MASK);
+
+ if (i2c->op == I2C_MASTER_WR) {
+ dma_unmap_single(i2c->dev, wpaddr,
+ msgs->len, DMA_TO_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
+ } else if (i2c->op == I2C_MASTER_RD) {
+ dma_unmap_single(i2c->dev, rpaddr,
+ msgs->len, DMA_FROM_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
+ } else {
+ dma_unmap_single(i2c->dev, wpaddr, msgs->len,
+ DMA_TO_DEVICE);
+ dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len,
+ DMA_FROM_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
+ }
+
+ if (ret == 0) {
+ dev_dbg(i2c->dev, "addr: %x, transfer timeout\n", msgs->addr);
+ mtk_i2c_init_hw(i2c);
+ return -ETIMEDOUT;
+ }
+
+ completion_done(&i2c->msg_complete);
+
+ if (i2c->irq_stat & (I2C_HS_NACKERR | I2C_ACKERR)) {
+ dev_dbg(i2c->dev, "addr: %x, transfer ACK error\n", msgs->addr);
+ mtk_i2c_init_hw(i2c);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int mtk_i2c_transfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ int ret;
+ int left_num = num;
+ struct mtk_i2c *i2c = i2c_get_adapdata(adap);
+
+ ret = mtk_i2c_clock_enable(i2c);
+ if (ret)
+ return ret;
+
+ i2c->auto_restart = i2c->dev_comp->auto_restart;
+
+ /* checking if we can skip restart and optimize using WRRD mode */
+ if (i2c->auto_restart && num == 2) {
+ if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+ msgs[0].addr == msgs[1].addr) {
+ i2c->auto_restart = 0;
+ }
+ }
+
+ if (i2c->auto_restart && num >= 2 && i2c->speed_hz > MAX_FS_MODE_SPEED)
+ /* ignore the first restart irq after the master code,
+ * otherwise the first transfer will be discarded.
+ */
+ i2c->ignore_restart_irq = true;
+ else
+ i2c->ignore_restart_irq = false;
+
+ while (left_num--) {
+ if (!msgs->buf) {
+ dev_dbg(i2c->dev, "data buffer is NULL.\n");
+ ret = -EINVAL;
+ goto err_exit;
+ }
+
+ if (msgs->flags & I2C_M_RD)
+ i2c->op = I2C_MASTER_RD;
+ else
+ i2c->op = I2C_MASTER_WR;
+
+ if (!i2c->auto_restart) {
+ if (num > 1) {
+ /* combined two messages into one transaction */
+ i2c->op = I2C_MASTER_WRRD;
+ left_num--;
+ }
+ }
+
+ /* always use DMA mode. */
+ ret = mtk_i2c_do_transfer(i2c, msgs, num, left_num);
+ if (ret < 0)
+ goto err_exit;
+
+ msgs++;
+ }
+ /* the return value is number of executed messages */
+ ret = num;
+
+err_exit:
+ mtk_i2c_clock_disable(i2c);
+ return ret;
+}
+
+static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
+{
+ struct mtk_i2c *i2c = dev_id;
+ u16 restart_flag = 0;
+ u16 intr_stat;
+
+ if (i2c->auto_restart)
+ restart_flag = I2C_RS_TRANSFER;
+
+ intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
+ writew(intr_stat, i2c->base + OFFSET_INTR_STAT);
+
+ /*
+ * when occurs ack error, i2c controller generate two interrupts
+ * first is the ack error interrupt, then the complete interrupt
+ * i2c->irq_stat need keep the two interrupt value.
+ */
+ i2c->irq_stat |= intr_stat;
+
+ if (i2c->ignore_restart_irq && (i2c->irq_stat & restart_flag)) {
+ i2c->ignore_restart_irq = false;
+ i2c->irq_stat = 0;
+ writew(I2C_RS_MUL_CNFG | I2C_RS_MUL_TRIG | I2C_TRANSAC_START,
+ i2c->base + OFFSET_START);
+ } else {
+ if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
+ complete(&i2c->msg_complete);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static u32 mtk_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mtk_i2c_algorithm = {
+ .master_xfer = mtk_i2c_transfer,
+ .functionality = mtk_i2c_functionality,
+};
+
+static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = of_property_read_u32(np, "clock-frequency", &i2c->speed_hz);
+ if (ret < 0)
+ i2c->speed_hz = I2C_DEFAULT_SPEED;
+
+ ret = of_property_read_u32(np, "clock-div", &i2c->clk_src_div);
+ if (ret < 0)
+ return ret;
+
+ if (i2c->clk_src_div == 0)
+ return -EINVAL;
+
+ i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic");
+ i2c->use_push_pull =
+ of_property_read_bool(np, "mediatek,use-push-pull");
+
+ return 0;
+}
+
+static int mtk_i2c_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mtk_i2c *i2c;
+ struct clk *clk;
+ struct resource *res;
+ int irq;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->pdmabase))
+ return PTR_ERR(i2c->pdmabase);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ init_completion(&i2c->msg_complete);
+
+ i2c->dev_comp = of_device_get_match_data(&pdev->dev);
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+ i2c->dev = &pdev->dev;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &mtk_i2c_algorithm;
+ i2c->adap.quirks = i2c->dev_comp->quirks;
+ i2c->adap.timeout = 2 * HZ;
+ i2c->adap.retries = 1;
+
+ ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
+ if (ret)
+ return -EINVAL;
+
+ if (i2c->dev_comp->timing_adjust)
+ i2c->clk_src_div *= I2C_DEFAULT_CLK_DIV;
+
+ if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c)
+ return -EINVAL;
+
+ i2c->clk_main = devm_clk_get(&pdev->dev, "main");
+ if (IS_ERR(i2c->clk_main)) {
+ dev_err(&pdev->dev, "cannot get main clock\n");
+ return PTR_ERR(i2c->clk_main);
+ }
+
+ i2c->clk_dma = devm_clk_get(&pdev->dev, "dma");
+ if (IS_ERR(i2c->clk_dma)) {
+ dev_err(&pdev->dev, "cannot get dma clock\n");
+ return PTR_ERR(i2c->clk_dma);
+ }
+
+ clk = i2c->clk_main;
+ if (i2c->have_pmic) {
+ i2c->clk_pmic = devm_clk_get(&pdev->dev, "pmic");
+ if (IS_ERR(i2c->clk_pmic)) {
+ dev_err(&pdev->dev, "cannot get pmic clock\n");
+ return PTR_ERR(i2c->clk_pmic);
+ }
+ clk = i2c->clk_pmic;
+ }
+
+ strlcpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name));
+
+ ret = mtk_i2c_set_speed(i2c, clk_get_rate(clk));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set the speed.\n");
+ return -EINVAL;
+ }
+
+ if (i2c->dev_comp->support_33bits) {
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(33));
+ if (ret) {
+ dev_err(&pdev->dev, "dma_set_mask return error.\n");
+ return ret;
+ }
+ }
+
+ ret = mtk_i2c_clock_enable(i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "clock enable failed!\n");
+ return ret;
+ }
+ mtk_i2c_init_hw(i2c);
+ mtk_i2c_clock_disable(i2c);
+
+ ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
+ IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Request I2C IRQ %d fail\n", irq);
+ return ret;
+ }
+
+ i2c_set_adapdata(&i2c->adap, i2c);
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, i2c);
+
+ return 0;
+}
+
+static int mtk_i2c_remove(struct platform_device *pdev)
+{
+ struct mtk_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_i2c_resume(struct device *dev)
+{
+ int ret;
+ struct mtk_i2c *i2c = dev_get_drvdata(dev);
+
+ ret = mtk_i2c_clock_enable(i2c);
+ if (ret) {
+ dev_err(dev, "clock enable failed!\n");
+ return ret;
+ }
+
+ mtk_i2c_init_hw(i2c);
+
+ mtk_i2c_clock_disable(i2c);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk_i2c_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume)
+};
+
+static struct platform_driver mtk_i2c_driver = {
+ .probe = mtk_i2c_probe,
+ .remove = mtk_i2c_remove,
+ .driver = {
+ .name = I2C_DRV_NAME,
+ .pm = &mtk_i2c_pm,
+ .of_match_table = of_match_ptr(mtk_i2c_of_match),
+ },
+};
+
+module_platform_driver(mtk_i2c_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek I2C Bus Driver");
+MODULE_AUTHOR("Xudong Chen <xudong.chen@mediatek.com>");
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
new file mode 100644
index 000000000..a5a95ea5b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -0,0 +1,1018 @@
+/*
+ * Driver for the i2c controller on the Marvell line of host bridges
+ * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mv643xx_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1)
+#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
+#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
+
+#define MV64XXX_I2C_REG_CONTROL_ACK BIT(2)
+#define MV64XXX_I2C_REG_CONTROL_IFLG BIT(3)
+#define MV64XXX_I2C_REG_CONTROL_STOP BIT(4)
+#define MV64XXX_I2C_REG_CONTROL_START BIT(5)
+#define MV64XXX_I2C_REG_CONTROL_TWSIEN BIT(6)
+#define MV64XXX_I2C_REG_CONTROL_INTEN BIT(7)
+
+/* Ctlr status values */
+#define MV64XXX_I2C_STATUS_BUS_ERR 0x00
+#define MV64XXX_I2C_STATUS_MAST_START 0x08
+#define MV64XXX_I2C_STATUS_MAST_REPEAT_START 0x10
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK 0x18
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20
+#define MV64XXX_I2C_STATUS_MAST_WR_ACK 0x28
+#define MV64XXX_I2C_STATUS_MAST_WR_NO_ACK 0x30
+#define MV64XXX_I2C_STATUS_MAST_LOST_ARB 0x38
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK 0x40
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48
+#define MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK 0x50
+#define MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0
+#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0
+#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8
+#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8
+
+/* Register defines (I2C bridge) */
+#define MV64XXX_I2C_REG_TX_DATA_LO 0xc0
+#define MV64XXX_I2C_REG_TX_DATA_HI 0xc4
+#define MV64XXX_I2C_REG_RX_DATA_LO 0xc8
+#define MV64XXX_I2C_REG_RX_DATA_HI 0xcc
+#define MV64XXX_I2C_REG_BRIDGE_CONTROL 0xd0
+#define MV64XXX_I2C_REG_BRIDGE_STATUS 0xd4
+#define MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE 0xd8
+#define MV64XXX_I2C_REG_BRIDGE_INTR_MASK 0xdC
+#define MV64XXX_I2C_REG_BRIDGE_TIMING 0xe0
+
+/* Bridge Control values */
+#define MV64XXX_I2C_BRIDGE_CONTROL_WR BIT(0)
+#define MV64XXX_I2C_BRIDGE_CONTROL_RD BIT(1)
+#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT 2
+#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT BIT(12)
+#define MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT 13
+#define MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT 16
+#define MV64XXX_I2C_BRIDGE_CONTROL_ENABLE BIT(19)
+#define MV64XXX_I2C_BRIDGE_CONTROL_REPEATED_START BIT(20)
+
+/* Bridge Status values */
+#define MV64XXX_I2C_BRIDGE_STATUS_ERROR BIT(0)
+
+/* Driver states */
+enum {
+ MV64XXX_I2C_STATE_INVALID,
+ MV64XXX_I2C_STATE_IDLE,
+ MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
+ MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA,
+};
+
+/* Driver actions */
+enum {
+ MV64XXX_I2C_ACTION_INVALID,
+ MV64XXX_I2C_ACTION_CONTINUE,
+ MV64XXX_I2C_ACTION_SEND_RESTART,
+ MV64XXX_I2C_ACTION_SEND_ADDR_1,
+ MV64XXX_I2C_ACTION_SEND_ADDR_2,
+ MV64XXX_I2C_ACTION_SEND_DATA,
+ MV64XXX_I2C_ACTION_RCV_DATA,
+ MV64XXX_I2C_ACTION_RCV_DATA_STOP,
+ MV64XXX_I2C_ACTION_SEND_STOP,
+};
+
+struct mv64xxx_i2c_regs {
+ u8 addr;
+ u8 ext_addr;
+ u8 data;
+ u8 control;
+ u8 status;
+ u8 clock;
+ u8 soft_reset;
+};
+
+struct mv64xxx_i2c_data {
+ struct i2c_msg *msgs;
+ int num_msgs;
+ int irq;
+ u32 state;
+ u32 action;
+ u32 aborting;
+ u32 cntl_bits;
+ void __iomem *reg_base;
+ struct mv64xxx_i2c_regs reg_offsets;
+ u32 addr1;
+ u32 addr2;
+ u32 bytes_left;
+ u32 byte_posn;
+ u32 send_stop;
+ u32 block;
+ int rc;
+ u32 freq_m;
+ u32 freq_n;
+ struct clk *clk;
+ struct clk *reg_clk;
+ wait_queue_head_t waitq;
+ spinlock_t lock;
+ struct i2c_msg *msg;
+ struct i2c_adapter adapter;
+ bool offload_enabled;
+/* 5us delay in order to avoid repeated start timing violation */
+ bool errata_delay;
+ struct reset_control *rstc;
+ bool irq_clear_inverted;
+ /* Clk div is 2 to the power n, not 2 to the power n + 1 */
+ bool clk_n_base_0;
+};
+
+static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
+ .addr = 0x00,
+ .ext_addr = 0x10,
+ .data = 0x04,
+ .control = 0x08,
+ .status = 0x0c,
+ .clock = 0x0c,
+ .soft_reset = 0x1c,
+};
+
+static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_sun4i = {
+ .addr = 0x00,
+ .ext_addr = 0x04,
+ .data = 0x08,
+ .control = 0x0c,
+ .status = 0x10,
+ .clock = 0x14,
+ .soft_reset = 0x18,
+};
+
+static void
+mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
+ struct i2c_msg *msg)
+{
+ u32 dir = 0;
+
+ drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
+ MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
+
+ if (msg->flags & I2C_M_RD)
+ dir = 1;
+
+ if (msg->flags & I2C_M_TEN) {
+ drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
+ drv_data->addr2 = (u32)msg->addr & 0xff;
+ } else {
+ drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir;
+ drv_data->addr2 = 0;
+ }
+}
+
+/*
+ *****************************************************************************
+ *
+ * Finite State Machine & Interrupt Routines
+ *
+ *****************************************************************************
+ */
+
+/* Reset hardware and initialize FSM */
+static void
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+ if (drv_data->offload_enabled) {
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
+ }
+
+ writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset);
+ writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n),
+ drv_data->reg_base + drv_data->reg_offsets.clock);
+ writel(0, drv_data->reg_base + drv_data->reg_offsets.addr);
+ writel(0, drv_data->reg_base + drv_data->reg_offsets.ext_addr);
+ writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
+static void
+mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
+{
+ /*
+ * If state is idle, then this is likely the remnants of an old
+ * operation that driver has given up on or the user has killed.
+ * If so, issue the stop condition and go to idle.
+ */
+ if (drv_data->state == MV64XXX_I2C_STATE_IDLE) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ return;
+ }
+
+ /* The status from the ctlr [mostly] tells us what to do next */
+ switch (status) {
+ /* Start condition interrupt */
+ case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */
+ case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+ break;
+
+ /* Performing a write */
+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */
+ if (drv_data->msg->flags & I2C_M_TEN) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+ break;
+ }
+ /* FALLTHRU */
+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
+ case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
+ if ((drv_data->bytes_left == 0)
+ || (drv_data->aborting
+ && (drv_data->byte_posn != 0))) {
+ if (drv_data->send_stop || drv_data->aborting) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ } else {
+ drv_data->action =
+ MV64XXX_I2C_ACTION_SEND_RESTART;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
+ }
+ } else {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+ drv_data->bytes_left--;
+ }
+ break;
+
+ /* Performing a read */
+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */
+ if (drv_data->msg->flags & I2C_M_TEN) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+ drv_data->state =
+ MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+ break;
+ }
+ /* FALLTHRU */
+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
+ if (drv_data->bytes_left == 0) {
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ break;
+ }
+ /* FALLTHRU */
+ case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
+ if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
+ drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+ else {
+ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
+ drv_data->bytes_left--;
+ }
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+
+ if ((drv_data->bytes_left == 1) || drv_data->aborting)
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
+ break;
+
+ case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */
+ drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ break;
+
+ case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */
+ case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */
+ case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */
+ /* Doesn't seem to be a device at other end */
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ drv_data->rc = -ENXIO;
+ break;
+
+ default:
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
+ "status: 0x%x, addr: 0x%x, flags: 0x%x\n",
+ drv_data->state, status, drv_data->msg->addr,
+ drv_data->msg->flags);
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+ mv64xxx_i2c_hw_init(drv_data);
+ drv_data->rc = -EIO;
+ }
+}
+
+static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
+{
+ drv_data->msg = drv_data->msgs;
+ drv_data->byte_posn = 0;
+ drv_data->bytes_left = drv_data->msg->len;
+ drv_data->aborting = 0;
+ drv_data->rc = 0;
+
+ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+}
+
+static void
+mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
+{
+ switch(drv_data->action) {
+ case MV64XXX_I2C_ACTION_SEND_RESTART:
+ /* We should only get here if we have further messages */
+ BUG_ON(drv_data->num_msgs == 0);
+
+ drv_data->msgs++;
+ drv_data->num_msgs--;
+ mv64xxx_i2c_send_start(drv_data);
+
+ if (drv_data->errata_delay)
+ udelay(5);
+
+ /*
+ * We're never at the start of the message here, and by this
+ * time it's already too late to do any protocol mangling.
+ * Thankfully, do not advertise support for that feature.
+ */
+ drv_data->send_stop = drv_data->num_msgs == 1;
+ break;
+
+ case MV64XXX_I2C_ACTION_CONTINUE:
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_ADDR_1:
+ writel(drv_data->addr1,
+ drv_data->reg_base + drv_data->reg_offsets.data);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_ADDR_2:
+ writel(drv_data->addr2,
+ drv_data->reg_base + drv_data->reg_offsets.data);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ break;
+
+ case MV64XXX_I2C_ACTION_SEND_DATA:
+ writel(drv_data->msg->buf[drv_data->byte_posn++],
+ drv_data->reg_base + drv_data->reg_offsets.data);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ break;
+
+ case MV64XXX_I2C_ACTION_RCV_DATA:
+ drv_data->msg->buf[drv_data->byte_posn++] =
+ readl(drv_data->reg_base + drv_data->reg_offsets.data);
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ break;
+
+ case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
+ drv_data->msg->buf[drv_data->byte_posn++] =
+ readl(drv_data->reg_base + drv_data->reg_offsets.data);
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ drv_data->block = 0;
+ if (drv_data->errata_delay)
+ udelay(5);
+
+ wake_up(&drv_data->waitq);
+ break;
+
+ case MV64XXX_I2C_ACTION_INVALID:
+ default:
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx_i2c_do_action: Invalid action: %d\n",
+ drv_data->action);
+ drv_data->rc = -EIO;
+
+ /* FALLTHRU */
+ case MV64XXX_I2C_ACTION_SEND_STOP:
+ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+ drv_data->block = 0;
+ wake_up(&drv_data->waitq);
+ break;
+ }
+}
+
+static void
+mv64xxx_i2c_read_offload_rx_data(struct mv64xxx_i2c_data *drv_data,
+ struct i2c_msg *msg)
+{
+ u32 buf[2];
+
+ buf[0] = readl(drv_data->reg_base + MV64XXX_I2C_REG_RX_DATA_LO);
+ buf[1] = readl(drv_data->reg_base + MV64XXX_I2C_REG_RX_DATA_HI);
+
+ memcpy(msg->buf, buf, msg->len);
+}
+
+static int
+mv64xxx_i2c_intr_offload(struct mv64xxx_i2c_data *drv_data)
+{
+ u32 cause, status;
+
+ cause = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ if (!cause)
+ return IRQ_NONE;
+
+ status = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_STATUS);
+
+ if (status & MV64XXX_I2C_BRIDGE_STATUS_ERROR) {
+ drv_data->rc = -EIO;
+ goto out;
+ }
+
+ drv_data->rc = 0;
+
+ /*
+ * Transaction is a one message read transaction, read data
+ * for this message.
+ */
+ if (drv_data->num_msgs == 1 && drv_data->msgs[0].flags & I2C_M_RD) {
+ mv64xxx_i2c_read_offload_rx_data(drv_data, drv_data->msgs);
+ drv_data->msgs++;
+ drv_data->num_msgs--;
+ }
+ /*
+ * Transaction is a two messages write/read transaction, read
+ * data for the second (read) message.
+ */
+ else if (drv_data->num_msgs == 2 &&
+ !(drv_data->msgs[0].flags & I2C_M_RD) &&
+ drv_data->msgs[1].flags & I2C_M_RD) {
+ mv64xxx_i2c_read_offload_rx_data(drv_data, drv_data->msgs + 1);
+ drv_data->msgs += 2;
+ drv_data->num_msgs -= 2;
+ }
+
+out:
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ drv_data->block = 0;
+
+ wake_up(&drv_data->waitq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+mv64xxx_i2c_intr(int irq, void *dev_id)
+{
+ struct mv64xxx_i2c_data *drv_data = dev_id;
+ unsigned long flags;
+ u32 status;
+ irqreturn_t rc = IRQ_NONE;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->offload_enabled)
+ rc = mv64xxx_i2c_intr_offload(drv_data);
+
+ while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
+ MV64XXX_I2C_REG_CONTROL_IFLG) {
+ status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
+ mv64xxx_i2c_fsm(drv_data, status);
+ mv64xxx_i2c_do_action(drv_data);
+
+ if (drv_data->irq_clear_inverted)
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_IFLG,
+ drv_data->reg_base + drv_data->reg_offsets.control);
+
+ rc = IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ * I2C Msg Execution Routines
+ *
+ *****************************************************************************
+ */
+static void
+mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
+{
+ long time_left;
+ unsigned long flags;
+ char abort = 0;
+
+ time_left = wait_event_timeout(drv_data->waitq,
+ !drv_data->block, drv_data->adapter.timeout);
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (!time_left) { /* Timed out */
+ drv_data->rc = -ETIMEDOUT;
+ abort = 1;
+ } else if (time_left < 0) { /* Interrupted/Error */
+ drv_data->rc = time_left; /* errno value */
+ abort = 1;
+ }
+
+ if (abort && drv_data->block) {
+ drv_data->aborting = 1;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ time_left = wait_event_timeout(drv_data->waitq,
+ !drv_data->block, drv_data->adapter.timeout);
+
+ if ((time_left <= 0) && drv_data->block) {
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx: I2C bus locked, block: %d, "
+ "time_left: %d\n", drv_data->block,
+ (int)time_left);
+ mv64xxx_i2c_hw_init(drv_data);
+ }
+ } else
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+static int
+mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
+ int is_last)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+
+ drv_data->send_stop = is_last;
+ drv_data->block = 1;
+ mv64xxx_i2c_send_start(drv_data);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ mv64xxx_i2c_wait_for_completion(drv_data);
+ return drv_data->rc;
+}
+
+static void
+mv64xxx_i2c_prepare_tx(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msg = drv_data->msgs;
+ u32 buf[2];
+
+ memcpy(buf, msg->buf, msg->len);
+
+ writel(buf[0], drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_LO);
+ writel(buf[1], drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_HI);
+}
+
+static int
+mv64xxx_i2c_offload_xfer(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msgs = drv_data->msgs;
+ int num = drv_data->num_msgs;
+ unsigned long ctrl_reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ /* Build transaction */
+ ctrl_reg = MV64XXX_I2C_BRIDGE_CONTROL_ENABLE |
+ (msgs[0].addr << MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT);
+
+ if (msgs[0].flags & I2C_M_TEN)
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT;
+
+ /* Single write message transaction */
+ if (num == 1 && !(msgs[0].flags & I2C_M_RD)) {
+ size_t len = msgs[0].len - 1;
+
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR |
+ (len << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT);
+ mv64xxx_i2c_prepare_tx(drv_data);
+ }
+ /* Single read message transaction */
+ else if (num == 1 && msgs[0].flags & I2C_M_RD) {
+ size_t len = msgs[0].len - 1;
+
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_RD |
+ (len << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT);
+ }
+ /*
+ * Transaction with one write and one read message. This is
+ * guaranteed by the mv64xx_i2c_can_offload() checks.
+ */
+ else if (num == 2) {
+ size_t lentx = msgs[0].len - 1;
+ size_t lenrx = msgs[1].len - 1;
+
+ ctrl_reg |=
+ MV64XXX_I2C_BRIDGE_CONTROL_RD |
+ MV64XXX_I2C_BRIDGE_CONTROL_WR |
+ (lentx << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT) |
+ (lenrx << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT) |
+ MV64XXX_I2C_BRIDGE_CONTROL_REPEATED_START;
+ mv64xxx_i2c_prepare_tx(drv_data);
+ }
+
+ /* Execute transaction */
+ drv_data->block = 1;
+ writel(ctrl_reg, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ mv64xxx_i2c_wait_for_completion(drv_data);
+
+ return drv_data->rc;
+}
+
+static bool
+mv64xxx_i2c_valid_offload_sz(struct i2c_msg *msg)
+{
+ return msg->len <= 8 && msg->len >= 1;
+}
+
+static bool
+mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msgs = drv_data->msgs;
+ int num = drv_data->num_msgs;
+
+ if (!drv_data->offload_enabled)
+ return false;
+
+ /*
+ * We can offload a transaction consisting of a single
+ * message, as long as the message has a length between 1 and
+ * 8 bytes.
+ */
+ if (num == 1 && mv64xxx_i2c_valid_offload_sz(msgs))
+ return true;
+
+ /*
+ * We can offload a transaction consisting of two messages, if
+ * the first is a write and a second is a read, and both have
+ * a length between 1 and 8 bytes.
+ */
+ if (num == 2 &&
+ mv64xxx_i2c_valid_offload_sz(msgs) &&
+ mv64xxx_i2c_valid_offload_sz(msgs + 1) &&
+ !(msgs[0].flags & I2C_M_RD) &&
+ msgs[1].flags & I2C_M_RD)
+ return true;
+
+ return false;
+}
+
+/*
+ *****************************************************************************
+ *
+ * I2C Core Support Routines (Interface to higher level I2C code)
+ *
+ *****************************************************************************
+ */
+static u32
+mv64xxx_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
+ int rc, ret = num;
+
+ BUG_ON(drv_data->msgs != NULL);
+ drv_data->msgs = msgs;
+ drv_data->num_msgs = num;
+
+ if (mv64xxx_i2c_can_offload(drv_data))
+ rc = mv64xxx_i2c_offload_xfer(drv_data);
+ else
+ rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
+
+ if (rc < 0)
+ ret = rc;
+
+ drv_data->num_msgs = 0;
+ drv_data->msgs = NULL;
+
+ return ret;
+}
+
+static const struct i2c_algorithm mv64xxx_i2c_algo = {
+ .master_xfer = mv64xxx_i2c_xfer,
+ .functionality = mv64xxx_i2c_functionality,
+};
+
+/*
+ *****************************************************************************
+ *
+ * Driver Interface & Early Init Routines
+ *
+ *****************************************************************************
+ */
+static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
+ { .compatible = "allwinner,sun4i-a10-i2c", .data = &mv64xxx_i2c_regs_sun4i},
+ { .compatible = "allwinner,sun6i-a31-i2c", .data = &mv64xxx_i2c_regs_sun4i},
+ { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
+ { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
+ { .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
+
+#ifdef CONFIG_OF
+static int
+mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
+ const int tclk, const int n, const int m)
+{
+ if (drv_data->clk_n_base_0)
+ return tclk / (10 * (m + 1) * (1 << n));
+ else
+ return tclk / (10 * (m + 1) * (2 << n));
+}
+
+static bool
+mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
+ const u32 req_freq, const u32 tclk)
+{
+ int freq, delta, best_delta = INT_MAX;
+ int m, n;
+
+ for (n = 0; n <= 7; n++)
+ for (m = 0; m <= 15; m++) {
+ freq = mv64xxx_calc_freq(drv_data, tclk, n, m);
+ delta = req_freq - freq;
+ if (delta >= 0 && delta < best_delta) {
+ drv_data->freq_m = m;
+ drv_data->freq_n = n;
+ best_delta = delta;
+ }
+ if (best_delta == 0)
+ return true;
+ }
+ if (best_delta == INT_MAX)
+ return false;
+ return true;
+}
+
+static int
+mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
+ struct device *dev)
+{
+ const struct of_device_id *device;
+ struct device_node *np = dev->of_node;
+ u32 bus_freq, tclk;
+ int rc = 0;
+
+ /* CLK is mandatory when using DT to describe the i2c bus. We
+ * need to know tclk in order to calculate bus clock
+ * factors.
+ */
+ if (IS_ERR(drv_data->clk)) {
+ rc = -ENODEV;
+ goto out;
+ }
+ tclk = clk_get_rate(drv_data->clk);
+
+ if (of_property_read_u32(np, "clock-frequency", &bus_freq))
+ bus_freq = 100000; /* 100kHz by default */
+
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-i2c") ||
+ of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
+ drv_data->clk_n_base_0 = true;
+
+ if (!mv64xxx_find_baud_factors(drv_data, bus_freq, tclk)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ drv_data->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(drv_data->rstc)) {
+ rc = PTR_ERR(drv_data->rstc);
+ goto out;
+ }
+ reset_control_deassert(drv_data->rstc);
+
+ /* Its not yet defined how timeouts will be specified in device tree.
+ * So hard code the value to 1 second.
+ */
+ drv_data->adapter.timeout = HZ;
+
+ device = of_match_device(mv64xxx_i2c_of_match_table, dev);
+ if (!device)
+ return -ENODEV;
+
+ memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets));
+
+ /*
+ * For controllers embedded in new SoCs activate the
+ * Transaction Generator support and the errata fix.
+ */
+ if (of_device_is_compatible(np, "marvell,mv78230-i2c")) {
+ drv_data->offload_enabled = true;
+ /* The delay is only needed in standard mode (100kHz) */
+ if (bus_freq <= 100000)
+ drv_data->errata_delay = true;
+ }
+
+ if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) {
+ drv_data->offload_enabled = false;
+ /* The delay is only needed in standard mode (100kHz) */
+ if (bus_freq <= 100000)
+ drv_data->errata_delay = true;
+ }
+
+ if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
+ drv_data->irq_clear_inverted = true;
+
+out:
+ return rc;
+}
+#else /* CONFIG_OF */
+static int
+mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
+ struct device *dev)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
+static int
+mv64xxx_i2c_probe(struct platform_device *pd)
+{
+ struct mv64xxx_i2c_data *drv_data;
+ struct mv64xxx_i2c_pdata *pdata = dev_get_platdata(&pd->dev);
+ struct resource *r;
+ int rc;
+
+ if ((!pdata && !pd->dev.of_node))
+ return -ENODEV;
+
+ drv_data = devm_kzalloc(&pd->dev, sizeof(struct mv64xxx_i2c_data),
+ GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ r = platform_get_resource(pd, IORESOURCE_MEM, 0);
+ drv_data->reg_base = devm_ioremap_resource(&pd->dev, r);
+ if (IS_ERR(drv_data->reg_base))
+ return PTR_ERR(drv_data->reg_base);
+
+ strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
+ sizeof(drv_data->adapter.name));
+
+ init_waitqueue_head(&drv_data->waitq);
+ spin_lock_init(&drv_data->lock);
+
+ /* Not all platforms have clocks */
+ drv_data->clk = devm_clk_get(&pd->dev, NULL);
+ if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR(drv_data->clk))
+ clk_prepare_enable(drv_data->clk);
+
+ drv_data->reg_clk = devm_clk_get(&pd->dev, "reg");
+ if (IS_ERR(drv_data->reg_clk) &&
+ PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR(drv_data->reg_clk))
+ clk_prepare_enable(drv_data->reg_clk);
+
+ drv_data->irq = platform_get_irq(pd, 0);
+
+ if (pdata) {
+ drv_data->freq_m = pdata->freq_m;
+ drv_data->freq_n = pdata->freq_n;
+ drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
+ drv_data->offload_enabled = false;
+ memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets));
+ } else if (pd->dev.of_node) {
+ rc = mv64xxx_of_config(drv_data, &pd->dev);
+ if (rc)
+ goto exit_clk;
+ }
+ if (drv_data->irq < 0) {
+ rc = drv_data->irq;
+ goto exit_reset;
+ }
+
+ drv_data->adapter.dev.parent = &pd->dev;
+ drv_data->adapter.algo = &mv64xxx_i2c_algo;
+ drv_data->adapter.owner = THIS_MODULE;
+ drv_data->adapter.class = I2C_CLASS_DEPRECATED;
+ drv_data->adapter.nr = pd->id;
+ drv_data->adapter.dev.of_node = pd->dev.of_node;
+ platform_set_drvdata(pd, drv_data);
+ i2c_set_adapdata(&drv_data->adapter, drv_data);
+
+ mv64xxx_i2c_hw_init(drv_data);
+
+ rc = request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
+ MV64XXX_I2C_CTLR_NAME, drv_data);
+ if (rc) {
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx: Can't register intr handler irq%d: %d\n",
+ drv_data->irq, rc);
+ goto exit_reset;
+ } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
+ dev_err(&drv_data->adapter.dev,
+ "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
+ goto exit_free_irq;
+ }
+
+ return 0;
+
+exit_free_irq:
+ free_irq(drv_data->irq, drv_data);
+exit_reset:
+ reset_control_assert(drv_data->rstc);
+exit_clk:
+ clk_disable_unprepare(drv_data->reg_clk);
+ clk_disable_unprepare(drv_data->clk);
+
+ return rc;
+}
+
+static int
+mv64xxx_i2c_remove(struct platform_device *dev)
+{
+ struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&drv_data->adapter);
+ free_irq(drv_data->irq, drv_data);
+ reset_control_assert(drv_data->rstc);
+ clk_disable_unprepare(drv_data->reg_clk);
+ clk_disable_unprepare(drv_data->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mv64xxx_i2c_resume(struct device *dev)
+{
+ struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev);
+
+ mv64xxx_i2c_hw_init(drv_data);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mv64xxx_i2c_pm = {
+ .resume = mv64xxx_i2c_resume,
+};
+
+#define mv64xxx_i2c_pm_ops (&mv64xxx_i2c_pm)
+#else
+#define mv64xxx_i2c_pm_ops NULL
+#endif
+
+static struct platform_driver mv64xxx_i2c_driver = {
+ .probe = mv64xxx_i2c_probe,
+ .remove = mv64xxx_i2c_remove,
+ .driver = {
+ .name = MV64XXX_I2C_CTLR_NAME,
+ .pm = mv64xxx_i2c_pm_ops,
+ .of_match_table = mv64xxx_i2c_of_match_table,
+ },
+};
+
+module_platform_driver(mv64xxx_i2c_driver);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
new file mode 100644
index 000000000..7d79317a1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -0,0 +1,912 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * 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:
+ *
+ * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/stmp_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+
+#define DRIVER_NAME "mxs-i2c"
+
+#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
+#define MXS_I2C_CTRL0_MASTER_MODE 0x00020000
+#define MXS_I2C_CTRL0_DIRECTION 0x00010000
+#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF)
+
+#define MXS_I2C_TIMING0 (0x10)
+#define MXS_I2C_TIMING1 (0x20)
+#define MXS_I2C_TIMING2 (0x30)
+
+#define MXS_I2C_CTRL1 (0x40)
+#define MXS_I2C_CTRL1_SET (0x44)
+#define MXS_I2C_CTRL1_CLR (0x48)
+
+#define MXS_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000
+#define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80
+#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40
+#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20
+#define MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x10
+#define MXS_I2C_CTRL1_EARLY_TERM_IRQ 0x08
+#define MXS_I2C_CTRL1_MASTER_LOSS_IRQ 0x04
+#define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02
+#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(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x60 : 0xa0)
+
+#define MXS_I2C_DEBUG0_CLR(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x78 : 0xb8)
+
+#define MXS_I2C_DEBUG0_DMAREQ 0x80000000
+
+#define MXS_I2C_IRQ_MASK (MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \
+ MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \
+ MXS_I2C_CTRL1_EARLY_TERM_IRQ | \
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ | \
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \
+ MXS_I2C_CTRL1_SLAVE_IRQ)
+
+
+#define MXS_CMD_I2C_SELECT (MXS_I2C_CTRL0_RETAIN_CLOCK | \
+ MXS_I2C_CTRL0_PRE_SEND_START | \
+ MXS_I2C_CTRL0_MASTER_MODE | \
+ MXS_I2C_CTRL0_DIRECTION | \
+ MXS_I2C_CTRL0_XFER_COUNT(1))
+
+#define MXS_CMD_I2C_WRITE (MXS_I2C_CTRL0_PRE_SEND_START | \
+ MXS_I2C_CTRL0_MASTER_MODE | \
+ MXS_I2C_CTRL0_DIRECTION)
+
+#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
+ * @adapter: i2c subsystem adapter node
+ */
+struct mxs_i2c_dev {
+ struct device *dev;
+ enum mxs_i2c_devtype dev_type;
+ void __iomem *regs;
+ struct completion cmd_complete;
+ int cmd_err;
+ struct i2c_adapter adapter;
+
+ uint32_t timing0;
+ uint32_t timing1;
+ uint32_t timing2;
+
+ /* DMA support components */
+ struct dma_chan *dmach;
+ uint32_t pio_data[2];
+ uint32_t addr_data;
+ struct scatterlist sg_io[2];
+ bool dma_read;
+};
+
+static int mxs_i2c_reset(struct mxs_i2c_dev *i2c)
+{
+ int ret = stmp_reset_block(i2c->regs);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure timing for the I2C block. The I2C TIMING2 register has to
+ * be programmed with this particular magic number. The rest is derived
+ * from the XTAL speed and requested I2C speed.
+ *
+ * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
+ */
+ writel(i2c->timing0, i2c->regs + MXS_I2C_TIMING0);
+ writel(i2c->timing1, i2c->regs + MXS_I2C_TIMING1);
+ writel(i2c->timing2, i2c->regs + MXS_I2C_TIMING2);
+
+ writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
+
+ return 0;
+}
+
+static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
+{
+ if (i2c->dma_read) {
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+ } else {
+ dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+ }
+}
+
+static void mxs_i2c_dma_irq_callback(void *param)
+{
+ struct mxs_i2c_dev *i2c = param;
+
+ complete(&i2c->cmd_complete);
+ mxs_i2c_dma_finish(i2c);
+}
+
+static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msg, uint32_t flags)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+
+ i2c->addr_data = i2c_8bit_addr_from_msg(msg);
+
+ if (msg->flags & I2C_M_RD) {
+ i2c->dma_read = true;
+
+ /*
+ * SELECT command.
+ */
+
+ /* Queue the PIO register write transfer. */
+ i2c->pio_data[0] = MXS_CMD_I2C_SELECT;
+ desc = dmaengine_prep_slave_sg(i2c->dmach,
+ (struct scatterlist *)&i2c->pio_data[0],
+ 1, DMA_TRANS_NONE, 0);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ goto select_init_pio_fail;
+ }
+
+ /* Queue the DMA data transfer. */
+ sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1);
+ dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+ desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get DMA data write descriptor.\n");
+ goto select_init_dma_fail;
+ }
+
+ /*
+ * READ command.
+ */
+
+ /* Queue the PIO register write transfer. */
+ i2c->pio_data[1] = flags | MXS_CMD_I2C_READ |
+ MXS_I2C_CTRL0_XFER_COUNT(msg->len);
+ desc = dmaengine_prep_slave_sg(i2c->dmach,
+ (struct scatterlist *)&i2c->pio_data[1],
+ 1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ goto select_init_dma_fail;
+ }
+
+ /* Queue the DMA data transfer. */
+ sg_init_one(&i2c->sg_io[1], msg->buf, msg->len);
+ dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+ desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get DMA data write descriptor.\n");
+ goto read_init_dma_fail;
+ }
+ } else {
+ i2c->dma_read = false;
+
+ /*
+ * WRITE command.
+ */
+
+ /* Queue the PIO register write transfer. */
+ i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE |
+ MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1);
+ desc = dmaengine_prep_slave_sg(i2c->dmach,
+ (struct scatterlist *)&i2c->pio_data[0],
+ 1, DMA_TRANS_NONE, 0);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get PIO reg. write descriptor.\n");
+ goto write_init_pio_fail;
+ }
+
+ /* Queue the DMA data transfer. */
+ sg_init_table(i2c->sg_io, 2);
+ sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1);
+ sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len);
+ dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+ desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(i2c->dev,
+ "Failed to get DMA data write descriptor.\n");
+ goto write_init_dma_fail;
+ }
+ }
+
+ /*
+ * The last descriptor must have this callback,
+ * to finish the DMA transaction.
+ */
+ desc->callback = mxs_i2c_dma_irq_callback;
+ desc->callback_param = i2c;
+
+ /* Start the transfer. */
+ dmaengine_submit(desc);
+ dma_async_issue_pending(i2c->dmach);
+ return 0;
+
+/* Read failpath. */
+read_init_dma_fail:
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+select_init_dma_fail:
+ dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+select_init_pio_fail:
+ dmaengine_terminate_all(i2c->dmach);
+ return -EINVAL;
+
+/* Write failpath. */
+write_init_dma_fail:
+ dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+write_init_pio_fail:
+ dmaengine_terminate_all(i2c->dmach);
+ return -EINVAL;
+}
+
+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_CTRL0) & MXS_I2C_CTRL0_RUN) {
+ if (readl(i2c->regs + MXS_I2C_CTRL1) &
+ MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
+ return -ENXIO;
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ cond_resched();
+ }
+
+ return 0;
+}
+
+static int mxs_i2c_pio_check_error_state(struct mxs_i2c_dev *i2c)
+{
+ u32 state;
+
+ state = readl(i2c->regs + MXS_I2C_CTRL1_CLR) & MXS_I2C_IRQ_MASK;
+
+ if (state & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
+ i2c->cmd_err = -ENXIO;
+ else if (state & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ |
+ MXS_I2C_CTRL1_SLAVE_IRQ))
+ i2c->cmd_err = -EIO;
+
+ return i2c->cmd_err;
+}
+
+static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd)
+{
+ u32 reg;
+
+ writel(cmd, i2c->regs + MXS_I2C_CTRL0);
+
+ /* readback makes sure the write is latched into hardware */
+ reg = readl(i2c->regs + MXS_I2C_CTRL0);
+ reg |= MXS_I2C_CTRL0_RUN;
+ 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 = i2c_8bit_addr_from_msg(msg);
+ uint32_t data = 0;
+ 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);
+
+ /* SELECT command. */
+ mxs_i2c_pio_trigger_write_cmd(i2c, MXS_CMD_I2C_SELECT,
+ addr_data);
+
+ ret = mxs_i2c_pio_wait_xfer_end(i2c);
+ if (ret) {
+ dev_dbg(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_dbg(i2c->dev,
+ "PIO: Failed to send READ command!\n");
+ goto cleanup;
+ }
+
+ data = readl(i2c->regs + MXS_I2C_DATA(i2c));
+ for (i = 0; i < msg->len; i++) {
+ 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.
+ */
+
+ /*
+ * 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);
+
+ 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));
+
+ 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_dbg(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;
+ }
+ }
+ }
+
+ /* make sure we capture any occurred error into cmd_err */
+ 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);
+
+ /* 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;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+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;
+ int flags;
+ int use_pio = 0;
+ unsigned long time_left;
+
+ flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
+ dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ /*
+ * 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 (use_pio) {
+ ret = mxs_i2c_pio_setup_xfer(adap, msg, flags);
+ /* 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);
+ if (ret)
+ return ret;
+
+ time_left = wait_for_completion_timeout(&i2c->cmd_complete,
+ msecs_to_jiffies(1000));
+ if (!time_left)
+ goto timeout;
+
+ ret = i2c->cmd_err;
+ }
+
+ 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.
+ */
+ writel(MXS_I2C_CTRL1_CLR_GOT_A_NAK,
+ i2c->regs + MXS_I2C_CTRL1_SET);
+ }
+
+ /*
+ * 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);
+
+ return ret;
+
+timeout:
+ dev_dbg(i2c->dev, "Timeout!\n");
+ mxs_i2c_dma_finish(i2c);
+ ret = mxs_i2c_reset(i2c);
+ if (ret)
+ return ret;
+
+ return -ETIMEDOUT;
+}
+
+static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < num; i++) {
+ err = mxs_i2c_xfer_msg(adap, &msgs[i], i == (num - 1));
+ if (err)
+ return err;
+ }
+
+ return num;
+}
+
+static u32 mxs_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
+{
+ struct mxs_i2c_dev *i2c = dev_id;
+ u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
+
+ if (!stat)
+ return IRQ_NONE;
+
+ if (stat & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
+ i2c->cmd_err = -ENXIO;
+ else if (stat & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ | MXS_I2C_CTRL1_SLAVE_IRQ))
+ /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
+ i2c->cmd_err = -EIO;
+
+ writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
+
+ return IRQ_HANDLED;
+}
+
+static const struct i2c_algorithm mxs_i2c_algo = {
+ .master_xfer = mxs_i2c_xfer,
+ .functionality = mxs_i2c_func,
+};
+
+static const struct i2c_adapter_quirks mxs_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed)
+{
+ /* The I2C block clock runs at 24MHz */
+ const uint32_t clk = 24000000;
+ uint32_t divider;
+ uint16_t high_count, low_count, rcv_count, xmit_count;
+ uint32_t bus_free, leadin;
+ struct device *dev = i2c->dev;
+
+ divider = DIV_ROUND_UP(clk, speed);
+
+ if (divider < 25) {
+ /*
+ * limit the divider, so that min(low_count, high_count)
+ * is >= 1
+ */
+ divider = 25;
+ dev_warn(dev,
+ "Speed too high (%u.%03u kHz), using %u.%03u kHz\n",
+ speed / 1000, speed % 1000,
+ clk / divider / 1000, clk / divider % 1000);
+ } else if (divider > 1897) {
+ /*
+ * limit the divider, so that max(low_count, high_count)
+ * cannot exceed 1023
+ */
+ divider = 1897;
+ dev_warn(dev,
+ "Speed too low (%u.%03u kHz), using %u.%03u kHz\n",
+ speed / 1000, speed % 1000,
+ clk / divider / 1000, clk / divider % 1000);
+ }
+
+ /*
+ * The I2C spec specifies the following timing data:
+ * standard mode fast mode Bitfield name
+ * tLOW (SCL LOW period) 4700 ns 1300 ns
+ * tHIGH (SCL HIGH period) 4000 ns 600 ns
+ * tSU;DAT (data setup time) 250 ns 100 ns
+ * tHD;STA (START hold time) 4000 ns 600 ns
+ * tBUF (bus free time) 4700 ns 1300 ns
+ *
+ * The hardware (of the i.MX28 at least) seems to add 2 additional
+ * clock cycles to the low_count and 7 cycles to the high_count.
+ * This is compensated for by subtracting the respective constants
+ * from the values written to the timing registers.
+ */
+ if (speed > 100000) {
+ /* fast mode */
+ low_count = DIV_ROUND_CLOSEST(divider * 13, (13 + 6));
+ high_count = DIV_ROUND_CLOSEST(divider * 6, (13 + 6));
+ leadin = DIV_ROUND_UP(600 * (clk / 1000000), 1000);
+ bus_free = DIV_ROUND_UP(1300 * (clk / 1000000), 1000);
+ } else {
+ /* normal mode */
+ low_count = DIV_ROUND_CLOSEST(divider * 47, (47 + 40));
+ high_count = DIV_ROUND_CLOSEST(divider * 40, (47 + 40));
+ leadin = DIV_ROUND_UP(4700 * (clk / 1000000), 1000);
+ bus_free = DIV_ROUND_UP(4700 * (clk / 1000000), 1000);
+ }
+ rcv_count = high_count * 3 / 8;
+ xmit_count = low_count * 3 / 8;
+
+ dev_dbg(dev,
+ "speed=%u(actual %u) divider=%u low=%u high=%u xmit=%u rcv=%u leadin=%u bus_free=%u\n",
+ speed, clk / divider, divider, low_count, high_count,
+ xmit_count, rcv_count, leadin, bus_free);
+
+ low_count -= 2;
+ high_count -= 7;
+ i2c->timing0 = (high_count << 16) | rcv_count;
+ i2c->timing1 = (low_count << 16) | xmit_count;
+ i2c->timing2 = (bus_free << 16 | leadin);
+}
+
+static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
+{
+ uint32_t speed;
+ struct device *dev = i2c->dev;
+ struct device_node *node = dev->of_node;
+ int ret;
+
+ ret = of_property_read_u32(node, "clock-frequency", &speed);
+ if (ret) {
+ dev_warn(dev, "No I2C speed selected, using 100kHz\n");
+ speed = 100000;
+ }
+
+ mxs_i2c_derive_timing(i2c, speed);
+
+ return 0;
+}
+
+static const 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;
+ struct resource *res;
+ int err, irq;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ 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);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
+ if (err)
+ return err;
+
+ i2c->dev = dev;
+
+ init_completion(&i2c->cmd_complete);
+
+ if (dev->of_node) {
+ err = mxs_i2c_get_ofdata(i2c);
+ if (err)
+ return err;
+ }
+
+ /* Setup the DMA */
+ i2c->dmach = dma_request_slave_channel(dev, "rx-tx");
+ if (!i2c->dmach) {
+ dev_err(dev, "Failed to request dma\n");
+ return -ENODEV;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ /* Do reset to enforce correct startup after pinmuxing */
+ err = mxs_i2c_reset(i2c);
+ if (err)
+ return err;
+
+ adap = &i2c->adapter;
+ strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
+ adap->owner = THIS_MODULE;
+ adap->algo = &mxs_i2c_algo;
+ adap->quirks = &mxs_i2c_quirks;
+ adap->dev.parent = dev;
+ adap->nr = pdev->id;
+ adap->dev.of_node = pdev->dev.of_node;
+ i2c_set_adapdata(adap, i2c);
+ err = i2c_add_numbered_adapter(adap);
+ if (err) {
+ writel(MXS_I2C_CTRL0_SFTRST,
+ i2c->regs + MXS_I2C_CTRL0_SET);
+ return err;
+ }
+
+ return 0;
+}
+
+static int mxs_i2c_remove(struct platform_device *pdev)
+{
+ struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adapter);
+
+ if (i2c->dmach)
+ dma_release_channel(i2c->dmach);
+
+ writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
+
+ return 0;
+}
+
+static struct platform_driver mxs_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = mxs_i2c_dt_ids,
+ },
+ .probe = mxs_i2c_probe,
+ .remove = mxs_i2c_remove,
+};
+
+static int __init mxs_i2c_init(void)
+{
+ return platform_driver_register(&mxs_i2c_driver);
+}
+subsys_initcall(mxs_i2c_init);
+
+static void __exit mxs_i2c_exit(void)
+{
+ platform_driver_unregister(&mxs_i2c_driver);
+}
+module_exit(mxs_i2c_exit);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("MXS I2C Bus Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c
new file mode 100644
index 000000000..58a0fbf0e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nforce2-s4985.c
@@ -0,0 +1,249 @@
+/*
+ * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
+ *
+ * Copyright (C) 2008 Jean Delvare <jdelvare@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4. We define one virtual
+ * adapter per CPU, which corresponds to one multiplexed channel:
+ * CPU0: virtual adapter 1, channel 1
+ * CPU1: virtual adapter 2, channel 2
+ * CPU2: virtual adapter 3, channel 3
+ * CPU3: virtual adapter 4, channel 4
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+extern struct i2c_adapter *nforce2_smbus;
+
+static struct i2c_adapter *s4985_adapter;
+static struct i2c_algorithm *s4985_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static DEFINE_MUTEX(nforce2_lock);
+
+static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ int error;
+
+ /* We exclude the multiplexed addresses */
+ if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+ || addr == 0x18)
+ return -ENXIO;
+
+ mutex_lock(&nforce2_lock);
+ error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+ mutex_unlock(&nforce2_lock);
+
+ return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+ channels when it is really needed. This greatly reduces the SMBus
+ overhead, but also assumes that nobody will be writing to the PCA9556
+ in our back. */
+static u8 last_channels;
+
+static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data,
+ u8 channels)
+{
+ int error;
+
+ /* We exclude the non-multiplexed addresses */
+ if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+ return -ENXIO;
+
+ mutex_lock(&nforce2_lock);
+ if (last_channels != channels) {
+ union i2c_smbus_data mplxdata;
+ mplxdata.byte = channels;
+
+ error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
+ I2C_SMBUS_WRITE, 0x01,
+ I2C_SMBUS_BYTE_DATA,
+ &mplxdata);
+ if (error)
+ goto UNLOCK;
+ last_channels = channels;
+ }
+ error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
+ command, size, data);
+
+UNLOCK:
+ mutex_unlock(&nforce2_lock);
+ return error;
+}
+
+static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU0: channel 1 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x02);
+}
+
+static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU1: channel 2 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x04);
+}
+
+static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU2: channel 3 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x08);
+}
+
+static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ /* CPU3: channel 4 enabled */
+ return nforce2_access_channel(adap, addr, flags, read_write, command,
+ size, data, 0x10);
+}
+
+static int __init nforce2_s4985_init(void)
+{
+ int i, error;
+ union i2c_smbus_data ioconfig;
+
+ if (!nforce2_smbus)
+ return -ENODEV;
+
+ /* Configure the PCA9556 multiplexer */
+ ioconfig.byte = 0x00; /* All I/O to output mode */
+ error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+ I2C_SMBUS_BYTE_DATA, &ioconfig);
+ if (error) {
+ dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
+ error = -EIO;
+ goto ERROR0;
+ }
+
+ /* Unregister physical bus */
+ i2c_del_adapter(nforce2_smbus);
+
+ printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
+ /* Define the 5 virtual adapters and algorithms structures */
+ s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!s4985_adapter) {
+ error = -ENOMEM;
+ goto ERROR1;
+ }
+ s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL);
+ if (!s4985_algo) {
+ error = -ENOMEM;
+ goto ERROR2;
+ }
+
+ /* Fill in the new structures */
+ s4985_algo[0] = *(nforce2_smbus->algo);
+ s4985_algo[0].smbus_xfer = nforce2_access_virt0;
+ s4985_adapter[0] = *nforce2_smbus;
+ s4985_adapter[0].algo = s4985_algo;
+ s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
+ for (i = 1; i < 5; i++) {
+ s4985_algo[i] = *(nforce2_smbus->algo);
+ s4985_adapter[i] = *nforce2_smbus;
+ snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
+ "SMBus nForce2 adapter (CPU%d)", i - 1);
+ s4985_adapter[i].algo = s4985_algo + i;
+ s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
+ }
+ s4985_algo[1].smbus_xfer = nforce2_access_virt1;
+ s4985_algo[2].smbus_xfer = nforce2_access_virt2;
+ s4985_algo[3].smbus_xfer = nforce2_access_virt3;
+ s4985_algo[4].smbus_xfer = nforce2_access_virt4;
+
+ /* Register virtual adapters */
+ for (i = 0; i < 5; i++) {
+ error = i2c_add_adapter(s4985_adapter + i);
+ if (error) {
+ printk(KERN_ERR "i2c-nforce2-s4985: "
+ "Virtual adapter %d registration "
+ "failed, module not inserted\n", i);
+ for (i--; i >= 0; i--)
+ i2c_del_adapter(s4985_adapter + i);
+ goto ERROR3;
+ }
+ }
+
+ return 0;
+
+ERROR3:
+ kfree(s4985_algo);
+ s4985_algo = NULL;
+ERROR2:
+ kfree(s4985_adapter);
+ s4985_adapter = NULL;
+ERROR1:
+ /* Restore physical bus */
+ i2c_add_adapter(nforce2_smbus);
+ERROR0:
+ return error;
+}
+
+static void __exit nforce2_s4985_exit(void)
+{
+ if (s4985_adapter) {
+ int i;
+
+ for (i = 0; i < 5; i++)
+ i2c_del_adapter(s4985_adapter+i);
+ kfree(s4985_adapter);
+ s4985_adapter = NULL;
+ }
+ kfree(s4985_algo);
+ s4985_algo = NULL;
+
+ /* Restore physical bus */
+ if (i2c_add_adapter(nforce2_smbus))
+ printk(KERN_ERR "i2c-nforce2-s4985: "
+ "Physical bus restoration failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("S4985 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(nforce2_s4985_init);
+module_exit(nforce2_s4985_exit);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
new file mode 100644
index 000000000..f6a1272c5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -0,0 +1,450 @@
+/*
+ SMBus driver for nVidia nForce2 MCP
+
+ Added nForce3 Pro 150 Thomas Leibold <thomas@plx.com>,
+ Ported to 2.5 Patrick Dreker <patrick@dreker.de>,
+ Copyright (c) 2003 Hans-Frieder Vogt <hfvogt@arcor.de>,
+ Based on
+ SMBus 2.0 driver for AMD-8111 IO-Hub
+ Copyright (c) 2002 Vojtech Pavlik
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ SUPPORTED DEVICES PCI ID
+ nForce2 MCP 0064
+ nForce2 Ultra 400 MCP 0084
+ nForce3 Pro150 MCP 00D4
+ nForce3 250Gb MCP 00E4
+ nForce4 MCP 0052
+ nForce4 MCP-04 0034
+ nForce MCP51 0264
+ nForce MCP55 0368
+ nForce MCP61 03EB
+ nForce MCP65 0446
+ nForce MCP67 0542
+ nForce MCP73 07D8
+ nForce MCP78S 0752
+ nForce MCP79 0AA2
+
+ This driver supports the 2 SMBuses that are included in the MCP of the
+ nForce2/3/4/5xx chipsets.
+*/
+
+/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
+
+
+struct nforce2_smbus {
+ struct i2c_adapter adapter;
+ int base;
+ int size;
+ int blockops;
+ int can_abort;
+};
+
+
+/*
+ * nVidia nForce2 SMBus control register definitions
+ * (Newer incarnations use standard BARs 4 and 5 instead)
+ */
+#define NFORCE_PCI_SMB1 0x50
+#define NFORCE_PCI_SMB2 0x54
+
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+#define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */
+#define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */
+#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
+#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
+#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
+#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
+ bytes */
+#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to
+ check the status of
+ the abort command */
+#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */
+
+#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that
+ abort succeeded */
+#define NVIDIA_SMB_CTRL_ABORT 0x20
+#define NVIDIA_SMB_STS_DONE 0x80
+#define NVIDIA_SMB_STS_ALRM 0x40
+#define NVIDIA_SMB_STS_RES 0x20
+#define NVIDIA_SMB_STS_STATUS 0x1f
+
+#define NVIDIA_SMB_PRTCL_WRITE 0x00
+#define NVIDIA_SMB_PRTCL_READ 0x01
+#define NVIDIA_SMB_PRTCL_QUICK 0x02
+#define NVIDIA_SMB_PRTCL_BYTE 0x04
+#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
+#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
+#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
+#define NVIDIA_SMB_PRTCL_PEC 0x80
+
+/* Misc definitions */
+#define MAX_TIMEOUT 100
+
+/* We disable the second SMBus channel on these boards */
+static const struct dmi_system_id nforce2_dmi_blacklist2[] = {
+ {
+ .ident = "DFI Lanparty NF4 Expert",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"),
+ DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"),
+ },
+ },
+ { }
+};
+
+static struct pci_driver nforce2_driver;
+
+/* For multiplexing support, we need a global reference to the 1st
+ SMBus channel */
+#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985)
+struct i2c_adapter *nforce2_smbus;
+EXPORT_SYMBOL_GPL(nforce2_smbus);
+
+static void nforce2_set_reference(struct i2c_adapter *adap)
+{
+ nforce2_smbus = adap;
+}
+#else
+static inline void nforce2_set_reference(struct i2c_adapter *adap) { }
+#endif
+
+static void nforce2_abort(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ dev_dbg(&adap->dev, "Aborting current transaction\n");
+
+ outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
+ } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
+ (timeout++ < MAX_TIMEOUT));
+ if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
+ dev_err(&adap->dev, "Can't reset the smbus\n");
+ outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
+}
+
+static int nforce2_check_status(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STS);
+ } while ((!temp) && (timeout++ < MAX_TIMEOUT));
+
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ if (smbus->can_abort)
+ nforce2_abort(adap);
+ return -ETIMEDOUT;
+ }
+ if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+ dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Return negative errno on error */
+static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ unsigned char protocol, pec;
+ u8 len;
+ int i, status;
+
+ protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
+ NVIDIA_SMB_PRTCL_WRITE;
+ pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ protocol |= NVIDIA_SMB_PRTCL_QUICK;
+ read_write = I2C_SMBUS_WRITE;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, NVIDIA_SMB_CMD);
+ protocol |= NVIDIA_SMB_PRTCL_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, NVIDIA_SMB_DATA);
+ protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word, NVIDIA_SMB_DATA);
+ outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
+ }
+ protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev,
+ "Transaction failed (requested block size: %d)\n",
+ len);
+ return -EINVAL;
+ }
+ outb_p(len, NVIDIA_SMB_BCNT);
+ for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
+ outb_p(data->block[i + 1],
+ NVIDIA_SMB_DATA + i);
+ }
+ protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
+ break;
+
+ default:
+ dev_err(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
+ outb_p(protocol, NVIDIA_SMB_PRTCL);
+
+ status = nforce2_check_status(adap);
+ if (status)
+ return status;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = inb_p(NVIDIA_SMB_DATA);
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ data->word = inb_p(NVIDIA_SMB_DATA) |
+ (inb_p(NVIDIA_SMB_DATA + 1) << 8);
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ len = inb_p(NVIDIA_SMB_BCNT);
+ if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev,
+ "Transaction failed (received block size: 0x%02x)\n",
+ len);
+ return -EPROTO;
+ }
+ for (i = 0; i < len; i++)
+ data->block[i + 1] = inb_p(NVIDIA_SMB_DATA + i);
+ data->block[0] = len;
+ break;
+ }
+
+ return 0;
+}
+
+
+static u32 nforce2_func(struct i2c_adapter *adapter)
+{
+ /* other functionality might be possible, but is not tested */
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PEC |
+ (((struct nforce2_smbus *)adapter->algo_data)->blockops ?
+ I2C_FUNC_SMBUS_BLOCK_DATA : 0);
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = nforce2_access,
+ .functionality = nforce2_func,
+};
+
+
+static const struct pci_device_id nforce2_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, nforce2_ids);
+
+
+static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg,
+ struct nforce2_smbus *smbus, const char *name)
+{
+ int error;
+
+ smbus->base = pci_resource_start(dev, bar);
+ if (smbus->base) {
+ smbus->size = pci_resource_len(dev, bar);
+ } else {
+ /* Older incarnations of the device used non-standard BARs */
+ u16 iobase;
+
+ if (pci_read_config_word(dev, alt_reg, &iobase)
+ != PCIBIOS_SUCCESSFUL) {
+ dev_err(&dev->dev, "Error reading PCI config for %s\n",
+ name);
+ return -EIO;
+ }
+
+ smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
+ smbus->size = 64;
+ }
+
+ error = acpi_check_region(smbus->base, smbus->size,
+ nforce2_driver.name);
+ if (error)
+ return error;
+
+ if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
+ dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
+ smbus->base, smbus->base+smbus->size-1, name);
+ return -EBUSY;
+ }
+ smbus->adapter.owner = THIS_MODULE;
+ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+ smbus->adapter.dev.parent = &dev->dev;
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+ "SMBus nForce2 adapter at %04x", smbus->base);
+
+ error = i2c_add_adapter(&smbus->adapter);
+ if (error) {
+ release_region(smbus->base, smbus->size);
+ return error;
+ }
+ dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n",
+ smbus->base);
+ return 0;
+}
+
+
+static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct nforce2_smbus *smbuses;
+ int res1, res2;
+
+ /* we support 2 SMBus adapters */
+ smbuses = kcalloc(2, sizeof(struct nforce2_smbus), GFP_KERNEL);
+ if (!smbuses)
+ return -ENOMEM;
+ pci_set_drvdata(dev, smbuses);
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
+ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
+ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
+ smbuses[0].blockops = 1;
+ smbuses[1].blockops = 1;
+ smbuses[0].can_abort = 1;
+ smbuses[1].can_abort = 1;
+ }
+
+ /* SMBus adapter 1 */
+ res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+ if (res1 < 0)
+ smbuses[0].base = 0; /* to have a check value */
+
+ /* SMBus adapter 2 */
+ if (dmi_check_system(nforce2_dmi_blacklist2)) {
+ dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n");
+ res2 = -EPERM;
+ smbuses[1].base = 0;
+ } else {
+ res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1],
+ "SMB2");
+ if (res2 < 0)
+ smbuses[1].base = 0; /* to have a check value */
+ }
+
+ if ((res1 < 0) && (res2 < 0)) {
+ /* we did not find even one of the SMBuses, so we give up */
+ kfree(smbuses);
+ return -ENODEV;
+ }
+
+ nforce2_set_reference(&smbuses[0].adapter);
+ return 0;
+}
+
+
+static void nforce2_remove(struct pci_dev *dev)
+{
+ struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
+
+ nforce2_set_reference(NULL);
+ if (smbuses[0].base) {
+ i2c_del_adapter(&smbuses[0].adapter);
+ release_region(smbuses[0].base, smbuses[0].size);
+ }
+ if (smbuses[1].base) {
+ i2c_del_adapter(&smbuses[1].adapter);
+ release_region(smbuses[1].base, smbuses[1].size);
+ }
+ kfree(smbuses);
+}
+
+static struct pci_driver nforce2_driver = {
+ .name = "nForce2_smbus",
+ .id_table = nforce2_ids,
+ .probe = nforce2_probe,
+ .remove = nforce2_remove,
+};
+
+module_pci_driver(nforce2_driver);
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
new file mode 100644
index 000000000..0ed5a4180
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * I2C master mode controller driver, used in Nomadik 8815
+ * and Ux500 platforms.
+ *
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ * Author: Sachin Verma <sachin.verma@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/init.h>
+#include <linux/module.h>
+#include <linux/amba/bus.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+
+#define DRIVER_NAME "nmk-i2c"
+
+/* I2C Controller register offsets */
+#define I2C_CR (0x000)
+#define I2C_SCR (0x004)
+#define I2C_HSMCR (0x008)
+#define I2C_MCR (0x00C)
+#define I2C_TFR (0x010)
+#define I2C_SR (0x014)
+#define I2C_RFR (0x018)
+#define I2C_TFTR (0x01C)
+#define I2C_RFTR (0x020)
+#define I2C_DMAR (0x024)
+#define I2C_BRCR (0x028)
+#define I2C_IMSCR (0x02C)
+#define I2C_RISR (0x030)
+#define I2C_MISR (0x034)
+#define I2C_ICR (0x038)
+
+/* Control registers */
+#define I2C_CR_PE (0x1 << 0) /* Peripheral Enable */
+#define I2C_CR_OM (0x3 << 1) /* Operating mode */
+#define I2C_CR_SAM (0x1 << 3) /* Slave addressing mode */
+#define I2C_CR_SM (0x3 << 4) /* Speed mode */
+#define I2C_CR_SGCM (0x1 << 6) /* Slave general call mode */
+#define I2C_CR_FTX (0x1 << 7) /* Flush Transmit */
+#define I2C_CR_FRX (0x1 << 8) /* Flush Receive */
+#define I2C_CR_DMA_TX_EN (0x1 << 9) /* DMA Tx enable */
+#define I2C_CR_DMA_RX_EN (0x1 << 10) /* DMA Rx Enable */
+#define I2C_CR_DMA_SLE (0x1 << 11) /* DMA sync. logic enable */
+#define I2C_CR_LM (0x1 << 12) /* Loopback mode */
+#define I2C_CR_FON (0x3 << 13) /* Filtering on */
+#define I2C_CR_FS (0x3 << 15) /* Force stop enable */
+
+/* Master controller (MCR) register */
+#define I2C_MCR_OP (0x1 << 0) /* Operation */
+#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */
+#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
+#define I2C_MCR_SB (0x1 << 11) /* Extended address */
+#define I2C_MCR_AM (0x3 << 12) /* Address type */
+#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
+#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
+
+/* Status register (SR) */
+#define I2C_SR_OP (0x3 << 0) /* Operation */
+#define I2C_SR_STATUS (0x3 << 2) /* controller status */
+#define I2C_SR_CAUSE (0x7 << 4) /* Abort cause */
+#define I2C_SR_TYPE (0x3 << 7) /* Receive type */
+#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */
+
+/* Interrupt mask set/clear (IMSCR) bits */
+#define I2C_IT_TXFE (0x1 << 0)
+#define I2C_IT_TXFNE (0x1 << 1)
+#define I2C_IT_TXFF (0x1 << 2)
+#define I2C_IT_TXFOVR (0x1 << 3)
+#define I2C_IT_RXFE (0x1 << 4)
+#define I2C_IT_RXFNF (0x1 << 5)
+#define I2C_IT_RXFF (0x1 << 6)
+#define I2C_IT_RFSR (0x1 << 16)
+#define I2C_IT_RFSE (0x1 << 17)
+#define I2C_IT_WTSR (0x1 << 18)
+#define I2C_IT_MTD (0x1 << 19)
+#define I2C_IT_STD (0x1 << 20)
+#define I2C_IT_MAL (0x1 << 24)
+#define I2C_IT_BERR (0x1 << 25)
+#define I2C_IT_MTDWS (0x1 << 28)
+
+#define GEN_MASK(val, mask, sb) (((val) << (sb)) & (mask))
+
+/* some bits in ICR are reserved */
+#define I2C_CLEAR_ALL_INTS 0x131f007f
+
+/* first three msb bits are reserved */
+#define IRQ_MASK(mask) (mask & 0x1fffffff)
+
+/* maximum threshold value */
+#define MAX_I2C_FIFO_THRESHOLD 15
+
+enum i2c_freq_mode {
+ I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */
+ I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */
+ I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */
+ I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */
+};
+
+/**
+ * struct i2c_vendor_data - per-vendor variations
+ * @has_mtdws: variant has the MTDWS bit
+ * @fifodepth: variant FIFO depth
+ */
+struct i2c_vendor_data {
+ bool has_mtdws;
+ u32 fifodepth;
+};
+
+enum i2c_status {
+ I2C_NOP,
+ I2C_ON_GOING,
+ I2C_OK,
+ I2C_ABORT
+};
+
+/* operation */
+enum i2c_operation {
+ I2C_NO_OPERATION = 0xff,
+ I2C_WRITE = 0x00,
+ I2C_READ = 0x01
+};
+
+/**
+ * struct i2c_nmk_client - client specific data
+ * @slave_adr: 7-bit slave address
+ * @count: no. bytes to be transferred
+ * @buffer: client data buffer
+ * @xfer_bytes: bytes transferred till now
+ * @operation: current I2C operation
+ */
+struct i2c_nmk_client {
+ unsigned short slave_adr;
+ unsigned long count;
+ unsigned char *buffer;
+ unsigned long xfer_bytes;
+ enum i2c_operation operation;
+};
+
+/**
+ * struct nmk_i2c_dev - private data structure of the controller.
+ * @vendor: vendor data for this variant.
+ * @adev: parent amba device.
+ * @adap: corresponding I2C adapter.
+ * @irq: interrupt line for the controller.
+ * @virtbase: virtual io memory area.
+ * @clk: hardware i2c block clock.
+ * @cli: holder of client specific data.
+ * @clk_freq: clock frequency for the operation mode
+ * @tft: Tx FIFO Threshold in bytes
+ * @rft: Rx FIFO Threshold in bytes
+ * @timeout Slave response timeout (ms)
+ * @sm: speed mode
+ * @stop: stop condition.
+ * @xfer_complete: acknowledge completion for a I2C message.
+ * @result: controller propogated result.
+ */
+struct nmk_i2c_dev {
+ struct i2c_vendor_data *vendor;
+ struct amba_device *adev;
+ struct i2c_adapter adap;
+ int irq;
+ void __iomem *virtbase;
+ struct clk *clk;
+ struct i2c_nmk_client cli;
+ u32 clk_freq;
+ unsigned char tft;
+ unsigned char rft;
+ int timeout;
+ enum i2c_freq_mode sm;
+ int stop;
+ struct completion xfer_complete;
+ int result;
+};
+
+/* controller's abort causes */
+static const char *abort_causes[] = {
+ "no ack received after address transmission",
+ "no ack received during data phase",
+ "ack received after xmission of master code",
+ "master lost arbitration",
+ "slave restarts",
+ "slave reset",
+ "overflow, maxsize is 2047 bytes",
+};
+
+static inline void i2c_set_bit(void __iomem *reg, u32 mask)
+{
+ writel(readl(reg) | mask, reg);
+}
+
+static inline void i2c_clr_bit(void __iomem *reg, u32 mask)
+{
+ writel(readl(reg) & ~mask, reg);
+}
+
+/**
+ * flush_i2c_fifo() - This function flushes the I2C FIFO
+ * @dev: private data of I2C Driver
+ *
+ * This function flushes the I2C Tx and Rx FIFOs. It returns
+ * 0 on successful flushing of FIFO
+ */
+static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
+{
+#define LOOP_ATTEMPTS 10
+ int i;
+ unsigned long timeout;
+
+ /*
+ * flush the transmit and receive FIFO. The flushing
+ * operation takes several cycles before to be completed.
+ * On the completion, the I2C internal logic clears these
+ * bits, until then no one must access Tx, Rx FIFO and
+ * should poll on these bits waiting for the completion.
+ */
+ writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
+
+ for (i = 0; i < LOOP_ATTEMPTS; i++) {
+ timeout = jiffies + dev->adap.timeout;
+
+ while (!time_after(jiffies, timeout)) {
+ if ((readl(dev->virtbase + I2C_CR) &
+ (I2C_CR_FTX | I2C_CR_FRX)) == 0)
+ return 0;
+ }
+ }
+
+ dev_err(&dev->adev->dev,
+ "flushing operation timed out giving up after %d attempts",
+ LOOP_ATTEMPTS);
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * disable_all_interrupts() - Disable all interrupts of this I2c Bus
+ * @dev: private data of I2C Driver
+ */
+static void disable_all_interrupts(struct nmk_i2c_dev *dev)
+{
+ u32 mask = IRQ_MASK(0);
+ writel(mask, dev->virtbase + I2C_IMSCR);
+}
+
+/**
+ * clear_all_interrupts() - Clear all interrupts of I2C Controller
+ * @dev: private data of I2C Driver
+ */
+static void clear_all_interrupts(struct nmk_i2c_dev *dev)
+{
+ u32 mask;
+ mask = IRQ_MASK(I2C_CLEAR_ALL_INTS);
+ writel(mask, dev->virtbase + I2C_ICR);
+}
+
+/**
+ * init_hw() - initialize the I2C hardware
+ * @dev: private data of I2C Driver
+ */
+static int init_hw(struct nmk_i2c_dev *dev)
+{
+ int stat;
+
+ stat = flush_i2c_fifo(dev);
+ if (stat)
+ goto exit;
+
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+ disable_all_interrupts(dev);
+
+ clear_all_interrupts(dev);
+
+ dev->cli.operation = I2C_NO_OPERATION;
+
+exit:
+ return stat;
+}
+
+/* enable peripheral, master mode operation */
+#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
+
+/**
+ * load_i2c_mcr_reg() - load the MCR register
+ * @dev: private data of controller
+ * @flags: message flags
+ */
+static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags)
+{
+ u32 mcr = 0;
+ unsigned short slave_adr_3msb_bits;
+
+ mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
+
+ if (unlikely(flags & I2C_M_TEN)) {
+ /* 10-bit address transaction */
+ mcr |= GEN_MASK(2, I2C_MCR_AM, 12);
+ /*
+ * Get the top 3 bits.
+ * EA10 represents extended address in MCR. This includes
+ * the extension (MSB bits) of the 7 bit address loaded
+ * in A7
+ */
+ slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7;
+
+ mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8);
+ } else {
+ /* 7-bit address transaction */
+ mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
+ }
+
+ /* start byte procedure not applied */
+ mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
+
+ /* check the operation, master read/write? */
+ if (dev->cli.operation == I2C_WRITE)
+ mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0);
+ else
+ mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0);
+
+ /* stop or repeated start? */
+ if (dev->stop)
+ mcr |= GEN_MASK(1, I2C_MCR_STOP, 14);
+ else
+ mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14));
+
+ mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15);
+
+ return mcr;
+}
+
+/**
+ * setup_i2c_controller() - setup the controller
+ * @dev: private data of controller
+ */
+static void setup_i2c_controller(struct nmk_i2c_dev *dev)
+{
+ u32 brcr1, brcr2;
+ u32 i2c_clk, div;
+ u32 ns;
+ u16 slsu;
+
+ writel(0x0, dev->virtbase + I2C_CR);
+ writel(0x0, dev->virtbase + I2C_HSMCR);
+ writel(0x0, dev->virtbase + I2C_TFTR);
+ writel(0x0, dev->virtbase + I2C_RFTR);
+ writel(0x0, dev->virtbase + I2C_DMAR);
+
+ i2c_clk = clk_get_rate(dev->clk);
+
+ /*
+ * set the slsu:
+ *
+ * slsu defines the data setup time after SCL clock
+ * stretching in terms of i2c clk cycles + 1 (zero means
+ * "wait one cycle"), the needed setup time for the three
+ * modes are 250ns, 100ns, 10ns respectively.
+ *
+ * As the time for one cycle T in nanoseconds is
+ * T = (1/f) * 1000000000 =>
+ * slsu = cycles / (1000000000 / f) + 1
+ */
+ ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk);
+ switch (dev->sm) {
+ case I2C_FREQ_MODE_FAST:
+ case I2C_FREQ_MODE_FAST_PLUS:
+ slsu = DIV_ROUND_UP(100, ns); /* Fast */
+ break;
+ case I2C_FREQ_MODE_HIGH_SPEED:
+ slsu = DIV_ROUND_UP(10, ns); /* High */
+ break;
+ case I2C_FREQ_MODE_STANDARD:
+ default:
+ slsu = DIV_ROUND_UP(250, ns); /* Standard */
+ break;
+ }
+ slsu += 1;
+
+ dev_dbg(&dev->adev->dev, "calculated SLSU = %04x\n", slsu);
+ writel(slsu << 16, dev->virtbase + I2C_SCR);
+
+ /*
+ * The spec says, in case of std. mode the divider is
+ * 2 whereas it is 3 for fast and fastplus mode of
+ * operation. TODO - high speed support.
+ */
+ div = (dev->clk_freq > 100000) ? 3 : 2;
+
+ /*
+ * generate the mask for baud rate counters. The controller
+ * has two baud rate counters. One is used for High speed
+ * operation, and the other is for std, fast mode, fast mode
+ * plus operation. Currently we do not supprt high speed mode
+ * so set brcr1 to 0.
+ */
+ brcr1 = 0 << 16;
+ brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff;
+
+ /* set the baud rate counter register */
+ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+
+ /*
+ * set the speed mode. Currently we support
+ * only standard and fast mode of operation
+ * TODO - support for fast mode plus (up to 1Mb/s)
+ * and high speed (up to 3.4 Mb/s)
+ */
+ if (dev->sm > I2C_FREQ_MODE_FAST) {
+ dev_err(&dev->adev->dev,
+ "do not support this mode defaulting to std. mode\n");
+ brcr2 = i2c_clk/(100000 * 2) & 0xffff;
+ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+ writel(I2C_FREQ_MODE_STANDARD << 4,
+ dev->virtbase + I2C_CR);
+ }
+ writel(dev->sm << 4, dev->virtbase + I2C_CR);
+
+ /* set the Tx and Rx FIFO threshold */
+ writel(dev->tft, dev->virtbase + I2C_TFTR);
+ writel(dev->rft, dev->virtbase + I2C_RFTR);
+}
+
+/**
+ * read_i2c() - Read from I2C client device
+ * @dev: private data of I2C Driver
+ * @flags: message flags
+ *
+ * This function reads from i2c client device when controller is in
+ * master mode. There is a completion timeout. If there is no transfer
+ * before timeout error is returned.
+ */
+static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
+{
+ int status = 0;
+ u32 mcr, irq_mask;
+ unsigned long timeout;
+
+ mcr = load_i2c_mcr_reg(dev, flags);
+ writel(mcr, dev->virtbase + I2C_MCR);
+
+ /* load the current CR value */
+ writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+ dev->virtbase + I2C_CR);
+
+ /* enable the controller */
+ i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+
+ init_completion(&dev->xfer_complete);
+
+ /* enable interrupts by setting the mask */
+ irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
+ I2C_IT_MAL | I2C_IT_BERR);
+
+ if (dev->stop || !dev->vendor->has_mtdws)
+ irq_mask |= I2C_IT_MTD;
+ else
+ irq_mask |= I2C_IT_MTDWS;
+
+ irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+ writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+ dev->virtbase + I2C_IMSCR);
+
+ timeout = wait_for_completion_timeout(
+ &dev->xfer_complete, dev->adap.timeout);
+
+ if (timeout == 0) {
+ /* Controller timed out */
+ dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n",
+ dev->cli.slave_adr);
+ status = -ETIMEDOUT;
+ }
+ return status;
+}
+
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+ int count;
+
+ for (count = (no_bytes - 2);
+ (count > 0) &&
+ (dev->cli.count != 0);
+ count--) {
+ /* write to the Tx FIFO */
+ writeb(*dev->cli.buffer,
+ dev->virtbase + I2C_TFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+
+}
+
+/**
+ * write_i2c() - Write data to I2C client.
+ * @dev: private data of I2C Driver
+ * @flags: message flags
+ *
+ * This function writes data to I2C client
+ */
+static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
+{
+ u32 status = 0;
+ u32 mcr, irq_mask;
+ unsigned long timeout;
+
+ mcr = load_i2c_mcr_reg(dev, flags);
+
+ writel(mcr, dev->virtbase + I2C_MCR);
+
+ /* load the current CR value */
+ writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+ dev->virtbase + I2C_CR);
+
+ /* enable the controller */
+ i2c_set_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+ init_completion(&dev->xfer_complete);
+
+ /* enable interrupts by settings the masks */
+ irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+ /* Fill the TX FIFO with transmit data */
+ fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+ if (dev->cli.count != 0)
+ irq_mask |= I2C_IT_TXFNE;
+
+ /*
+ * check if we want to transfer a single or multiple bytes, if so
+ * set the MTDWS bit (Master Transaction Done Without Stop)
+ * to start repeated start operation
+ */
+ if (dev->stop || !dev->vendor->has_mtdws)
+ irq_mask |= I2C_IT_MTD;
+ else
+ irq_mask |= I2C_IT_MTDWS;
+
+ irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+ writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+ dev->virtbase + I2C_IMSCR);
+
+ timeout = wait_for_completion_timeout(
+ &dev->xfer_complete, dev->adap.timeout);
+
+ if (timeout == 0) {
+ /* Controller timed out */
+ dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n",
+ dev->cli.slave_adr);
+ status = -ETIMEDOUT;
+ }
+
+ return status;
+}
+
+/**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+ int status;
+
+ if (flags & I2C_M_RD) {
+ /* read operation */
+ dev->cli.operation = I2C_READ;
+ status = read_i2c(dev, flags);
+ } else {
+ /* write operation */
+ dev->cli.operation = I2C_WRITE;
+ status = write_i2c(dev, flags);
+ }
+
+ if (status || (dev->result)) {
+ u32 i2c_sr;
+ u32 cause;
+
+ i2c_sr = readl(dev->virtbase + I2C_SR);
+ /*
+ * Check if the controller I2C operation status
+ * is set to ABORT(11b).
+ */
+ if (((i2c_sr >> 2) & 0x3) == 0x3) {
+ /* get the abort cause */
+ cause = (i2c_sr >> 4) & 0x7;
+ dev_err(&dev->adev->dev, "%s\n",
+ cause >= ARRAY_SIZE(abort_causes) ?
+ "unknown reason" :
+ abort_causes[cause]);
+ }
+
+ (void) init_hw(dev);
+
+ status = status ? status : dev->result;
+ }
+
+ return status;
+}
+
+/**
+ * nmk_i2c_xfer() - I2C transfer function used by kernel framework
+ * @i2c_adap: Adapter pointer to the controller
+ * @msgs: Pointer to data to be written.
+ * @num_msgs: Number of messages to be executed
+ *
+ * This is the function called by the generic kernel i2c_transfer()
+ * or i2c_smbus...() API calls. Note that this code is protected by the
+ * semaphore set in the kernel i2c_transfer() function.
+ *
+ * NOTE:
+ * READ TRANSFER : We impose a restriction of the first message to be the
+ * index message for any read transaction.
+ * - a no index is coded as '0',
+ * - 2byte big endian index is coded as '3'
+ * !!! msg[0].buf holds the actual index.
+ * This is compatible with generic messages of smbus emulator
+ * that send a one byte index.
+ * eg. a I2C transation to read 2 bytes from index 0
+ * idx = 0;
+ * msg[0].addr = client->addr;
+ * msg[0].flags = 0x0;
+ * msg[0].len = 1;
+ * msg[0].buf = &idx;
+ *
+ * msg[1].addr = client->addr;
+ * msg[1].flags = I2C_M_RD;
+ * msg[1].len = 2;
+ * msg[1].buf = rd_buff
+ * i2c_transfer(adap, msg, 2);
+ *
+ * WRITE TRANSFER : The I2C standard interface interprets all data as payload.
+ * If you want to emulate an SMBUS write transaction put the
+ * index as first byte(or first and second) in the payload.
+ * eg. a I2C transation to write 2 bytes from index 1
+ * wr_buff[0] = 0x1;
+ * wr_buff[1] = 0x23;
+ * wr_buff[2] = 0x46;
+ * msg[0].flags = 0x0;
+ * msg[0].len = 3;
+ * msg[0].buf = wr_buff;
+ * i2c_transfer(adap, msg, 1);
+ *
+ * To read or write a block of data (multiple bytes) using SMBUS emulation
+ * please use the i2c_smbus_read_i2c_block_data()
+ * or i2c_smbus_write_i2c_block_data() API
+ */
+static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num_msgs)
+{
+ int status = 0;
+ int i;
+ struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+ int j;
+
+ pm_runtime_get_sync(&dev->adev->dev);
+
+ /* Attempt three times to send the message queue */
+ for (j = 0; j < 3; j++) {
+ /* setup the i2c controller */
+ setup_i2c_controller(dev);
+
+ for (i = 0; i < num_msgs; i++) {
+ dev->cli.slave_adr = msgs[i].addr;
+ dev->cli.buffer = msgs[i].buf;
+ dev->cli.count = msgs[i].len;
+ dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+ dev->result = 0;
+
+ status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+ if (status != 0)
+ break;
+ }
+ if (status == 0)
+ break;
+ }
+
+ pm_runtime_put_sync(&dev->adev->dev);
+
+ /* return the no. messages processed */
+ if (status)
+ return status;
+ else
+ return num_msgs;
+}
+
+/**
+ * disable_interrupts() - disable the interrupts
+ * @dev: private data of controller
+ * @irq: interrupt number
+ */
+static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
+{
+ irq = IRQ_MASK(irq);
+ writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq),
+ dev->virtbase + I2C_IMSCR);
+ return 0;
+}
+
+/**
+ * i2c_irq_handler() - interrupt routine
+ * @irq: interrupt number
+ * @arg: data passed to the handler
+ *
+ * This is the interrupt handler for the i2c driver. Currently
+ * it handles the major interrupts like Rx & Tx FIFO management
+ * interrupts, master transaction interrupts, arbitration and
+ * bus error interrupts. The rest of the interrupts are treated as
+ * unhandled.
+ */
+static irqreturn_t i2c_irq_handler(int irq, void *arg)
+{
+ struct nmk_i2c_dev *dev = arg;
+ u32 tft, rft;
+ u32 count;
+ u32 misr, src;
+
+ /* load Tx FIFO and Rx FIFO threshold values */
+ tft = readl(dev->virtbase + I2C_TFTR);
+ rft = readl(dev->virtbase + I2C_RFTR);
+
+ /* read interrupt status register */
+ misr = readl(dev->virtbase + I2C_MISR);
+
+ src = __ffs(misr);
+ switch ((1 << src)) {
+
+ /* Transmit FIFO nearly empty interrupt */
+ case I2C_IT_TXFNE:
+ {
+ if (dev->cli.operation == I2C_READ) {
+ /*
+ * in read operation why do we care for writing?
+ * so disable the Transmit FIFO interrupt
+ */
+ disable_interrupts(dev, I2C_IT_TXFNE);
+ } else {
+ fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
+ /*
+ * if done, close the transfer by disabling the
+ * corresponding TXFNE interrupt
+ */
+ if (dev->cli.count == 0)
+ disable_interrupts(dev, I2C_IT_TXFNE);
+ }
+ }
+ break;
+
+ /*
+ * Rx FIFO nearly full interrupt.
+ * This is set when the numer of entries in Rx FIFO is
+ * greater or equal than the threshold value programmed
+ * in RFT
+ */
+ case I2C_IT_RXFNF:
+ for (count = rft; count > 0; count--) {
+ /* Read the Rx FIFO */
+ *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ }
+ dev->cli.count -= rft;
+ dev->cli.xfer_bytes += rft;
+ break;
+
+ /* Rx FIFO full */
+ case I2C_IT_RXFF:
+ for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) {
+ *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ }
+ dev->cli.count -= MAX_I2C_FIFO_THRESHOLD;
+ dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD;
+ break;
+
+ /* Master Transaction Done with/without stop */
+ case I2C_IT_MTD:
+ case I2C_IT_MTDWS:
+ if (dev->cli.operation == I2C_READ) {
+ while (!(readl(dev->virtbase + I2C_RISR)
+ & I2C_IT_RXFE)) {
+ if (dev->cli.count == 0)
+ break;
+ *dev->cli.buffer =
+ readb(dev->virtbase + I2C_RFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+ }
+
+ disable_all_interrupts(dev);
+ clear_all_interrupts(dev);
+
+ if (dev->cli.count) {
+ dev->result = -EIO;
+ dev_err(&dev->adev->dev,
+ "%lu bytes still remain to be xfered\n",
+ dev->cli.count);
+ (void) init_hw(dev);
+ }
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /* Master Arbitration lost interrupt */
+ case I2C_IT_MAL:
+ dev->result = -EIO;
+ (void) init_hw(dev);
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /*
+ * Bus Error interrupt.
+ * This happens when an unexpected start/stop condition occurs
+ * during the transaction.
+ */
+ case I2C_IT_BERR:
+ dev->result = -EIO;
+ /* get the status */
+ if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
+ (void) init_hw(dev);
+
+ i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR);
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /*
+ * Tx FIFO overrun interrupt.
+ * This is set when a write operation in Tx FIFO is performed and
+ * the Tx FIFO is full.
+ */
+ case I2C_IT_TXFOVR:
+ dev->result = -EIO;
+ (void) init_hw(dev);
+
+ dev_err(&dev->adev->dev, "Tx Fifo Over run\n");
+ complete(&dev->xfer_complete);
+
+ break;
+
+ /* unhandled interrupts by this driver - TODO*/
+ case I2C_IT_TXFE:
+ case I2C_IT_TXFF:
+ case I2C_IT_RXFE:
+ case I2C_IT_RFSR:
+ case I2C_IT_RFSE:
+ case I2C_IT_WTSR:
+ case I2C_IT_STD:
+ dev_err(&dev->adev->dev, "unhandled Interrupt\n");
+ break;
+ default:
+ dev_err(&dev->adev->dev, "spurious Interrupt..\n");
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int nmk_i2c_suspend_late(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ pinctrl_pm_select_sleep_state(dev);
+ return 0;
+}
+
+static int nmk_i2c_resume_early(struct device *dev)
+{
+ return pm_runtime_force_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int nmk_i2c_runtime_suspend(struct device *dev)
+{
+ struct amba_device *adev = to_amba_device(dev);
+ struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+
+ clk_disable_unprepare(nmk_i2c->clk);
+ pinctrl_pm_select_idle_state(dev);
+ return 0;
+}
+
+static int nmk_i2c_runtime_resume(struct device *dev)
+{
+ struct amba_device *adev = to_amba_device(dev);
+ struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+ int ret;
+
+ ret = clk_prepare_enable(nmk_i2c->clk);
+ if (ret) {
+ dev_err(dev, "can't prepare_enable clock\n");
+ return ret;
+ }
+
+ pinctrl_pm_select_default_state(dev);
+
+ ret = init_hw(nmk_i2c);
+ if (ret) {
+ clk_disable_unprepare(nmk_i2c->clk);
+ pinctrl_pm_select_idle_state(dev);
+ }
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops nmk_i2c_pm = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early)
+ SET_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend,
+ nmk_i2c_runtime_resume,
+ NULL)
+};
+
+static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm nmk_i2c_algo = {
+ .master_xfer = nmk_i2c_xfer,
+ .functionality = nmk_i2c_functionality
+};
+
+static void nmk_i2c_of_probe(struct device_node *np,
+ struct nmk_i2c_dev *nmk)
+{
+ /* Default to 100 kHz if no frequency is given in the node */
+ if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq))
+ nmk->clk_freq = 100000;
+
+ /* This driver only supports 'standard' and 'fast' modes of operation. */
+ if (nmk->clk_freq <= 100000)
+ nmk->sm = I2C_FREQ_MODE_STANDARD;
+ else
+ nmk->sm = I2C_FREQ_MODE_FAST;
+ nmk->tft = 1; /* Tx FIFO threshold */
+ nmk->rft = 8; /* Rx FIFO threshold */
+ nmk->timeout = 200; /* Slave response timeout(ms) */
+}
+
+static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ int ret = 0;
+ struct device_node *np = adev->dev.of_node;
+ struct nmk_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct i2c_vendor_data *vendor = id->data;
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+
+ dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&adev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+ dev->vendor = vendor;
+ dev->adev = adev;
+ nmk_i2c_of_probe(np, dev);
+
+ if (dev->tft > max_fifo_threshold) {
+ dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
+ dev->tft, max_fifo_threshold);
+ dev->tft = max_fifo_threshold;
+ }
+
+ if (dev->rft > max_fifo_threshold) {
+ dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
+ dev->rft, max_fifo_threshold);
+ dev->rft = max_fifo_threshold;
+ }
+
+ amba_set_drvdata(adev, dev);
+
+ dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
+ resource_size(&adev->res));
+ if (!dev->virtbase) {
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ dev->irq = adev->irq[0];
+ ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
+ DRIVER_NAME, dev);
+ if (ret) {
+ dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
+ goto err_no_mem;
+ }
+
+ dev->clk = devm_clk_get(&adev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(&adev->dev, "could not get i2c clock\n");
+ ret = PTR_ERR(dev->clk);
+ goto err_no_mem;
+ }
+
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ dev_err(&adev->dev, "can't prepare_enable clock\n");
+ goto err_no_mem;
+ }
+
+ init_hw(dev);
+
+ adap = &dev->adap;
+ adap->dev.of_node = np;
+ adap->dev.parent = &adev->dev;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_DEPRECATED;
+ adap->algo = &nmk_i2c_algo;
+ adap->timeout = msecs_to_jiffies(dev->timeout);
+ snprintf(adap->name, sizeof(adap->name),
+ "Nomadik I2C at %pR", &adev->res);
+
+ i2c_set_adapdata(adap, dev);
+
+ dev_info(&adev->dev,
+ "initialize %s on virtual base %p\n",
+ adap->name, dev->virtbase);
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ goto err_no_adap;
+
+ pm_runtime_put(&adev->dev);
+
+ return 0;
+
+ err_no_adap:
+ clk_disable_unprepare(dev->clk);
+ err_no_mem:
+
+ return ret;
+}
+
+static int nmk_i2c_remove(struct amba_device *adev)
+{
+ struct resource *res = &adev->res;
+ struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
+
+ i2c_del_adapter(&dev->adap);
+ flush_i2c_fifo(dev);
+ disable_all_interrupts(dev);
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+ clk_disable_unprepare(dev->clk);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ return 0;
+}
+
+static struct i2c_vendor_data vendor_stn8815 = {
+ .has_mtdws = false,
+ .fifodepth = 16, /* Guessed from TFTR/RFTR = 7 */
+};
+
+static struct i2c_vendor_data vendor_db8500 = {
+ .has_mtdws = true,
+ .fifodepth = 32, /* Guessed from TFTR/RFTR = 15 */
+};
+
+static const struct amba_id nmk_i2c_ids[] = {
+ {
+ .id = 0x00180024,
+ .mask = 0x00ffffff,
+ .data = &vendor_stn8815,
+ },
+ {
+ .id = 0x00380024,
+ .mask = 0x00ffffff,
+ .data = &vendor_db8500,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(amba, nmk_i2c_ids);
+
+static struct amba_driver nmk_i2c_driver = {
+ .drv = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .pm = &nmk_i2c_pm,
+ },
+ .id_table = nmk_i2c_ids,
+ .probe = nmk_i2c_probe,
+ .remove = nmk_i2c_remove,
+};
+
+static int __init nmk_i2c_init(void)
+{
+ return amba_driver_register(&nmk_i2c_driver);
+}
+
+static void __exit nmk_i2c_exit(void)
+{
+ amba_driver_unregister(&nmk_i2c_driver);
+}
+
+subsys_initcall(nmk_i2c_init);
+module_exit(nmk_i2c_exit);
+
+MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
+MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
new file mode 100644
index 000000000..87f9caacb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -0,0 +1,582 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (https://opencores.org/project/i2c/overview)
+ *
+ * Peter Korsgaard <peter@korsgaard.com>
+ *
+ * Support for the GRLIB port of the controller by
+ * Andreas Larsson <andreas@gaisler.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/platform_data/i2c-ocores.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+
+struct ocores_i2c {
+ void __iomem *base;
+ u32 reg_shift;
+ u32 reg_io_width;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state; /* see STATE_ */
+ struct clk *clk;
+ int ip_clock_khz;
+ int bus_clock_khz;
+ void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value);
+ u8 (*getreg)(struct ocores_i2c *i2c, int reg);
+};
+
+/* registers */
+#define OCI2C_PRELOW 0
+#define OCI2C_PREHIGH 1
+#define OCI2C_CONTROL 2
+#define OCI2C_DATA 3
+#define OCI2C_CMD 4 /* write only */
+#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */
+
+#define OCI2C_CTRL_IEN 0x40
+#define OCI2C_CTRL_EN 0x80
+
+#define OCI2C_CMD_START 0x91
+#define OCI2C_CMD_STOP 0x41
+#define OCI2C_CMD_READ 0x21
+#define OCI2C_CMD_WRITE 0x11
+#define OCI2C_CMD_READ_ACK 0x21
+#define OCI2C_CMD_READ_NACK 0x29
+#define OCI2C_CMD_IACK 0x01
+
+#define OCI2C_STAT_IF 0x01
+#define OCI2C_STAT_TIP 0x02
+#define OCI2C_STAT_ARBLOST 0x20
+#define OCI2C_STAT_BUSY 0x40
+#define OCI2C_STAT_NACK 0x80
+
+#define STATE_DONE 0
+#define STATE_START 1
+#define STATE_WRITE 2
+#define STATE_READ 3
+#define STATE_ERROR 4
+
+#define TYPE_OCORES 0
+#define TYPE_GRLIB 1
+
+static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite8(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite16(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite32(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite16be(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite32be(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg)
+{
+ return ioread8(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg)
+{
+ return ioread16(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg)
+{
+ return ioread32(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg)
+{
+ return ioread16be(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg)
+{
+ return ioread32be(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ i2c->setreg(i2c, reg, value);
+}
+
+static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+ return i2c->getreg(i2c, reg);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->msg;
+ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+ if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
+ /* stop has been sent */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ wake_up(&i2c->wait);
+ return;
+ }
+
+ /* error? */
+ if (stat & OCI2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+
+ if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
+ i2c->state =
+ (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & OCI2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ } else
+ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+ /* end of msg? */
+ if (i2c->pos == msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) { /* end? */
+ /* send start? */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ u8 addr = i2c_8bit_addr_from_msg(msg);
+
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, addr);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+ return;
+ } else
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ } else {
+ i2c->state = STATE_DONE;
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+ return;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
+ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+ } else {
+ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+ }
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id)
+{
+ struct ocores_i2c *i2c = dev_id;
+
+ ocores_process(i2c);
+
+ return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_START;
+
+ oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ))
+ return (i2c->state == STATE_DONE) ? num : -EIO;
+ else
+ return -ETIMEDOUT;
+}
+
+static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
+{
+ int prescale;
+ int diff;
+ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;
+ prescale = clamp(prescale, 0, 0xffff);
+
+ diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz;
+ if (abs(diff) > i2c->bus_clock_khz / 10) {
+ dev_err(dev,
+ "Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
+ i2c->ip_clock_khz, i2c->bus_clock_khz);
+ return -EINVAL;
+ }
+
+ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+ /* Init the device */
+ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+
+ return 0;
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ocores_algorithm = {
+ .master_xfer = ocores_xfer,
+ .functionality = ocores_func,
+};
+
+static const struct i2c_adapter ocores_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ocores",
+ .class = I2C_CLASS_DEPRECATED,
+ .algo = &ocores_algorithm,
+};
+
+static const struct of_device_id ocores_i2c_match[] = {
+ {
+ .compatible = "opencores,i2c-ocores",
+ .data = (void *)TYPE_OCORES,
+ },
+ {
+ .compatible = "aeroflexgaisler,i2cmst",
+ .data = (void *)TYPE_GRLIB,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ocores_i2c_match);
+
+#ifdef CONFIG_OF
+/* Read and write functions for the GRLIB port of the controller. Registers are
+ * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one
+ * register. The subsequent registers has their offset decreased accordingly. */
+static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg)
+{
+ u32 rd;
+ int rreg = reg;
+ if (reg != OCI2C_PRELOW)
+ rreg--;
+ rd = ioread32be(i2c->base + (rreg << i2c->reg_shift));
+ if (reg == OCI2C_PREHIGH)
+ return (u8)(rd >> 8);
+ else
+ return (u8)rd;
+}
+
+static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ u32 curr, wr;
+ int rreg = reg;
+ if (reg != OCI2C_PRELOW)
+ rreg--;
+ if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) {
+ curr = ioread32be(i2c->base + (rreg << i2c->reg_shift));
+ if (reg == OCI2C_PRELOW)
+ wr = (curr & 0xff00) | value;
+ else
+ wr = (((u32)value) << 8) | (curr & 0xff);
+ } else {
+ wr = value;
+ }
+ iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift));
+}
+
+static int ocores_i2c_of_probe(struct platform_device *pdev,
+ struct ocores_i2c *i2c)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ u32 val;
+ u32 clock_frequency;
+ bool clock_frequency_present;
+
+ if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
+ /* no 'reg-shift', check for deprecated 'regstep' */
+ if (!of_property_read_u32(np, "regstep", &val)) {
+ if (!is_power_of_2(val)) {
+ dev_err(&pdev->dev, "invalid regstep %d\n",
+ val);
+ return -EINVAL;
+ }
+ i2c->reg_shift = ilog2(val);
+ dev_warn(&pdev->dev,
+ "regstep property deprecated, use reg-shift\n");
+ }
+ }
+
+ clock_frequency_present = !of_property_read_u32(np, "clock-frequency",
+ &clock_frequency);
+ i2c->bus_clock_khz = 100;
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (!IS_ERR(i2c->clk)) {
+ int ret = clk_prepare_enable(i2c->clk);
+
+ if (ret) {
+ dev_err(&pdev->dev,
+ "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+ i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000;
+ if (clock_frequency_present)
+ i2c->bus_clock_khz = clock_frequency / 1000;
+ }
+
+ if (i2c->ip_clock_khz == 0) {
+ if (of_property_read_u32(np, "opencores,ip-clock-frequency",
+ &val)) {
+ if (!clock_frequency_present) {
+ dev_err(&pdev->dev,
+ "Missing required parameter 'opencores,ip-clock-frequency'\n");
+ clk_disable_unprepare(i2c->clk);
+ return -ENODEV;
+ }
+ i2c->ip_clock_khz = clock_frequency / 1000;
+ dev_warn(&pdev->dev,
+ "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");
+ } else {
+ i2c->ip_clock_khz = val / 1000;
+ if (clock_frequency_present)
+ i2c->bus_clock_khz = clock_frequency / 1000;
+ }
+ }
+
+ of_property_read_u32(pdev->dev.of_node, "reg-io-width",
+ &i2c->reg_io_width);
+
+ match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+ if (match && (long)match->data == TYPE_GRLIB) {
+ dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n");
+ i2c->setreg = oc_setreg_grlib;
+ i2c->getreg = oc_getreg_grlib;
+ }
+
+ return 0;
+}
+#else
+#define ocores_i2c_of_probe(pdev,i2c) -ENODEV
+#endif
+
+static int ocores_i2c_probe(struct platform_device *pdev)
+{
+ struct ocores_i2c *i2c;
+ struct ocores_i2c_platform_data *pdata;
+ struct resource *res;
+ int irq;
+ int ret;
+ int i;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (pdata) {
+ i2c->reg_shift = pdata->reg_shift;
+ i2c->reg_io_width = pdata->reg_io_width;
+ i2c->ip_clock_khz = pdata->clock_khz;
+ i2c->bus_clock_khz = 100;
+ } else {
+ ret = ocores_i2c_of_probe(pdev, i2c);
+ if (ret)
+ return ret;
+ }
+
+ if (i2c->reg_io_width == 0)
+ i2c->reg_io_width = 1; /* Set to default value */
+
+ if (!i2c->setreg || !i2c->getreg) {
+ bool be = pdata ? pdata->big_endian :
+ of_device_is_big_endian(pdev->dev.of_node);
+
+ switch (i2c->reg_io_width) {
+ case 1:
+ i2c->setreg = oc_setreg_8;
+ i2c->getreg = oc_getreg_8;
+ break;
+
+ case 2:
+ i2c->setreg = be ? oc_setreg_16be : oc_setreg_16;
+ i2c->getreg = be ? oc_getreg_16be : oc_getreg_16;
+ break;
+
+ case 4:
+ i2c->setreg = be ? oc_setreg_32be : oc_setreg_32;
+ i2c->getreg = be ? oc_getreg_32be : oc_getreg_32;
+ break;
+
+ default:
+ dev_err(&pdev->dev, "Unsupported I/O width (%d)\n",
+ i2c->reg_io_width);
+ ret = -EINVAL;
+ goto err_clk;
+ }
+ }
+
+ ret = ocores_init(&pdev->dev, i2c);
+ if (ret)
+ goto err_clk;
+
+ init_waitqueue_head(&i2c->wait);
+ ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
+ pdev->name, i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto err_clk;
+ }
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = ocores_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ goto err_clk;
+
+ /* add in known devices to the bus */
+ if (pdata) {
+ for (i = 0; i < pdata->num_devices; i++)
+ i2c_new_device(&i2c->adap, pdata->devices + i);
+ }
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int ocores_i2c_remove(struct platform_device *pdev)
+{
+ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+
+ /* disable i2c logic */
+ oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
+ & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+
+ if (!IS_ERR(i2c->clk))
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ocores_i2c_suspend(struct device *dev)
+{
+ struct ocores_i2c *i2c = dev_get_drvdata(dev);
+ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+ /* make sure the device is disabled */
+ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+ if (!IS_ERR(i2c->clk))
+ clk_disable_unprepare(i2c->clk);
+ return 0;
+}
+
+static int ocores_i2c_resume(struct device *dev)
+{
+ struct ocores_i2c *i2c = dev_get_drvdata(dev);
+
+ if (!IS_ERR(i2c->clk)) {
+ unsigned long rate;
+ int ret = clk_prepare_enable(i2c->clk);
+
+ if (ret) {
+ dev_err(dev,
+ "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+ rate = clk_get_rate(i2c->clk) / 1000;
+ if (rate)
+ i2c->ip_clock_khz = rate;
+ }
+ return ocores_init(dev, i2c);
+}
+
+static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
+#define OCORES_I2C_PM (&ocores_i2c_pm)
+#else
+#define OCORES_I2C_PM NULL
+#endif
+
+static struct platform_driver ocores_i2c_driver = {
+ .probe = ocores_i2c_probe,
+ .remove = ocores_i2c_remove,
+ .driver = {
+ .name = "ocores-i2c",
+ .of_match_table = ocores_i2c_match,
+ .pm = OCORES_I2C_PM,
+ },
+};
+
+module_platform_driver(ocores_i2c_driver);
+
+MODULE_AUTHOR("Peter Korsgaard <peter@korsgaard.com>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ocores-i2c");
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
new file mode 100644
index 000000000..845eda70b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -0,0 +1,792 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "i2c-octeon-core.h"
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+ struct octeon_i2c *i2c = dev_id;
+
+ i2c->int_disable(i2c);
+ wake_up(&i2c->queue);
+
+ return IRQ_HANDLED;
+}
+
+static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+{
+ return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+ long time_left;
+
+ /*
+ * Some chip revisions don't assert the irq in the interrupt
+ * controller. So we must poll for the IFLG change.
+ */
+ if (i2c->broken_irq_mode) {
+ u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+ while (!octeon_i2c_test_iflg(i2c) &&
+ time_before64(get_jiffies_64(), end))
+ usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+ return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+ }
+
+ i2c->int_enable(i2c);
+ time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+ i2c->adap.timeout);
+ i2c->int_disable(i2c);
+
+ if (i2c->broken_irq_check && !time_left &&
+ octeon_i2c_test_iflg(i2c)) {
+ dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+ i2c->broken_irq_mode = true;
+ return 0;
+ }
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
+{
+ return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0;
+}
+
+static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
+{
+ /* clear ST/TS events, listen for neither */
+ octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT);
+}
+
+/*
+ * Cleanup low-level state & enable high-level controller.
+ */
+static void octeon_i2c_hlc_enable(struct octeon_i2c *i2c)
+{
+ int try = 0;
+ u64 val;
+
+ if (i2c->hlc_enabled)
+ return;
+ i2c->hlc_enabled = true;
+
+ while (1) {
+ val = octeon_i2c_ctl_read(i2c);
+ if (!(val & (TWSI_CTL_STA | TWSI_CTL_STP)))
+ break;
+
+ /* clear IFLG event */
+ if (val & TWSI_CTL_IFLG)
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+ if (try++ > 100) {
+ pr_err("%s: giving up\n", __func__);
+ break;
+ }
+
+ /* spin until any start/stop has finished */
+ udelay(10);
+ }
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_CE | TWSI_CTL_AAK | TWSI_CTL_ENAB);
+}
+
+static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
+{
+ if (!i2c->hlc_enabled)
+ return;
+
+ i2c->hlc_enabled = false;
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+}
+
+/**
+ * octeon_i2c_hlc_wait - wait for an HLC operation to complete
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise -ETIMEDOUT.
+ */
+static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
+{
+ int time_left;
+
+ /*
+ * Some cn38xx boards don't assert the irq in the interrupt
+ * controller. So we must poll for the valid bit change.
+ */
+ if (i2c->broken_irq_mode) {
+ u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+ while (!octeon_i2c_hlc_test_valid(i2c) &&
+ time_before64(get_jiffies_64(), end))
+ usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+ return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT;
+ }
+
+ i2c->hlc_int_enable(i2c);
+ time_left = wait_event_timeout(i2c->queue,
+ octeon_i2c_hlc_test_valid(i2c),
+ i2c->adap.timeout);
+ i2c->hlc_int_disable(i2c);
+ if (!time_left)
+ octeon_i2c_hlc_int_clear(i2c);
+
+ if (i2c->broken_irq_check && !time_left &&
+ octeon_i2c_hlc_test_valid(i2c)) {
+ dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+ i2c->broken_irq_mode = true;
+ return 0;
+ }
+
+ if (!time_left)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
+{
+ u8 stat;
+
+ /*
+ * This is ugly... in HLC mode the status is not in the status register
+ * but in the lower 8 bits of SW_TWSI.
+ */
+ if (i2c->hlc_enabled)
+ stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ else
+ stat = octeon_i2c_stat_read(i2c);
+
+ switch (stat) {
+ /* Everything is fine */
+ case STAT_IDLE:
+ case STAT_AD2W_ACK:
+ case STAT_RXADDR_ACK:
+ case STAT_TXADDR_ACK:
+ case STAT_TXDATA_ACK:
+ return 0;
+
+ /* ACK allowed on pre-terminal bytes only */
+ case STAT_RXDATA_ACK:
+ if (!final_read)
+ return 0;
+ return -EIO;
+
+ /* NAK allowed on terminal byte only */
+ case STAT_RXDATA_NAK:
+ if (final_read)
+ return 0;
+ return -EIO;
+
+ /* Arbitration lost */
+ case STAT_LOST_ARB_38:
+ case STAT_LOST_ARB_68:
+ case STAT_LOST_ARB_78:
+ case STAT_LOST_ARB_B0:
+ return -EAGAIN;
+
+ /* Being addressed as slave, should back off & listen */
+ case STAT_SLAVE_60:
+ case STAT_SLAVE_70:
+ case STAT_GENDATA_ACK:
+ case STAT_GENDATA_NAK:
+ return -EOPNOTSUPP;
+
+ /* Core busy as slave */
+ case STAT_SLAVE_80:
+ case STAT_SLAVE_88:
+ case STAT_SLAVE_A0:
+ case STAT_SLAVE_A8:
+ case STAT_SLAVE_LOST:
+ case STAT_SLAVE_NAK:
+ case STAT_SLAVE_ACK:
+ return -EOPNOTSUPP;
+
+ case STAT_TXDATA_NAK:
+ case STAT_BUS_ERROR:
+ return -EIO;
+ case STAT_TXADDR_NAK:
+ case STAT_RXADDR_NAK:
+ case STAT_AD2W_NAK:
+ return -ENXIO;
+ default:
+ dev_err(i2c->dev, "unhandled state: %d\n", stat);
+ return -EIO;
+ }
+}
+
+static int octeon_i2c_recovery(struct octeon_i2c *i2c)
+{
+ int ret;
+
+ ret = i2c_recover_bus(&i2c->adap);
+ if (ret)
+ /* recover failed, try hardware re-init */
+ ret = octeon_i2c_init_lowlevel(i2c);
+ return ret;
+}
+
+/**
+ * octeon_i2c_start - send START to the bus
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
+{
+ int ret;
+ u8 stat;
+
+ octeon_i2c_hlc_disable(i2c);
+
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
+ ret = octeon_i2c_wait(i2c);
+ if (ret)
+ goto error;
+
+ stat = octeon_i2c_stat_read(i2c);
+ if (stat == STAT_START || stat == STAT_REP_START)
+ /* START successful, bail out */
+ return 0;
+
+error:
+ /* START failed, try to recover */
+ ret = octeon_i2c_recovery(i2c);
+ return (ret) ? ret : -EAGAIN;
+}
+
+/* send STOP to the bus */
+static void octeon_i2c_stop(struct octeon_i2c *i2c)
+{
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP);
+}
+
+/**
+ * octeon_i2c_read - receive data from the bus via low-level controller
+ * @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the location to store the data
+ * @rlength: Length of the data
+ * @recv_len: flag for length byte
+ *
+ * The address is sent over the bus, then the data is read.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
+ u8 *data, u16 *rlength, bool recv_len)
+{
+ int i, result, length = *rlength;
+ bool final_read = false;
+
+ octeon_i2c_data_write(i2c, (target << 1) | 1);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ /* address OK ? */
+ result = octeon_i2c_check_status(i2c, false);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ /*
+ * For the last byte to receive TWSI_CTL_AAK must not be set.
+ *
+ * A special case is I2C_M_RECV_LEN where we don't know the
+ * additional length yet. If recv_len is set we assume we're
+ * not reading the final byte and therefore need to set
+ * TWSI_CTL_AAK.
+ */
+ if ((i + 1 == length) && !(recv_len && i == 0))
+ final_read = true;
+
+ /* clear iflg to allow next event */
+ if (final_read)
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+ else
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ data[i] = octeon_i2c_data_read(i2c, &result);
+ if (result)
+ return result;
+ if (recv_len && i == 0) {
+ if (data[i] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ length += data[i];
+ }
+
+ result = octeon_i2c_check_status(i2c, final_read);
+ if (result)
+ return result;
+ }
+ *rlength = length;
+ return 0;
+}
+
+/**
+ * octeon_i2c_write - send data to the bus via low-level controller
+ * @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the data to be sent
+ * @length: Length of the data
+ *
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+ const u8 *data, int length)
+{
+ int i, result;
+
+ octeon_i2c_data_write(i2c, target << 1);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+
+ for (i = 0; i < length; i++) {
+ result = octeon_i2c_check_status(i2c, false);
+ if (result)
+ return result;
+
+ octeon_i2c_data_write(i2c, data[i]);
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+ result = octeon_i2c_wait(i2c);
+ if (result)
+ return result;
+ }
+
+ return 0;
+}
+
+/* high-level-controller pure read of up to 8 bytes */
+static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+ int i, j, ret = 0;
+ u64 cmd;
+
+ octeon_i2c_hlc_enable(i2c);
+ octeon_i2c_hlc_int_clear(i2c);
+
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+ /* SIZE */
+ cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
+ /* A */
+ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+ if (msgs[0].flags & I2C_M_TEN)
+ cmd |= SW_TWSI_OP_10;
+ else
+ cmd |= SW_TWSI_OP_7;
+
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+ ret = octeon_i2c_hlc_wait(i2c);
+ if (ret)
+ goto err;
+
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if ((cmd & SW_TWSI_R) == 0)
+ return octeon_i2c_check_status(i2c, false);
+
+ for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--)
+ msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
+
+ if (msgs[0].len > 4) {
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
+ for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
+ msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
+ }
+
+err:
+ return ret;
+}
+
+/* high-level-controller pure write of up to 8 bytes */
+static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+ int i, j, ret = 0;
+ u64 cmd;
+
+ octeon_i2c_hlc_enable(i2c);
+ octeon_i2c_hlc_int_clear(i2c);
+
+ cmd = SW_TWSI_V | SW_TWSI_SOVR;
+ /* SIZE */
+ cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
+ /* A */
+ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+ if (msgs[0].flags & I2C_M_TEN)
+ cmd |= SW_TWSI_OP_10;
+ else
+ cmd |= SW_TWSI_OP_7;
+
+ for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--)
+ cmd |= (u64)msgs[0].buf[j] << (8 * i);
+
+ if (msgs[0].len > 4) {
+ u64 ext = 0;
+
+ for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
+ ext |= (u64)msgs[0].buf[j] << (8 * i);
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
+ }
+
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+ ret = octeon_i2c_hlc_wait(i2c);
+ if (ret)
+ goto err;
+
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if ((cmd & SW_TWSI_R) == 0)
+ return octeon_i2c_check_status(i2c, false);
+
+err:
+ return ret;
+}
+
+/* high-level-controller composite write+read, msg0=addr, msg1=data */
+static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+ int i, j, ret = 0;
+ u64 cmd;
+
+ octeon_i2c_hlc_enable(i2c);
+
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+ /* SIZE */
+ cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
+ /* A */
+ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+ if (msgs[0].flags & I2C_M_TEN)
+ cmd |= SW_TWSI_OP_10_IA;
+ else
+ cmd |= SW_TWSI_OP_7_IA;
+
+ if (msgs[0].len == 2) {
+ u64 ext = 0;
+
+ cmd |= SW_TWSI_EIA;
+ ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+ cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
+ } else {
+ cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+ }
+
+ octeon_i2c_hlc_int_clear(i2c);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+
+ ret = octeon_i2c_hlc_wait(i2c);
+ if (ret)
+ goto err;
+
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if ((cmd & SW_TWSI_R) == 0)
+ return octeon_i2c_check_status(i2c, false);
+
+ for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--)
+ msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
+
+ if (msgs[1].len > 4) {
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c));
+ for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--)
+ msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
+ }
+
+err:
+ return ret;
+}
+
+/* high-level-controller composite write+write, m[0]len<=2, m[1]len<=8 */
+static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+ bool set_ext = false;
+ int i, j, ret = 0;
+ u64 cmd, ext = 0;
+
+ octeon_i2c_hlc_enable(i2c);
+
+ cmd = SW_TWSI_V | SW_TWSI_SOVR;
+ /* SIZE */
+ cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
+ /* A */
+ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+ if (msgs[0].flags & I2C_M_TEN)
+ cmd |= SW_TWSI_OP_10_IA;
+ else
+ cmd |= SW_TWSI_OP_7_IA;
+
+ if (msgs[0].len == 2) {
+ cmd |= SW_TWSI_EIA;
+ ext |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+ set_ext = true;
+ cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
+ } else {
+ cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+ }
+
+ for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--)
+ cmd |= (u64)msgs[1].buf[j] << (8 * i);
+
+ if (msgs[1].len > 4) {
+ for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--)
+ ext |= (u64)msgs[1].buf[j] << (8 * i);
+ set_ext = true;
+ }
+ if (set_ext)
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c));
+
+ octeon_i2c_hlc_int_clear(i2c);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c));
+
+ ret = octeon_i2c_hlc_wait(i2c);
+ if (ret)
+ goto err;
+
+ cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if ((cmd & SW_TWSI_R) == 0)
+ return octeon_i2c_check_status(i2c, false);
+
+err:
+ return ret;
+}
+
+/**
+ * octeon_i2c_xfer - The driver's master_xfer function
+ * @adap: Pointer to the i2c_adapter structure
+ * @msgs: Pointer to the messages to be processed
+ * @num: Length of the MSGS array
+ *
+ * Returns the number of messages processed, or a negative errno on failure.
+ */
+int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+ int i, ret = 0;
+
+ if (num == 1) {
+ if (msgs[0].len > 0 && msgs[0].len <= 8) {
+ if (msgs[0].flags & I2C_M_RD)
+ ret = octeon_i2c_hlc_read(i2c, msgs);
+ else
+ ret = octeon_i2c_hlc_write(i2c, msgs);
+ goto out;
+ }
+ } else if (num == 2) {
+ if ((msgs[0].flags & I2C_M_RD) == 0 &&
+ (msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
+ msgs[0].len > 0 && msgs[0].len <= 2 &&
+ msgs[1].len > 0 && msgs[1].len <= 8 &&
+ msgs[0].addr == msgs[1].addr) {
+ if (msgs[1].flags & I2C_M_RD)
+ ret = octeon_i2c_hlc_comp_read(i2c, msgs);
+ else
+ ret = octeon_i2c_hlc_comp_write(i2c, msgs);
+ goto out;
+ }
+ }
+
+ for (i = 0; ret == 0 && i < num; i++) {
+ struct i2c_msg *pmsg = &msgs[i];
+
+ /* zero-length messages are not supported */
+ if (!pmsg->len) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ ret = octeon_i2c_start(i2c);
+ if (ret)
+ return ret;
+
+ if (pmsg->flags & I2C_M_RD)
+ ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
+ &pmsg->len, pmsg->flags & I2C_M_RECV_LEN);
+ else
+ ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ }
+ octeon_i2c_stop(i2c);
+out:
+ return (ret != 0) ? ret : num;
+}
+
+/* calculate and set clock divisors */
+void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+{
+ int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+ int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+
+ for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+ /*
+ * An mdiv value of less than 2 seems to not work well
+ * with ds1337 RTCs, so we constrain it to larger values.
+ */
+ for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
+ /*
+ * For given ndiv and mdiv values check the
+ * two closest thp values.
+ */
+ tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+ tclk *= (1 << ndiv_idx);
+ thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+
+ for (inc = 0; inc <= 1; inc++) {
+ thp_idx = thp_base + inc;
+ if (thp_idx < 5 || thp_idx > 0xff)
+ continue;
+
+ foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+ foscl = foscl / (1 << ndiv_idx);
+ foscl = foscl / (mdiv_idx + 1) / 10;
+ diff = abs(foscl - i2c->twsi_freq);
+ if (diff < delta_hz) {
+ delta_hz = diff;
+ thp = thp_idx;
+ mdiv = mdiv_idx;
+ ndiv = ndiv_idx;
+ }
+ }
+ }
+ }
+ octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+}
+
+int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+{
+ u8 status = 0;
+ int tries;
+
+ /* reset controller */
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+ for (tries = 10; tries && status != STAT_IDLE; tries--) {
+ udelay(1);
+ status = octeon_i2c_stat_read(i2c);
+ if (status == STAT_IDLE)
+ break;
+ }
+
+ if (status != STAT_IDLE) {
+ dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n",
+ __func__, status);
+ return -EIO;
+ }
+
+ /* toggle twice to force both teardowns */
+ octeon_i2c_hlc_enable(i2c);
+ octeon_i2c_hlc_disable(i2c);
+ return 0;
+}
+
+static int octeon_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+ u64 state;
+
+ state = octeon_i2c_read_int(i2c);
+ return state & TWSI_INT_SCL;
+}
+
+static void octeon_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+ octeon_i2c_write_int(i2c, val ? 0 : TWSI_INT_SCL_OVR);
+}
+
+static int octeon_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+ u64 state;
+
+ state = octeon_i2c_read_int(i2c);
+ return state & TWSI_INT_SDA;
+}
+
+static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+ octeon_i2c_hlc_disable(i2c);
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+ /* wait for software reset to settle */
+ udelay(5);
+
+ /*
+ * Bring control register to a good state regardless
+ * of HLC state.
+ */
+ octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+ octeon_i2c_write_int(i2c, 0);
+}
+
+static void octeon_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+ /*
+ * Generate STOP to finish the unfinished transaction.
+ * Can't generate STOP via the TWSI CTL register
+ * since it could bring the TWSI controller into an inoperable state.
+ */
+ octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR);
+ udelay(5);
+ octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR);
+ udelay(5);
+ octeon_i2c_write_int(i2c, 0);
+}
+
+struct i2c_bus_recovery_info octeon_i2c_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = octeon_i2c_get_scl,
+ .set_scl = octeon_i2c_set_scl,
+ .get_sda = octeon_i2c_get_sda,
+ .prepare_recovery = octeon_i2c_prepare_recovery,
+ .unprepare_recovery = octeon_i2c_unprepare_recovery,
+};
diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h
new file mode 100644
index 000000000..9bb9f64fd
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon-core.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+/* Controller command patterns */
+#define SW_TWSI_V BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */
+#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */
+#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_ADDR_SHIFT 40
+#define SW_TWSI_IA_SHIFT 32 /* Internal address */
+
+/* Controller opcode word (bits 60:57) */
+#define SW_TWSI_OP_SHIFT 57
+#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
+
+/* Controller extended opcode word (bits 34:32) */
+#define SW_TWSI_EOP_SHIFT 32
+#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE 0x80 /* High level controller enable */
+#define TWSI_CTL_ENAB 0x40 /* Bus enable */
+#define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */
+#define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */
+#define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK 0x04 /* Assert ACK */
+
+/* Status values */
+#define STAT_BUS_ERROR 0x00
+#define STAT_START 0x08
+#define STAT_REP_START 0x10
+#define STAT_TXADDR_ACK 0x18
+#define STAT_TXADDR_NAK 0x20
+#define STAT_TXDATA_ACK 0x28
+#define STAT_TXDATA_NAK 0x30
+#define STAT_LOST_ARB_38 0x38
+#define STAT_RXADDR_ACK 0x40
+#define STAT_RXADDR_NAK 0x48
+#define STAT_RXDATA_ACK 0x50
+#define STAT_RXDATA_NAK 0x58
+#define STAT_SLAVE_60 0x60
+#define STAT_LOST_ARB_68 0x68
+#define STAT_SLAVE_70 0x70
+#define STAT_LOST_ARB_78 0x78
+#define STAT_SLAVE_80 0x80
+#define STAT_SLAVE_88 0x88
+#define STAT_GENDATA_ACK 0x90
+#define STAT_GENDATA_NAK 0x98
+#define STAT_SLAVE_A0 0xA0
+#define STAT_SLAVE_A8 0xA8
+#define STAT_LOST_ARB_B0 0xB0
+#define STAT_SLAVE_LOST 0xB8
+#define STAT_SLAVE_NAK 0xC0
+#define STAT_SLAVE_ACK 0xC8
+#define STAT_AD2W_ACK 0xD0
+#define STAT_AD2W_NAK 0xD8
+#define STAT_IDLE 0xF8
+
+/* TWSI_INT values */
+#define TWSI_INT_ST_INT BIT_ULL(0)
+#define TWSI_INT_TS_INT BIT_ULL(1)
+#define TWSI_INT_CORE_INT BIT_ULL(2)
+#define TWSI_INT_ST_EN BIT_ULL(4)
+#define TWSI_INT_TS_EN BIT_ULL(5)
+#define TWSI_INT_CORE_EN BIT_ULL(6)
+#define TWSI_INT_SDA_OVR BIT_ULL(8)
+#define TWSI_INT_SCL_OVR BIT_ULL(9)
+#define TWSI_INT_SDA BIT_ULL(10)
+#define TWSI_INT_SCL BIT_ULL(11)
+
+#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */
+
+/* Register offsets */
+struct octeon_i2c_reg_offset {
+ unsigned int sw_twsi;
+ unsigned int twsi_int;
+ unsigned int sw_twsi_ext;
+};
+
+#define SW_TWSI(x) (x->roff.sw_twsi)
+#define TWSI_INT(x) (x->roff.twsi_int)
+#define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext)
+
+struct octeon_i2c {
+ wait_queue_head_t queue;
+ struct i2c_adapter adap;
+ struct octeon_i2c_reg_offset roff;
+ struct clk *clk;
+ int irq;
+ int hlc_irq; /* For cn7890 only */
+ u32 twsi_freq;
+ int sys_freq;
+ void __iomem *twsi_base;
+ struct device *dev;
+ bool hlc_enabled;
+ bool broken_irq_mode;
+ bool broken_irq_check;
+ void (*int_enable)(struct octeon_i2c *);
+ void (*int_disable)(struct octeon_i2c *);
+ void (*hlc_int_enable)(struct octeon_i2c *);
+ void (*hlc_int_disable)(struct octeon_i2c *);
+ atomic_t int_enable_cnt;
+ atomic_t hlc_int_enable_cnt;
+ struct i2c_smbus_alert_setup alert_data;
+ struct i2c_client *ara;
+};
+
+static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
+{
+ __raw_writeq(val, addr);
+ __raw_readq(addr); /* wait for write to land */
+}
+
+/**
+ * octeon_i2c_reg_write - write an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ * @data: Value to be written
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+{
+ int tries = 1000;
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
+ do {
+ tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if (--tries < 0)
+ return;
+ } while ((tmp & SW_TWSI_V) != 0);
+}
+
+#define octeon_i2c_ctl_write(i2c, val) \
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val)
+#define octeon_i2c_data_write(i2c, val) \
+ octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val)
+
+/**
+ * octeon_i2c_reg_read - read lower bits of an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
+ int *error)
+{
+ int tries = 1000;
+ u64 tmp;
+
+ __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
+ do {
+ tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+ if (--tries < 0) {
+ /* signal that the returned data is invalid */
+ if (error)
+ *error = -EIO;
+ return 0;
+ }
+ } while ((tmp & SW_TWSI_V) != 0);
+
+ return tmp & 0xFF;
+}
+
+#define octeon_i2c_ctl_read(i2c) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
+#define octeon_i2c_data_read(i2c, error) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
+#define octeon_i2c_stat_read(i2c) \
+ octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
+
+/**
+ * octeon_i2c_read_int - read the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns the value of the register.
+ */
+static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
+{
+ return __raw_readq(i2c->twsi_base + TWSI_INT(i2c));
+}
+
+/**
+ * octeon_i2c_write_int - write the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ * @data: Value to be written
+ */
+static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+{
+ octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c));
+}
+
+/* Prototypes */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id);
+int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
+int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c);
+void octeon_i2c_set_clock(struct octeon_i2c *i2c);
+extern struct i2c_bus_recovery_info octeon_i2c_recovery_info;
diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c
new file mode 100644
index 000000000..64bda83e6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon-platdrv.c
@@ -0,0 +1,286 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/octeon/octeon.h>
+#include "i2c-octeon-core.h"
+
+#define DRV_NAME "i2c-octeon"
+
+/**
+ * octeon_i2c_int_enable - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
+{
+ /* clear TS/ST/IFLG events */
+ octeon_i2c_write_int(i2c, 0);
+}
+
+/**
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+ atomic_inc_return(&i2c->int_enable_cnt);
+ enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+ int count;
+
+ /*
+ * The interrupt can be disabled in two places, but we only
+ * want to make the disable_irq_nosync() call once, so keep
+ * track with the atomic variable.
+ */
+ count = atomic_dec_if_positive(cnt);
+ if (count >= 0)
+ disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+ __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+ atomic_inc_return(&i2c->hlc_int_enable_cnt);
+ enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+ __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq);
+}
+
+/* HLC interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+ struct octeon_i2c *i2c = dev_id;
+
+ i2c->hlc_int_disable(i2c);
+ wake_up(&i2c->queue);
+
+ return IRQ_HANDLED;
+}
+
+static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_write_int(i2c, TWSI_INT_ST_EN);
+}
+
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm octeon_i2c_algo = {
+ .master_xfer = octeon_i2c_xfer,
+ .functionality = octeon_i2c_functionality,
+};
+
+static const struct i2c_adapter octeon_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "OCTEON adapter",
+ .algo = &octeon_i2c_algo,
+};
+
+static int octeon_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int irq, result = 0, hlc_irq = 0;
+ struct resource *res_mem;
+ struct octeon_i2c *i2c;
+ bool cn78xx_style;
+
+ cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi");
+ if (cn78xx_style) {
+ hlc_irq = platform_get_irq(pdev, 0);
+ if (hlc_irq < 0)
+ return hlc_irq;
+
+ irq = platform_get_irq(pdev, 2);
+ if (irq < 0)
+ return irq;
+ } else {
+ /* All adaptors have an irq. */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ }
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c) {
+ result = -ENOMEM;
+ goto out;
+ }
+ i2c->dev = &pdev->dev;
+
+ i2c->roff.sw_twsi = 0x00;
+ i2c->roff.twsi_int = 0x10;
+ i2c->roff.sw_twsi_ext = 0x18;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem);
+ if (IS_ERR(i2c->twsi_base)) {
+ result = PTR_ERR(i2c->twsi_base);
+ goto out;
+ }
+
+ /*
+ * "clock-rate" is a legacy binding, the official binding is
+ * "clock-frequency". Try the official one first and then
+ * fall back if it doesn't exist.
+ */
+ if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) &&
+ of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) {
+ dev_err(i2c->dev,
+ "no I2C 'clock-rate' or 'clock-frequency' property\n");
+ result = -ENXIO;
+ goto out;
+ }
+
+ i2c->sys_freq = octeon_get_io_clock_rate();
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->irq = irq;
+
+ if (cn78xx_style) {
+ i2c->hlc_irq = hlc_irq;
+
+ i2c->int_enable = octeon_i2c_int_enable78;
+ i2c->int_disable = octeon_i2c_int_disable78;
+ i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78;
+ i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78;
+
+ irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN);
+ irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN);
+
+ result = devm_request_irq(&pdev->dev, i2c->hlc_irq,
+ octeon_i2c_hlc_isr78, 0,
+ DRV_NAME, i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto out;
+ }
+ } else {
+ i2c->int_enable = octeon_i2c_int_enable;
+ i2c->int_disable = octeon_i2c_int_disable;
+ i2c->hlc_int_enable = octeon_i2c_hlc_int_enable;
+ i2c->hlc_int_disable = octeon_i2c_int_disable;
+ }
+
+ result = devm_request_irq(&pdev->dev, i2c->irq,
+ octeon_i2c_isr, 0, DRV_NAME, i2c);
+ if (result < 0) {
+ dev_err(i2c->dev, "failed to attach interrupt\n");
+ goto out;
+ }
+
+ if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+ i2c->broken_irq_check = true;
+
+ result = octeon_i2c_init_lowlevel(i2c);
+ if (result) {
+ dev_err(i2c->dev, "init low level failed\n");
+ goto out;
+ }
+
+ octeon_i2c_set_clock(i2c);
+
+ i2c->adap = octeon_i2c_ops;
+ i2c->adap.timeout = msecs_to_jiffies(2);
+ i2c->adap.retries = 5;
+ i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = node;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ result = i2c_add_adapter(&i2c->adap);
+ if (result < 0)
+ goto out;
+ dev_info(i2c->dev, "probed\n");
+ return 0;
+
+out:
+ return result;
+};
+
+static int octeon_i2c_remove(struct platform_device *pdev)
+{
+ struct octeon_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+};
+
+static const struct of_device_id octeon_i2c_match[] = {
+ { .compatible = "cavium,octeon-3860-twsi", },
+ { .compatible = "cavium,octeon-7890-twsi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_i2c_match);
+
+static struct platform_driver octeon_i2c_driver = {
+ .probe = octeon_i2c_probe,
+ .remove = octeon_i2c_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = octeon_i2c_match,
+ },
+};
+
+module_platform_driver(octeon_i2c_driver);
+
+MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
new file mode 100644
index 000000000..cd9c65f3d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -0,0 +1,1577 @@
+/*
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ * Tony Lindgren <tony@atomide.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * Juha Yrjölä <juha.yrjola@solidboot.com>
+ * Syed Khasim <x0khasim@ti.com>
+ * Nishant Menon <nm@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/i2c-omap.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
+
+/* I2C controller revisions */
+#define OMAP_I2C_OMAP1_REV_2 0x20
+
+/* I2C controller revisions present on specific hardware */
+#define OMAP_I2C_REV_ON_2430 0x00000036
+#define OMAP_I2C_REV_ON_3430_3530 0x0000003C
+#define OMAP_I2C_REV_ON_3630 0x00000040
+#define OMAP_I2C_REV_ON_4430_PLUS 0x50400002
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+/* timeout for pm runtime autosuspend */
+#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */
+
+/* timeout for making decision on bus free status */
+#define OMAP_I2C_BUS_FREE_TIMEOUT (msecs_to_jiffies(10))
+
+/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
+enum {
+ OMAP_I2C_REV_REG = 0,
+ OMAP_I2C_IE_REG,
+ OMAP_I2C_STAT_REG,
+ OMAP_I2C_IV_REG,
+ OMAP_I2C_WE_REG,
+ OMAP_I2C_SYSS_REG,
+ OMAP_I2C_BUF_REG,
+ OMAP_I2C_CNT_REG,
+ OMAP_I2C_DATA_REG,
+ OMAP_I2C_SYSC_REG,
+ OMAP_I2C_CON_REG,
+ OMAP_I2C_OA_REG,
+ OMAP_I2C_SA_REG,
+ OMAP_I2C_PSC_REG,
+ OMAP_I2C_SCLL_REG,
+ OMAP_I2C_SCLH_REG,
+ OMAP_I2C_SYSTEST_REG,
+ OMAP_I2C_BUFSTAT_REG,
+ /* only on OMAP4430 */
+ OMAP_I2C_IP_V2_REVNB_LO,
+ OMAP_I2C_IP_V2_REVNB_HI,
+ OMAP_I2C_IP_V2_IRQSTATUS_RAW,
+ OMAP_I2C_IP_V2_IRQENABLE_SET,
+ OMAP_I2C_IP_V2_IRQENABLE_CLR,
+};
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
+#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_BF (1 << 8) /* Bus Free */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C WE wakeup enable register */
+#define OMAP_I2C_WE_XDR_WE (1 << 14) /* TX drain wakup */
+#define OMAP_I2C_WE_RDR_WE (1 << 13) /* RX drain wakeup */
+#define OMAP_I2C_WE_AAS_WE (1 << 9) /* Address as slave wakeup*/
+#define OMAP_I2C_WE_BF_WE (1 << 8) /* Bus free wakeup */
+#define OMAP_I2C_WE_STC_WE (1 << 6) /* Start condition wakeup */
+#define OMAP_I2C_WE_GC_WE (1 << 5) /* General call wakeup */
+#define OMAP_I2C_WE_DRDY_WE (1 << 3) /* TX/RX data ready wakeup */
+#define OMAP_I2C_WE_ARDY_WE (1 << 2) /* Reg access ready wakeup */
+#define OMAP_I2C_WE_NACK_WE (1 << 1) /* No acknowledgment wakeup */
+#define OMAP_I2C_WE_AL_WE (1 << 0) /* Arbitration lost wakeup */
+
+#define OMAP_I2C_WE_ALL (OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \
+ OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \
+ OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \
+ OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \
+ OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE)
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL 8
+#define OMAP_I2C_SCLH_HSSCLH 8
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+/* Functional mode */
+#define OMAP_I2C_SYSTEST_SCL_I_FUNC (1 << 8) /* SCL line input value */
+#define OMAP_I2C_SYSTEST_SCL_O_FUNC (1 << 7) /* SCL line output value */
+#define OMAP_I2C_SYSTEST_SDA_I_FUNC (1 << 6) /* SDA line input value */
+#define OMAP_I2C_SYSTEST_SDA_O_FUNC (1 << 5) /* SDA line output value */
+/* SDA/SCL IO mode */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+
+/* OCP_SYSSTATUS bit definitions */
+#define SYSS_RESETDONE_MASK (1 << 0)
+
+/* OCP_SYSCONFIG bit definitions */
+#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8)
+#define SYSC_SIDLEMODE_MASK (0x3 << 3)
+#define SYSC_ENAWAKEUP_MASK (1 << 2)
+#define SYSC_SOFTRESET_MASK (1 << 1)
+#define SYSC_AUTOIDLE_MASK (1 << 0)
+
+#define SYSC_IDLEMODE_SMART 0x2
+#define SYSC_CLOCKACTIVITY_FCLK 0x2
+
+/* Errata definitions */
+#define I2C_OMAP_ERRATA_I207 (1 << 0)
+#define I2C_OMAP_ERRATA_I462 (1 << 1)
+
+#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
+
+struct omap_i2c_dev {
+ struct device *dev;
+ void __iomem *base; /* virtual */
+ int irq;
+ int reg_shift; /* bit shift for I2C register addresses */
+ struct completion cmd_complete;
+ struct resource *ioarea;
+ u32 latency; /* maximum mpu wkup latency */
+ void (*set_mpu_wkup_lat)(struct device *dev,
+ long latency);
+ u32 speed; /* Speed of bus in kHz */
+ u32 flags;
+ u16 scheme;
+ u16 cmd_err;
+ u8 *buf;
+ u8 *regs;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ u8 threshold;
+ u8 fifo_size; /* use as flag and value
+ * fifo_size==0 implies no fifo
+ * if set, should be trsh+1
+ */
+ u32 rev;
+ unsigned b_hw:1; /* bad h/w fixes */
+ unsigned bb_valid:1; /* true when BB-bit reflects
+ * the I2C bus state
+ */
+ unsigned receiver:1; /* true when we're in receiver mode */
+ u16 iestate; /* Saved interrupt register */
+ u16 pscstate;
+ u16 scllstate;
+ u16 sclhstate;
+ u16 syscstate;
+ u16 westate;
+ u16 errata;
+};
+
+static const u8 reg_map_ip_v1[] = {
+ [OMAP_I2C_REV_REG] = 0x00,
+ [OMAP_I2C_IE_REG] = 0x01,
+ [OMAP_I2C_STAT_REG] = 0x02,
+ [OMAP_I2C_IV_REG] = 0x03,
+ [OMAP_I2C_WE_REG] = 0x03,
+ [OMAP_I2C_SYSS_REG] = 0x04,
+ [OMAP_I2C_BUF_REG] = 0x05,
+ [OMAP_I2C_CNT_REG] = 0x06,
+ [OMAP_I2C_DATA_REG] = 0x07,
+ [OMAP_I2C_SYSC_REG] = 0x08,
+ [OMAP_I2C_CON_REG] = 0x09,
+ [OMAP_I2C_OA_REG] = 0x0a,
+ [OMAP_I2C_SA_REG] = 0x0b,
+ [OMAP_I2C_PSC_REG] = 0x0c,
+ [OMAP_I2C_SCLL_REG] = 0x0d,
+ [OMAP_I2C_SCLH_REG] = 0x0e,
+ [OMAP_I2C_SYSTEST_REG] = 0x0f,
+ [OMAP_I2C_BUFSTAT_REG] = 0x10,
+};
+
+static const u8 reg_map_ip_v2[] = {
+ [OMAP_I2C_REV_REG] = 0x04,
+ [OMAP_I2C_IE_REG] = 0x2c,
+ [OMAP_I2C_STAT_REG] = 0x28,
+ [OMAP_I2C_IV_REG] = 0x34,
+ [OMAP_I2C_WE_REG] = 0x34,
+ [OMAP_I2C_SYSS_REG] = 0x90,
+ [OMAP_I2C_BUF_REG] = 0x94,
+ [OMAP_I2C_CNT_REG] = 0x98,
+ [OMAP_I2C_DATA_REG] = 0x9c,
+ [OMAP_I2C_SYSC_REG] = 0x10,
+ [OMAP_I2C_CON_REG] = 0xa4,
+ [OMAP_I2C_OA_REG] = 0xa8,
+ [OMAP_I2C_SA_REG] = 0xac,
+ [OMAP_I2C_PSC_REG] = 0xb0,
+ [OMAP_I2C_SCLL_REG] = 0xb4,
+ [OMAP_I2C_SCLH_REG] = 0xb8,
+ [OMAP_I2C_SYSTEST_REG] = 0xbC,
+ [OMAP_I2C_BUFSTAT_REG] = 0xc0,
+ [OMAP_I2C_IP_V2_REVNB_LO] = 0x00,
+ [OMAP_I2C_IP_V2_REVNB_HI] = 0x04,
+ [OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24,
+ [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c,
+ [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap,
+ int reg, u16 val)
+{
+ writew_relaxed(val, omap->base +
+ (omap->regs[reg] << omap->reg_shift));
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *omap, int reg)
+{
+ return readw_relaxed(omap->base +
+ (omap->regs[reg] << omap->reg_shift));
+}
+
+static void __omap_i2c_init(struct omap_i2c_dev *omap)
+{
+
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(omap, OMAP_I2C_PSC_REG, omap->pscstate);
+
+ /* SCL low and high time values */
+ omap_i2c_write_reg(omap, OMAP_I2C_SCLL_REG, omap->scllstate);
+ omap_i2c_write_reg(omap, OMAP_I2C_SCLH_REG, omap->sclhstate);
+ if (omap->rev >= OMAP_I2C_REV_ON_3430_3530)
+ omap_i2c_write_reg(omap, OMAP_I2C_WE_REG, omap->westate);
+
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+ /*
+ * NOTE: right after setting CON_EN, STAT_BB could be 0 while the
+ * bus is busy. It will be changed to 1 on the next IP FCLK clock.
+ * udelay(1) will be enough to fix that.
+ */
+
+ /*
+ * Don't write to this register if the IE state is 0 as it can
+ * cause deadlock.
+ */
+ if (omap->iestate)
+ omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate);
+}
+
+static int omap_i2c_reset(struct omap_i2c_dev *omap)
+{
+ unsigned long timeout;
+ u16 sysc;
+
+ if (omap->rev >= OMAP_I2C_OMAP1_REV_2) {
+ sysc = omap_i2c_read_reg(omap, OMAP_I2C_SYSC_REG);
+
+ /* Disable I2C controller before soft reset */
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG,
+ omap_i2c_read_reg(omap, OMAP_I2C_CON_REG) &
+ ~(OMAP_I2C_CON_EN));
+
+ omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
+ /* For some reason we need to set the EN bit before the
+ * reset done bit gets set. */
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(omap, OMAP_I2C_SYSS_REG) &
+ SYSS_RESETDONE_MASK)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(omap->dev, "timeout waiting "
+ "for controller reset\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ /* SYSC register is cleared by the reset; rewrite it */
+ omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, sysc);
+
+ if (omap->rev > OMAP_I2C_REV_ON_3430_3530) {
+ /* Schedule I2C-bus monitoring on the next transfer */
+ omap->bb_valid = 0;
+ }
+ }
+
+ return 0;
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *omap)
+{
+ u16 psc = 0, scll = 0, sclh = 0;
+ u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
+ unsigned long fclk_rate = 12000000;
+ unsigned long internal_clk = 0;
+ struct clk *fclk;
+ int error;
+
+ if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) {
+ /*
+ * Enabling all wakup sources to stop I2C freezing on
+ * WFI instruction.
+ * REVISIT: Some wkup sources might not be needed.
+ */
+ omap->westate = OMAP_I2C_WE_ALL;
+ }
+
+ if (omap->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
+ /*
+ * The I2C functional clock is the armxor_ck, so there's
+ * no need to get "armxor_ck" separately. Now, if OMAP2420
+ * always returns 12MHz for the functional clock, we can
+ * do this bit unconditionally.
+ */
+ fclk = clk_get(omap->dev, "fck");
+ if (IS_ERR(fclk)) {
+ error = PTR_ERR(fclk);
+ dev_err(omap->dev, "could not get fck: %i\n", error);
+
+ return error;
+ }
+
+ fclk_rate = clk_get_rate(fclk);
+ clk_put(fclk);
+
+ /* TRM for 5912 says the I2C clock must be prescaled to be
+ * between 7 - 12 MHz. The XOR input clock is typically
+ * 12, 13 or 19.2 MHz. So we should have code that produces:
+ *
+ * XOR MHz Divider Prescaler
+ * 12 1 0
+ * 13 2 1
+ * 19.2 2 1
+ */
+ if (fclk_rate > 12000000)
+ psc = fclk_rate / 12000000;
+ }
+
+ if (!(omap->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
+
+ /*
+ * HSI2C controller internal clk rate should be 19.2 Mhz for
+ * HS and for all modes on 2430. On 34xx we can use lower rate
+ * to get longer filter period for better noise suppression.
+ * The filter is iclk (fclk for HS) period.
+ */
+ if (omap->speed > 400 ||
+ omap->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
+ internal_clk = 19200;
+ else if (omap->speed > 100)
+ internal_clk = 9600;
+ else
+ internal_clk = 4000;
+ fclk = clk_get(omap->dev, "fck");
+ if (IS_ERR(fclk)) {
+ error = PTR_ERR(fclk);
+ dev_err(omap->dev, "could not get fck: %i\n", error);
+
+ return error;
+ }
+ fclk_rate = clk_get_rate(fclk) / 1000;
+ clk_put(fclk);
+
+ /* Compute prescaler divisor */
+ psc = fclk_rate / internal_clk;
+ psc = psc - 1;
+
+ /* If configured for High Speed */
+ if (omap->speed > 400) {
+ unsigned long scl;
+
+ /* For first phase of HS mode */
+ scl = internal_clk / 400;
+ fsscll = scl - (scl / 3) - 7;
+ fssclh = (scl / 3) - 5;
+
+ /* For second phase of HS mode */
+ scl = fclk_rate / omap->speed;
+ hsscll = scl - (scl / 3) - 7;
+ hssclh = (scl / 3) - 5;
+ } else if (omap->speed > 100) {
+ unsigned long scl;
+
+ /* Fast mode */
+ scl = internal_clk / omap->speed;
+ fsscll = scl - (scl / 3) - 7;
+ fssclh = (scl / 3) - 5;
+ } else {
+ /* Standard mode */
+ fsscll = internal_clk / (omap->speed * 2) - 7;
+ fssclh = internal_clk / (omap->speed * 2) - 5;
+ }
+ scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+ sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+ } else {
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+ scll = fclk_rate / (omap->speed * 2) - 7 + psc;
+ sclh = fclk_rate / (omap->speed * 2) - 7 + psc;
+ }
+
+ omap->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL) | ((omap->fifo_size) ?
+ (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
+
+ omap->pscstate = psc;
+ omap->scllstate = scll;
+ omap->sclhstate = sclh;
+
+ if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) {
+ /* Not implemented */
+ omap->bb_valid = 1;
+ }
+
+ __omap_i2c_init(omap);
+
+ return 0;
+}
+
+/*
+ * Try bus recovery, but only if SDA is actually low.
+ */
+static int omap_i2c_recover_bus(struct omap_i2c_dev *omap)
+{
+ u16 systest;
+
+ systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG);
+ if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
+ (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC))
+ return 0; /* bus seems to already be fine */
+ if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC))
+ return -EBUSY; /* recovery would not fix SCL */
+ return i2c_recover_bus(&omap->adapter);
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (time_after(jiffies, timeout))
+ return omap_i2c_recover_bus(omap);
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Wait while BB-bit doesn't reflect the I2C bus state
+ *
+ * In a multimaster environment, after IP software reset, BB-bit value doesn't
+ * correspond to the current bus state. It may happen what BB-bit will be 0,
+ * while the bus is busy due to another I2C master activity.
+ * Here are BB-bit values after reset:
+ * SDA SCL BB NOTES
+ * 0 0 0 1, 2
+ * 1 0 0 1, 2
+ * 0 1 1
+ * 1 1 0 3
+ * Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START)
+ * combinations on the bus, it set BB-bit to 1.
+ * If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus,
+ * it set BB-bit to 0 and BF to 1.
+ * BB and BF bits correctly tracks the bus state while IP is suspended
+ * BB bit became valid on the next FCLK clock after CON_EN bit set
+ *
+ * NOTES:
+ * 1. Any transfer started when BB=0 and bus is busy wouldn't be
+ * completed by IP and results in controller timeout.
+ * 2. Any transfer started when BB=0 and SCL=0 results in IP
+ * starting to drive SDA low. In that case IP corrupt data
+ * on the bus.
+ * 3. Any transfer started in the middle of another master's transfer
+ * results in unpredictable results and data corruption
+ */
+static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap)
+{
+ unsigned long bus_free_timeout = 0;
+ unsigned long timeout;
+ int bus_free = 0;
+ u16 stat, systest;
+
+ if (omap->bb_valid)
+ return 0;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (1) {
+ stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
+ /*
+ * We will see BB or BF event in a case IP had detected any
+ * activity on the I2C bus. Now IP correctly tracks the bus
+ * state. BB-bit value is valid.
+ */
+ if (stat & (OMAP_I2C_STAT_BB | OMAP_I2C_STAT_BF))
+ break;
+
+ /*
+ * Otherwise, we must look signals on the bus to make
+ * the right decision.
+ */
+ systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG);
+ if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
+ (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
+ if (!bus_free) {
+ bus_free_timeout = jiffies +
+ OMAP_I2C_BUS_FREE_TIMEOUT;
+ bus_free = 1;
+ }
+
+ /*
+ * SDA and SCL lines was high for 10 ms without bus
+ * activity detected. The bus is free. Consider
+ * BB-bit value is valid.
+ */
+ if (time_after(jiffies, bus_free_timeout))
+ break;
+ } else {
+ bus_free = 0;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ /*
+ * SDA or SCL were low for the entire timeout without
+ * any activity detected. Most likely, a slave is
+ * locking up the bus with no master driving the clock.
+ */
+ dev_warn(omap->dev, "timeout waiting for bus ready\n");
+ return omap_i2c_recover_bus(omap);
+ }
+
+ msleep(1);
+ }
+
+ omap->bb_valid = 1;
+ return 0;
+}
+
+static void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx)
+{
+ u16 buf;
+
+ if (omap->flags & OMAP_I2C_FLAG_NO_FIFO)
+ return;
+
+ /*
+ * Set up notification threshold based on message size. We're doing
+ * this to try and avoid draining feature as much as possible. Whenever
+ * we have big messages to transfer (bigger than our total fifo size)
+ * then we might use draining feature to transfer the remaining bytes.
+ */
+
+ omap->threshold = clamp(size, (u8) 1, omap->fifo_size);
+
+ buf = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG);
+
+ if (is_rx) {
+ /* Clear RX Threshold */
+ buf &= ~(0x3f << 8);
+ buf |= ((omap->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR;
+ } else {
+ /* Clear TX Threshold */
+ buf &= ~0x3f;
+ buf |= (omap->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR;
+ }
+
+ omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, buf);
+
+ if (omap->rev < OMAP_I2C_REV_ON_3630)
+ omap->b_hw = 1; /* Enable hardware fixes */
+
+ /* calculate wakeup latency constraint for MPU */
+ if (omap->set_mpu_wkup_lat != NULL)
+ omap->latency = (1000000 * omap->threshold) /
+ (1000 * omap->speed / 8);
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
+ unsigned long timeout;
+ u16 w;
+
+ dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ omap->receiver = !!(msg->flags & I2C_M_RD);
+ omap_i2c_resize_fifo(omap, msg->len, omap->receiver);
+
+ omap_i2c_write_reg(omap, OMAP_I2C_SA_REG, msg->addr);
+
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ omap->buf = msg->buf;
+ omap->buf_len = msg->len;
+
+ /* make sure writes to omap->buf_len are ordered */
+ barrier();
+
+ omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len);
+
+ /* Clear the FIFO Buffers */
+ w = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG);
+ w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+ omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w);
+
+ reinit_completion(&omap->cmd_complete);
+ omap->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+ /* High speed configuration */
+ if (omap->speed > 400)
+ w |= OMAP_I2C_CON_OPMODE_HS;
+
+ if (msg->flags & I2C_M_STOP)
+ stop = 1;
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+
+ if (!omap->b_hw && stop)
+ w |= OMAP_I2C_CON_STP;
+ /*
+ * NOTE: STAT_BB bit could became 1 here if another master occupy
+ * the bus. IP successfully complete transfer when the bus will be
+ * free again (BB reset to 0).
+ */
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
+
+ /*
+ * Don't write stt and stp together on some hardware.
+ */
+ if (omap->b_hw && stop) {
+ unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
+ u16 con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
+ while (con & OMAP_I2C_CON_STT) {
+ con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
+
+ /* Let the user know if i2c is in a bad state */
+ if (time_after(jiffies, delay)) {
+ dev_err(omap->dev, "controller timed out "
+ "waiting for start condition to finish\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ w |= OMAP_I2C_CON_STP;
+ w &= ~OMAP_I2C_CON_STT;
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
+ }
+
+ /*
+ * REVISIT: We should abort the transfer on signals, but the bus goes
+ * into arbitration and we're currently unable to recover from it.
+ */
+ timeout = wait_for_completion_timeout(&omap->cmd_complete,
+ OMAP_I2C_TIMEOUT);
+ if (timeout == 0) {
+ dev_err(omap->dev, "controller timed out\n");
+ omap_i2c_reset(omap);
+ __omap_i2c_init(omap);
+ return -ETIMEDOUT;
+ }
+
+ if (likely(!omap->cmd_err))
+ return 0;
+
+ /* We have an error */
+ if (omap->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) {
+ omap_i2c_reset(omap);
+ __omap_i2c_init(omap);
+ return -EIO;
+ }
+
+ if (omap->cmd_err & OMAP_I2C_STAT_AL)
+ return -EAGAIN;
+
+ if (omap->cmd_err & OMAP_I2C_STAT_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+
+ w = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w);
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *omap = i2c_get_adapdata(adap);
+ int i;
+ int r;
+
+ r = pm_runtime_get_sync(omap->dev);
+ if (r < 0)
+ goto out;
+
+ r = omap_i2c_wait_for_bb_valid(omap);
+ if (r < 0)
+ goto out;
+
+ r = omap_i2c_wait_for_bb(omap);
+ if (r < 0)
+ goto out;
+
+ if (omap->set_mpu_wkup_lat != NULL)
+ omap->set_mpu_wkup_lat(omap->dev, omap->latency);
+
+ for (i = 0; i < num; i++) {
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (r == 0)
+ r = num;
+
+ omap_i2c_wait_for_bb(omap);
+
+ if (omap->set_mpu_wkup_lat != NULL)
+ omap->set_mpu_wkup_lat(omap->dev, -1);
+
+out:
+ pm_runtime_mark_last_busy(omap->dev);
+ pm_runtime_put_autosuspend(omap->dev);
+ return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *omap, u16 err)
+{
+ omap->cmd_err |= err;
+ complete(&omap->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *omap, u16 stat)
+{
+ omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, stat);
+}
+
+static inline void i2c_omap_errata_i207(struct omap_i2c_dev *omap, u16 stat)
+{
+ /*
+ * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
+ * Not applicable for OMAP4.
+ * Under certain rare conditions, RDR could be set again
+ * when the bus is busy, then ignore the interrupt and
+ * clear the interrupt.
+ */
+ if (stat & OMAP_I2C_STAT_RDR) {
+ /* Step 1: If RDR is set, clear it */
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR);
+
+ /* Step 2: */
+ if (!(omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG)
+ & OMAP_I2C_STAT_BB)) {
+
+ /* Step 3: */
+ if (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG)
+ & OMAP_I2C_STAT_RDR) {
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR);
+ dev_dbg(omap->dev, "RDR when bus is busy.\n");
+ }
+
+ }
+ }
+}
+
+/* rev1 devices are apparently only on some 15xx */
+#ifdef CONFIG_ARCH_OMAP15XX
+
+static irqreturn_t
+omap_i2c_omap1_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *omap = dev_id;
+ u16 iv, w;
+
+ if (pm_runtime_suspended(omap->dev))
+ return IRQ_NONE;
+
+ iv = omap_i2c_read_reg(omap, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x00: /* None */
+ break;
+ case 0x01: /* Arbitration lost */
+ dev_err(omap->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_AL);
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ break;
+ case 0x03: /* Register access ready */
+ omap_i2c_complete_cmd(omap, 0);
+ break;
+ case 0x04: /* Receive data ready */
+ if (omap->buf_len) {
+ w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG);
+ *omap->buf++ = w;
+ omap->buf_len--;
+ if (omap->buf_len) {
+ *omap->buf++ = w >> 8;
+ omap->buf_len--;
+ }
+ } else
+ dev_err(omap->dev, "RRDY IRQ while no data requested\n");
+ break;
+ case 0x05: /* Transmit data ready */
+ if (omap->buf_len) {
+ w = *omap->buf++;
+ omap->buf_len--;
+ if (omap->buf_len) {
+ w |= *omap->buf++ << 8;
+ omap->buf_len--;
+ }
+ omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w);
+ } else
+ dev_err(omap->dev, "XRDY IRQ while no data to send\n");
+ break;
+ default:
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+#else
+#define omap_i2c_omap1_isr NULL
+#endif
+
+/*
+ * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
+ * data to DATA_REG. Otherwise some data bytes can be lost while transferring
+ * them from the memory to the I2C interface.
+ */
+static int errata_omap3_i462(struct omap_i2c_dev *omap)
+{
+ unsigned long timeout = 10000;
+ u16 stat;
+
+ do {
+ stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
+ if (stat & OMAP_I2C_STAT_XUDF)
+ break;
+
+ if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_XRDY |
+ OMAP_I2C_STAT_XDR));
+ if (stat & OMAP_I2C_STAT_NACK) {
+ omap->cmd_err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK);
+ }
+
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(omap->dev, "Arbitration lost\n");
+ omap->cmd_err |= OMAP_I2C_STAT_AL;
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL);
+ }
+
+ return -EIO;
+ }
+
+ cpu_relax();
+ } while (--timeout);
+
+ if (!timeout) {
+ dev_err(omap->dev, "timeout waiting on XUDF bit\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+static void omap_i2c_receive_data(struct omap_i2c_dev *omap, u8 num_bytes,
+ bool is_rdr)
+{
+ u16 w;
+
+ while (num_bytes--) {
+ w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG);
+ *omap->buf++ = w;
+ omap->buf_len--;
+
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+ *omap->buf++ = w >> 8;
+ omap->buf_len--;
+ }
+ }
+}
+
+static int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes,
+ bool is_xdr)
+{
+ u16 w;
+
+ while (num_bytes--) {
+ w = *omap->buf++;
+ omap->buf_len--;
+
+ /*
+ * Data reg in 2430, omap3 and
+ * omap4 is 8 bit wide
+ */
+ if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) {
+ w |= *omap->buf++ << 8;
+ omap->buf_len--;
+ }
+
+ if (omap->errata & I2C_OMAP_ERRATA_I462) {
+ int ret;
+
+ ret = errata_omap3_i462(omap);
+ if (ret < 0)
+ return ret;
+ }
+
+ omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w);
+ }
+
+ return 0;
+}
+
+static irqreturn_t
+omap_i2c_isr(int irq, void *dev_id)
+{
+ struct omap_i2c_dev *omap = dev_id;
+ irqreturn_t ret = IRQ_HANDLED;
+ u16 mask;
+ u16 stat;
+
+ stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
+ mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
+
+ if (stat & mask)
+ ret = IRQ_WAKE_THREAD;
+
+ return ret;
+}
+
+static irqreturn_t
+omap_i2c_isr_thread(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *omap = dev_id;
+ u16 bits;
+ u16 stat;
+ int err = 0, count = 0;
+
+ do {
+ bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
+ stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
+ stat &= bits;
+
+ /* If we're in receiver mode, ignore XDR/XRDY */
+ if (omap->receiver)
+ stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY);
+ else
+ stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY);
+
+ if (!stat) {
+ /* my work here is done */
+ goto out;
+ }
+
+ dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat);
+ if (count++ == 100) {
+ dev_warn(omap->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ if (stat & OMAP_I2C_STAT_NACK) {
+ err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK);
+ }
+
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(omap->dev, "Arbitration lost\n");
+ err |= OMAP_I2C_STAT_AL;
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL);
+ }
+
+ /*
+ * ProDB0017052: Clear ARDY bit twice
+ */
+ if (stat & OMAP_I2C_STAT_ARDY)
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ARDY);
+
+ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+ OMAP_I2C_STAT_AL)) {
+ omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_RRDY |
+ OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY |
+ OMAP_I2C_STAT_XDR |
+ OMAP_I2C_STAT_ARDY));
+ break;
+ }
+
+ if (stat & OMAP_I2C_STAT_RDR) {
+ u8 num_bytes = 1;
+
+ if (omap->fifo_size)
+ num_bytes = omap->buf_len;
+
+ if (omap->errata & I2C_OMAP_ERRATA_I207) {
+ i2c_omap_errata_i207(omap, stat);
+ num_bytes = (omap_i2c_read_reg(omap,
+ OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F;
+ }
+
+ omap_i2c_receive_data(omap, num_bytes, true);
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR);
+ continue;
+ }
+
+ if (stat & OMAP_I2C_STAT_RRDY) {
+ u8 num_bytes = 1;
+
+ if (omap->threshold)
+ num_bytes = omap->threshold;
+
+ omap_i2c_receive_data(omap, num_bytes, false);
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RRDY);
+ continue;
+ }
+
+ if (stat & OMAP_I2C_STAT_XDR) {
+ u8 num_bytes = 1;
+ int ret;
+
+ if (omap->fifo_size)
+ num_bytes = omap->buf_len;
+
+ ret = omap_i2c_transmit_data(omap, num_bytes, true);
+ if (ret < 0)
+ break;
+
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XDR);
+ continue;
+ }
+
+ if (stat & OMAP_I2C_STAT_XRDY) {
+ u8 num_bytes = 1;
+ int ret;
+
+ if (omap->threshold)
+ num_bytes = omap->threshold;
+
+ ret = omap_i2c_transmit_data(omap, num_bytes, false);
+ if (ret < 0)
+ break;
+
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XRDY);
+ continue;
+ }
+
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err(omap->dev, "Receive overrun\n");
+ err |= OMAP_I2C_STAT_ROVR;
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ROVR);
+ break;
+ }
+
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err(omap->dev, "Transmit underflow\n");
+ err |= OMAP_I2C_STAT_XUDF;
+ omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XUDF);
+ break;
+ }
+ } while (stat);
+
+ omap_i2c_complete_cmd(omap, err);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static const struct i2c_adapter_quirks omap_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+#ifdef CONFIG_OF
+static struct omap_i2c_bus_platform_data omap2420_pdata = {
+ .rev = OMAP_I2C_IP_VERSION_1,
+ .flags = OMAP_I2C_FLAG_NO_FIFO |
+ OMAP_I2C_FLAG_SIMPLE_CLOCK |
+ OMAP_I2C_FLAG_16BIT_DATA_REG |
+ OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_i2c_bus_platform_data omap2430_pdata = {
+ .rev = OMAP_I2C_IP_VERSION_1,
+ .flags = OMAP_I2C_FLAG_BUS_SHIFT_2 |
+ OMAP_I2C_FLAG_FORCE_19200_INT_CLK,
+};
+
+static struct omap_i2c_bus_platform_data omap3_pdata = {
+ .rev = OMAP_I2C_IP_VERSION_1,
+ .flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_i2c_bus_platform_data omap4_pdata = {
+ .rev = OMAP_I2C_IP_VERSION_2,
+};
+
+static const struct of_device_id omap_i2c_of_match[] = {
+ {
+ .compatible = "ti,omap4-i2c",
+ .data = &omap4_pdata,
+ },
+ {
+ .compatible = "ti,omap3-i2c",
+ .data = &omap3_pdata,
+ },
+ {
+ .compatible = "ti,omap2430-i2c",
+ .data = &omap2430_pdata,
+ },
+ {
+ .compatible = "ti,omap2420-i2c",
+ .data = &omap2420_pdata,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
+#endif
+
+#define OMAP_I2C_SCHEME(rev) ((rev & 0xc000) >> 14)
+
+#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4)
+#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf)
+
+#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7)
+#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f)
+#define OMAP_I2C_SCHEME_0 0
+#define OMAP_I2C_SCHEME_1 1
+
+static int omap_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ u32 reg;
+
+ reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+
+ return reg & OMAP_I2C_SYSTEST_SCL_I_FUNC;
+}
+
+static int omap_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ u32 reg;
+
+ reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+
+ return reg & OMAP_I2C_SYSTEST_SDA_I_FUNC;
+}
+
+static void omap_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ u32 reg;
+
+ reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ if (val)
+ reg |= OMAP_I2C_SYSTEST_SCL_O;
+ else
+ reg &= ~OMAP_I2C_SYSTEST_SCL_O;
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
+}
+
+static void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ u32 reg;
+
+ reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ /* enable test mode */
+ reg |= OMAP_I2C_SYSTEST_ST_EN;
+ /* select SDA/SCL IO mode */
+ reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT;
+ /* set SCL to high-impedance state (reset value is 0) */
+ reg |= OMAP_I2C_SYSTEST_SCL_O;
+ /* set SDA to high-impedance state (reset value is 0) */
+ reg |= OMAP_I2C_SYSTEST_SDA_O;
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
+}
+
+static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ u32 reg;
+
+ reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ /* restore reset values */
+ reg &= ~OMAP_I2C_SYSTEST_ST_EN;
+ reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK;
+ reg &= ~OMAP_I2C_SYSTEST_SCL_O;
+ reg &= ~OMAP_I2C_SYSTEST_SDA_O;
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
+}
+
+static struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = {
+ .get_scl = omap_i2c_get_scl,
+ .get_sda = omap_i2c_get_sda,
+ .set_scl = omap_i2c_set_scl,
+ .prepare_recovery = omap_i2c_prepare_recovery,
+ .unprepare_recovery = omap_i2c_unprepare_recovery,
+ .recover_bus = i2c_generic_scl_recovery,
+};
+
+static int
+omap_i2c_probe(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *omap;
+ struct i2c_adapter *adap;
+ struct resource *mem;
+ const struct omap_i2c_bus_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct device_node *node = pdev->dev.of_node;
+ const struct of_device_id *match;
+ int irq;
+ int r;
+ u32 rev;
+ u16 minor, major;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return irq;
+ }
+
+ omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!omap)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ omap->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(omap->base))
+ return PTR_ERR(omap->base);
+
+ match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
+ if (match) {
+ u32 freq = 100000; /* default to 100000 Hz */
+
+ pdata = match->data;
+ omap->flags = pdata->flags;
+
+ of_property_read_u32(node, "clock-frequency", &freq);
+ /* convert DT freq value in Hz into kHz for speed */
+ omap->speed = freq / 1000;
+ } else if (pdata != NULL) {
+ omap->speed = pdata->clkrate;
+ omap->flags = pdata->flags;
+ omap->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
+ }
+
+ omap->dev = &pdev->dev;
+ omap->irq = irq;
+
+ platform_set_drvdata(pdev, omap);
+ init_completion(&omap->cmd_complete);
+
+ omap->reg_shift = (omap->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
+
+ pm_runtime_enable(omap->dev);
+ pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(omap->dev);
+
+ r = pm_runtime_get_sync(omap->dev);
+ if (r < 0)
+ goto err_free_mem;
+
+ /*
+ * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2.
+ * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset.
+ * Also since the omap_i2c_read_reg uses reg_map_ip_* a
+ * readw_relaxed is done.
+ */
+ rev = readw_relaxed(omap->base + 0x04);
+
+ omap->scheme = OMAP_I2C_SCHEME(rev);
+ switch (omap->scheme) {
+ case OMAP_I2C_SCHEME_0:
+ omap->regs = (u8 *)reg_map_ip_v1;
+ omap->rev = omap_i2c_read_reg(omap, OMAP_I2C_REV_REG);
+ minor = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev);
+ major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev);
+ break;
+ case OMAP_I2C_SCHEME_1:
+ /* FALLTHROUGH */
+ default:
+ omap->regs = (u8 *)reg_map_ip_v2;
+ rev = (rev << 16) |
+ omap_i2c_read_reg(omap, OMAP_I2C_IP_V2_REVNB_LO);
+ minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev);
+ major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev);
+ omap->rev = rev;
+ }
+
+ omap->errata = 0;
+
+ if (omap->rev >= OMAP_I2C_REV_ON_2430 &&
+ omap->rev < OMAP_I2C_REV_ON_4430_PLUS)
+ omap->errata |= I2C_OMAP_ERRATA_I207;
+
+ if (omap->rev <= OMAP_I2C_REV_ON_3430_3530)
+ omap->errata |= I2C_OMAP_ERRATA_I462;
+
+ if (!(omap->flags & OMAP_I2C_FLAG_NO_FIFO)) {
+ u16 s;
+
+ /* Set up the fifo size - Get total size */
+ s = (omap_i2c_read_reg(omap, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
+ omap->fifo_size = 0x8 << s;
+
+ /*
+ * Set up notification threshold as half the total available
+ * size. This is to ensure that we can handle the status on int
+ * call back latencies.
+ */
+
+ omap->fifo_size = (omap->fifo_size / 2);
+
+ if (omap->rev < OMAP_I2C_REV_ON_3630)
+ omap->b_hw = 1; /* Enable hardware fixes */
+
+ /* calculate wakeup latency constraint for MPU */
+ if (omap->set_mpu_wkup_lat != NULL)
+ omap->latency = (1000000 * omap->fifo_size) /
+ (1000 * omap->speed / 8);
+ }
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_init(omap);
+
+ if (omap->rev < OMAP_I2C_OMAP1_REV_2)
+ r = devm_request_irq(&pdev->dev, omap->irq, omap_i2c_omap1_isr,
+ IRQF_NO_SUSPEND, pdev->name, omap);
+ else
+ r = devm_request_threaded_irq(&pdev->dev, omap->irq,
+ omap_i2c_isr, omap_i2c_isr_thread,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ pdev->name, omap);
+
+ if (r) {
+ dev_err(omap->dev, "failure requesting irq %i\n", omap->irq);
+ goto err_unuse_clocks;
+ }
+
+ adap = &omap->adapter;
+ i2c_set_adapdata(adap, omap);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_DEPRECATED;
+ strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->quirks = &omap_i2c_quirks;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+ adap->bus_recovery_info = &omap_i2c_bus_recovery_info;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r)
+ goto err_unuse_clocks;
+
+ dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr,
+ major, minor, omap->speed);
+
+ pm_runtime_mark_last_busy(omap->dev);
+ pm_runtime_put_autosuspend(omap->dev);
+
+ return 0;
+
+err_unuse_clocks:
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
+ pm_runtime_dont_use_autosuspend(omap->dev);
+ pm_runtime_put_sync(omap->dev);
+ pm_runtime_disable(&pdev->dev);
+err_free_mem:
+
+ return r;
+}
+
+static int omap_i2c_remove(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *omap = platform_get_drvdata(pdev);
+ int ret;
+
+ i2c_del_adapter(&omap->adapter);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static int __maybe_unused omap_i2c_runtime_suspend(struct device *dev)
+{
+ struct omap_i2c_dev *omap = dev_get_drvdata(dev);
+
+ omap->iestate = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
+
+ if (omap->scheme == OMAP_I2C_SCHEME_0)
+ omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, 0);
+ else
+ omap_i2c_write_reg(omap, OMAP_I2C_IP_V2_IRQENABLE_CLR,
+ OMAP_I2C_IP_V2_INTERRUPTS_MASK);
+
+ if (omap->rev < OMAP_I2C_OMAP1_REV_2) {
+ omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); /* Read clears */
+ } else {
+ omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, omap->iestate);
+
+ /* Flush posted write */
+ omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
+ }
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int __maybe_unused omap_i2c_runtime_resume(struct device *dev)
+{
+ struct omap_i2c_dev *omap = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_default_state(dev);
+
+ if (!omap->regs)
+ return 0;
+
+ __omap_i2c_init(omap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops omap_i2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
+ omap_i2c_runtime_resume, NULL)
+};
+
+static struct platform_driver omap_i2c_driver = {
+ .probe = omap_i2c_probe,
+ .remove = omap_i2c_remove,
+ .driver = {
+ .name = "omap_i2c",
+ .pm = &omap_i2c_pm_ops,
+ .of_match_table = of_match_ptr(omap_i2c_of_match),
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+ return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap_i2c");
diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
new file mode 100644
index 000000000..dc2a23f4f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-opal.c
@@ -0,0 +1,290 @@
+/*
+ * IBM OPAL I2C driver
+ * Copyright (C) 2014 IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <asm/firmware.h>
+#include <asm/opal.h>
+
+static int i2c_opal_translate_error(int rc)
+{
+ switch (rc) {
+ case OPAL_NO_MEM:
+ return -ENOMEM;
+ case OPAL_PARAMETER:
+ return -EINVAL;
+ case OPAL_I2C_ARBT_LOST:
+ return -EAGAIN;
+ case OPAL_I2C_TIMEOUT:
+ return -ETIMEDOUT;
+ case OPAL_I2C_NACK_RCVD:
+ return -ENXIO;
+ case OPAL_I2C_STOP_ERR:
+ return -EBUSY;
+ default:
+ return -EIO;
+ }
+}
+
+static int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req)
+{
+ struct opal_msg msg;
+ int token, rc;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("Failed to get the async token\n");
+
+ return token;
+ }
+
+ rc = opal_i2c_request(token, bus_id, req);
+ if (rc != OPAL_ASYNC_COMPLETION) {
+ rc = i2c_opal_translate_error(rc);
+ goto exit;
+ }
+
+ rc = opal_async_wait_response(token, &msg);
+ if (rc)
+ goto exit;
+
+ rc = opal_get_async_rc(msg);
+ if (rc != OPAL_SUCCESS) {
+ rc = i2c_opal_translate_error(rc);
+ goto exit;
+ }
+
+exit:
+ opal_async_release_token(token);
+ return rc;
+}
+
+static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ unsigned long opal_id = (unsigned long)adap->algo_data;
+ struct opal_i2c_request req;
+ int rc, i;
+
+ /* We only support fairly simple combinations here of one
+ * or two messages
+ */
+ memset(&req, 0, sizeof(req));
+ switch(num) {
+ case 1:
+ req.type = (msgs[0].flags & I2C_M_RD) ?
+ OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
+ req.addr = cpu_to_be16(msgs[0].addr);
+ req.size = cpu_to_be32(msgs[0].len);
+ req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
+ break;
+ case 2:
+ req.type = (msgs[1].flags & I2C_M_RD) ?
+ OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
+ req.addr = cpu_to_be16(msgs[0].addr);
+ req.subaddr_sz = msgs[0].len;
+ for (i = 0; i < msgs[0].len; i++)
+ req.subaddr = (req.subaddr << 8) | msgs[0].buf[i];
+ req.subaddr = cpu_to_be32(req.subaddr);
+ req.size = cpu_to_be32(msgs[1].len);
+ req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf));
+ break;
+ }
+
+ rc = i2c_opal_send_request(opal_id, &req);
+ if (rc)
+ return rc;
+
+ return num;
+}
+
+static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ unsigned long opal_id = (unsigned long)adap->algo_data;
+ struct opal_i2c_request req;
+ u8 local[2];
+ int rc;
+
+ memset(&req, 0, sizeof(req));
+
+ req.addr = cpu_to_be16(addr);
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ req.buffer_ra = cpu_to_be64(__pa(&data->byte));
+ req.size = cpu_to_be32(1);
+ /* Fall through */
+ case I2C_SMBUS_QUICK:
+ req.type = (read_write == I2C_SMBUS_READ) ?
+ OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ req.buffer_ra = cpu_to_be64(__pa(&data->byte));
+ req.size = cpu_to_be32(1);
+ req.subaddr = cpu_to_be32(command);
+ req.subaddr_sz = 1;
+ req.type = (read_write == I2C_SMBUS_READ) ?
+ OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (!read_write) {
+ local[0] = data->word & 0xff;
+ local[1] = (data->word >> 8) & 0xff;
+ }
+ req.buffer_ra = cpu_to_be64(__pa(local));
+ req.size = cpu_to_be32(2);
+ req.subaddr = cpu_to_be32(command);
+ req.subaddr_sz = 1;
+ req.type = (read_write == I2C_SMBUS_READ) ?
+ OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ req.buffer_ra = cpu_to_be64(__pa(&data->block[1]));
+ req.size = cpu_to_be32(data->block[0]);
+ req.subaddr = cpu_to_be32(command);
+ req.subaddr_sz = 1;
+ req.type = (read_write == I2C_SMBUS_READ) ?
+ OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = i2c_opal_send_request(opal_id, &req);
+ if (!rc && read_write && size == I2C_SMBUS_WORD_DATA) {
+ data->word = ((u16)local[1]) << 8;
+ data->word |= local[0];
+ }
+
+ return rc;
+}
+
+static u32 i2c_opal_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm i2c_opal_algo = {
+ .master_xfer = i2c_opal_master_xfer,
+ .smbus_xfer = i2c_opal_smbus_xfer,
+ .functionality = i2c_opal_func,
+};
+
+/*
+ * For two messages, we basically support simple smbus transactions of a
+ * write-then-anything.
+ */
+static const struct i2c_adapter_quirks i2c_opal_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
+ .max_comb_1st_msg_len = 4,
+};
+
+static int i2c_opal_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ const char *pname;
+ u32 opal_id;
+ int rc;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ rc = of_property_read_u32(pdev->dev.of_node, "ibm,opal-id", &opal_id);
+ if (rc) {
+ dev_err(&pdev->dev, "Missing ibm,opal-id property !\n");
+ return -EIO;
+ }
+
+ adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ adapter->algo = &i2c_opal_algo;
+ adapter->algo_data = (void *)(unsigned long)opal_id;
+ adapter->quirks = &i2c_opal_quirks;
+ adapter->dev.parent = &pdev->dev;
+ adapter->dev.of_node = of_node_get(pdev->dev.of_node);
+ pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
+ if (pname)
+ strlcpy(adapter->name, pname, sizeof(adapter->name));
+ else
+ strlcpy(adapter->name, "opal", sizeof(adapter->name));
+
+ platform_set_drvdata(pdev, adapter);
+ rc = i2c_add_adapter(adapter);
+ if (rc)
+ dev_err(&pdev->dev, "Failed to register the i2c adapter\n");
+
+ return rc;
+}
+
+static int i2c_opal_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(adapter);
+
+ return 0;
+}
+
+static const struct of_device_id i2c_opal_of_match[] = {
+ {
+ .compatible = "ibm,opal-i2c",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, i2c_opal_of_match);
+
+static struct platform_driver i2c_opal_driver = {
+ .probe = i2c_opal_probe,
+ .remove = i2c_opal_remove,
+ .driver = {
+ .name = "i2c-opal",
+ .of_match_table = i2c_opal_of_match,
+ },
+};
+
+static int __init i2c_opal_init(void)
+{
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
+ return -ENODEV;
+
+ return platform_driver_register(&i2c_opal_driver);
+}
+module_init(i2c_opal_init);
+
+static void __exit i2c_opal_exit(void)
+{
+ return platform_driver_unregister(&i2c_opal_driver);
+}
+module_exit(i2c_opal_exit);
+
+MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IBM OPAL I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c
new file mode 100644
index 000000000..cf3fcf35f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-owl.c
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Actions Semiconductor Owl SoC's I2C driver
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+/* I2C registers */
+#define OWL_I2C_REG_CTL 0x0000
+#define OWL_I2C_REG_CLKDIV 0x0004
+#define OWL_I2C_REG_STAT 0x0008
+#define OWL_I2C_REG_ADDR 0x000C
+#define OWL_I2C_REG_TXDAT 0x0010
+#define OWL_I2C_REG_RXDAT 0x0014
+#define OWL_I2C_REG_CMD 0x0018
+#define OWL_I2C_REG_FIFOCTL 0x001C
+#define OWL_I2C_REG_FIFOSTAT 0x0020
+#define OWL_I2C_REG_DATCNT 0x0024
+#define OWL_I2C_REG_RCNT 0x0028
+
+/* I2Cx_CTL Bit Mask */
+#define OWL_I2C_CTL_RB BIT(1)
+#define OWL_I2C_CTL_GBCC(x) (((x) & 0x3) << 2)
+#define OWL_I2C_CTL_GBCC_NONE OWL_I2C_CTL_GBCC(0)
+#define OWL_I2C_CTL_GBCC_START OWL_I2C_CTL_GBCC(1)
+#define OWL_I2C_CTL_GBCC_STOP OWL_I2C_CTL_GBCC(2)
+#define OWL_I2C_CTL_GBCC_RSTART OWL_I2C_CTL_GBCC(3)
+#define OWL_I2C_CTL_IRQE BIT(5)
+#define OWL_I2C_CTL_EN BIT(7)
+#define OWL_I2C_CTL_AE BIT(8)
+#define OWL_I2C_CTL_SHSM BIT(10)
+
+#define OWL_I2C_DIV_FACTOR(x) ((x) & 0xff)
+
+/* I2Cx_STAT Bit Mask */
+#define OWL_I2C_STAT_RACK BIT(0)
+#define OWL_I2C_STAT_BEB BIT(1)
+#define OWL_I2C_STAT_IRQP BIT(2)
+#define OWL_I2C_STAT_LAB BIT(3)
+#define OWL_I2C_STAT_STPD BIT(4)
+#define OWL_I2C_STAT_STAD BIT(5)
+#define OWL_I2C_STAT_BBB BIT(6)
+#define OWL_I2C_STAT_TCB BIT(7)
+#define OWL_I2C_STAT_LBST BIT(8)
+#define OWL_I2C_STAT_SAMB BIT(9)
+#define OWL_I2C_STAT_SRGC BIT(10)
+
+/* I2Cx_CMD Bit Mask */
+#define OWL_I2C_CMD_SBE BIT(0)
+#define OWL_I2C_CMD_RBE BIT(4)
+#define OWL_I2C_CMD_DE BIT(8)
+#define OWL_I2C_CMD_NS BIT(9)
+#define OWL_I2C_CMD_SE BIT(10)
+#define OWL_I2C_CMD_MSS BIT(11)
+#define OWL_I2C_CMD_WRS BIT(12)
+#define OWL_I2C_CMD_SECL BIT(15)
+
+#define OWL_I2C_CMD_AS(x) (((x) & 0x7) << 1)
+#define OWL_I2C_CMD_SAS(x) (((x) & 0x7) << 5)
+
+/* I2Cx_FIFOCTL Bit Mask */
+#define OWL_I2C_FIFOCTL_NIB BIT(0)
+#define OWL_I2C_FIFOCTL_RFR BIT(1)
+#define OWL_I2C_FIFOCTL_TFR BIT(2)
+
+/* I2Cc_FIFOSTAT Bit Mask */
+#define OWL_I2C_FIFOSTAT_RNB BIT(1)
+#define OWL_I2C_FIFOSTAT_RFE BIT(2)
+#define OWL_I2C_FIFOSTAT_TFF BIT(5)
+#define OWL_I2C_FIFOSTAT_TFD GENMASK(23, 16)
+#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8)
+
+/* I2C bus timeout */
+#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000)
+
+#define OWL_I2C_MAX_RETRIES 50
+
+#define OWL_I2C_DEF_SPEED_HZ 100000
+#define OWL_I2C_MAX_SPEED_HZ 400000
+
+struct owl_i2c_dev {
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ struct completion msg_complete;
+ struct clk *clk;
+ spinlock_t lock;
+ void __iomem *base;
+ unsigned long clk_rate;
+ u32 bus_freq;
+ u32 msg_ptr;
+ int err;
+};
+
+static void owl_i2c_update_reg(void __iomem *reg, unsigned int val, bool state)
+{
+ unsigned int regval;
+
+ regval = readl(reg);
+
+ if (state)
+ regval |= val;
+ else
+ regval &= ~val;
+
+ writel(regval, reg);
+}
+
+static void owl_i2c_reset(struct owl_i2c_dev *i2c_dev)
+{
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
+ OWL_I2C_CTL_EN, false);
+ mdelay(1);
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
+ OWL_I2C_CTL_EN, true);
+
+ /* Clear status registers */
+ writel(0, i2c_dev->base + OWL_I2C_REG_STAT);
+}
+
+static int owl_i2c_reset_fifo(struct owl_i2c_dev *i2c_dev)
+{
+ unsigned int val, timeout = 0;
+
+ /* Reset FIFO */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
+ OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR,
+ true);
+
+ /* Wait 50ms for FIFO reset complete */
+ do {
+ val = readl(i2c_dev->base + OWL_I2C_REG_FIFOCTL);
+ if (!(val & (OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR)))
+ break;
+ usleep_range(500, 1000);
+ } while (timeout++ < OWL_I2C_MAX_RETRIES);
+
+ if (timeout > OWL_I2C_MAX_RETRIES) {
+ dev_err(&i2c_dev->adap.dev, "FIFO reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev)
+{
+ unsigned int val;
+
+ val = DIV_ROUND_UP(i2c_dev->clk_rate, i2c_dev->bus_freq * 16);
+
+ /* Set clock divider factor */
+ writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
+}
+
+static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+{
+ struct owl_i2c_dev *i2c_dev = _dev;
+ struct i2c_msg *msg = i2c_dev->msg;
+ unsigned long flags;
+ unsigned int stat, fifostat;
+
+ spin_lock_irqsave(&i2c_dev->lock, flags);
+
+ i2c_dev->err = 0;
+
+ /* Handle NACK from slave */
+ fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT);
+ if (fifostat & OWL_I2C_FIFOSTAT_RNB) {
+ i2c_dev->err = -ENXIO;
+ /* Clear NACK error bit by writing "1" */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
+ OWL_I2C_FIFOSTAT_RNB, true);
+ goto stop;
+ }
+
+ /* Handle bus error */
+ stat = readl(i2c_dev->base + OWL_I2C_REG_STAT);
+ if (stat & OWL_I2C_STAT_BEB) {
+ i2c_dev->err = -EIO;
+ /* Clear BUS error bit by writing "1" */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
+ OWL_I2C_STAT_BEB, true);
+ goto stop;
+ }
+
+ /* Handle FIFO read */
+ if (msg->flags & I2C_M_RD) {
+ while ((readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
+ OWL_I2C_FIFOSTAT_RFE) && i2c_dev->msg_ptr < msg->len) {
+ msg->buf[i2c_dev->msg_ptr++] = readl(i2c_dev->base +
+ OWL_I2C_REG_RXDAT);
+ }
+ } else {
+ /* Handle the remaining bytes which were not sent */
+ while (!(readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
+ OWL_I2C_FIFOSTAT_TFF) && i2c_dev->msg_ptr < msg->len) {
+ writel(msg->buf[i2c_dev->msg_ptr++],
+ i2c_dev->base + OWL_I2C_REG_TXDAT);
+ }
+ }
+
+stop:
+ /* Clear pending interrupts */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
+ OWL_I2C_STAT_IRQP, true);
+
+ complete_all(&i2c_dev->msg_complete);
+ spin_unlock_irqrestore(&i2c_dev->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static u32 owl_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
+{
+ struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ unsigned long timeout;
+
+ /* Check for Bus busy */
+ timeout = jiffies + OWL_I2C_TIMEOUT;
+ while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(&adap->dev, "Bus busy timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ struct i2c_msg *msg;
+ unsigned long time_left, flags;
+ unsigned int i2c_cmd, val;
+ unsigned int addr;
+ int ret, idx;
+
+ spin_lock_irqsave(&i2c_dev->lock, flags);
+
+ /* Reset I2C controller */
+ owl_i2c_reset(i2c_dev);
+
+ /* Set bus frequency */
+ owl_i2c_set_freq(i2c_dev);
+
+ /*
+ * Spinlock should be released before calling reset FIFO and
+ * bus busy check since those functions may sleep
+ */
+ spin_unlock_irqrestore(&i2c_dev->lock, flags);
+
+ /* Reset FIFO */
+ ret = owl_i2c_reset_fifo(i2c_dev);
+ if (ret)
+ goto unlocked_err_exit;
+
+ /* Check for bus busy */
+ ret = owl_i2c_check_bus_busy(adap);
+ if (ret)
+ goto unlocked_err_exit;
+
+ spin_lock_irqsave(&i2c_dev->lock, flags);
+
+ /* Check for Arbitration lost */
+ val = readl(i2c_dev->base + OWL_I2C_REG_STAT);
+ if (val & OWL_I2C_STAT_LAB) {
+ val &= ~OWL_I2C_STAT_LAB;
+ writel(val, i2c_dev->base + OWL_I2C_REG_STAT);
+ ret = -EAGAIN;
+ goto err_exit;
+ }
+
+ reinit_completion(&i2c_dev->msg_complete);
+
+ /* Enable I2C controller interrupt */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
+ OWL_I2C_CTL_IRQE, true);
+
+ /*
+ * Select: FIFO enable, Master mode, Stop enable, Data count enable,
+ * Send start bit
+ */
+ i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE |
+ OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE;
+
+ /* Handle repeated start condition */
+ if (num > 1) {
+ /* Set internal address length and enable repeated start */
+ i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) |
+ OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE;
+
+ /* Write slave address */
+ addr = i2c_8bit_addr_from_msg(&msgs[0]);
+ writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT);
+
+ /* Write internal register address */
+ for (idx = 0; idx < msgs[0].len; idx++)
+ writel(msgs[0].buf[idx],
+ i2c_dev->base + OWL_I2C_REG_TXDAT);
+
+ msg = &msgs[1];
+ } else {
+ /* Set address length */
+ i2c_cmd |= OWL_I2C_CMD_AS(1);
+ msg = &msgs[0];
+ }
+
+ i2c_dev->msg = msg;
+ i2c_dev->msg_ptr = 0;
+
+ /* Set data count for the message */
+ writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT);
+
+ addr = i2c_8bit_addr_from_msg(msg);
+ writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT);
+
+ if (!(msg->flags & I2C_M_RD)) {
+ /* Write data to FIFO */
+ for (idx = 0; idx < msg->len; idx++) {
+ /* Check for FIFO full */
+ if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) &
+ OWL_I2C_FIFOSTAT_TFF)
+ break;
+
+ writel(msg->buf[idx],
+ i2c_dev->base + OWL_I2C_REG_TXDAT);
+ }
+
+ i2c_dev->msg_ptr = idx;
+ }
+
+ /* Ignore the NACK if needed */
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
+ OWL_I2C_FIFOCTL_NIB, true);
+ else
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL,
+ OWL_I2C_FIFOCTL_NIB, false);
+
+ /* Start the transfer */
+ writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD);
+
+ spin_unlock_irqrestore(&i2c_dev->lock, flags);
+
+ time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+ adap->timeout);
+
+ spin_lock_irqsave(&i2c_dev->lock, flags);
+ if (time_left == 0) {
+ dev_err(&adap->dev, "Transaction timed out\n");
+ /* Send stop condition and release the bus */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
+ OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
+ true);
+ ret = -ETIMEDOUT;
+ goto err_exit;
+ }
+
+ ret = i2c_dev->err < 0 ? i2c_dev->err : num;
+
+err_exit:
+ spin_unlock_irqrestore(&i2c_dev->lock, flags);
+
+unlocked_err_exit:
+ /* Disable I2C controller */
+ owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
+ OWL_I2C_CTL_EN, false);
+
+ return ret;
+}
+
+static const struct i2c_algorithm owl_i2c_algorithm = {
+ .master_xfer = owl_i2c_master_xfer,
+ .functionality = owl_i2c_func,
+};
+
+static const struct i2c_adapter_quirks owl_i2c_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST,
+ .max_read_len = 240,
+ .max_write_len = 240,
+ .max_comb_1st_msg_len = 6,
+ .max_comb_2nd_msg_len = 240,
+};
+
+static int owl_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct owl_i2c_dev *i2c_dev;
+ struct resource *res;
+ int ret, irq;
+
+ i2c_dev = devm_kzalloc(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(dev, res);
+ if (IS_ERR(i2c_dev->base))
+ return PTR_ERR(i2c_dev->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number\n");
+ return irq;
+ }
+
+ if (of_property_read_u32(dev->of_node, "clock-frequency",
+ &i2c_dev->bus_freq))
+ i2c_dev->bus_freq = OWL_I2C_DEF_SPEED_HZ;
+
+ /* We support only frequencies of 100k and 400k for now */
+ if (i2c_dev->bus_freq != OWL_I2C_DEF_SPEED_HZ &&
+ i2c_dev->bus_freq != OWL_I2C_MAX_SPEED_HZ) {
+ dev_err(dev, "invalid clock-frequency %d\n", i2c_dev->bus_freq);
+ return -EINVAL;
+ }
+
+ i2c_dev->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret)
+ return ret;
+
+ i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk);
+ if (!i2c_dev->clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ ret = -EINVAL;
+ goto disable_clk;
+ }
+
+ init_completion(&i2c_dev->msg_complete);
+ spin_lock_init(&i2c_dev->lock);
+ i2c_dev->adap.owner = THIS_MODULE;
+ i2c_dev->adap.algo = &owl_i2c_algorithm;
+ i2c_dev->adap.timeout = OWL_I2C_TIMEOUT;
+ i2c_dev->adap.quirks = &owl_i2c_quirks;
+ i2c_dev->adap.dev.parent = dev;
+ i2c_dev->adap.dev.of_node = dev->of_node;
+ snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name),
+ "%s", "OWL I2C adapter");
+ i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ ret = devm_request_irq(dev, irq, owl_i2c_interrupt, 0, pdev->name,
+ i2c_dev);
+ if (ret) {
+ dev_err(dev, "failed to request irq %d\n", irq);
+ goto disable_clk;
+ }
+
+ return i2c_add_adapter(&i2c_dev->adap);
+
+disable_clk:
+ clk_disable_unprepare(i2c_dev->clk);
+
+ return ret;
+}
+
+static const struct of_device_id owl_i2c_of_match[] = {
+ { .compatible = "actions,s900-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, owl_i2c_of_match);
+
+static struct platform_driver owl_i2c_driver = {
+ .probe = owl_i2c_probe,
+ .driver = {
+ .name = "owl-i2c",
+ .of_match_table = of_match_ptr(owl_i2c_of_match),
+ },
+};
+module_platform_driver(owl_i2c_driver);
+
+MODULE_AUTHOR("David Liu <liuwei@actions-semi.com>");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_DESCRIPTION("Actions Semiconductor Owl SoC's I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
new file mode 100644
index 000000000..fa41ff799
--- /dev/null
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -0,0 +1,275 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport-light.c I2C bus over parallel port *
+ * ------------------------------------------------------------------------ *
+ Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
+
+ Based on older i2c-velleman.c driver
+ Copyright (C) 1995-2000 Simon G. Vogl
+ With some changes from:
+ Frodo Looijaard <frodol@dds.nl>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ * ------------------------------------------------------------------------ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
+#include <linux/io.h>
+#include "i2c-parport.h"
+
+#define DEFAULT_BASE 0x378
+#define DRVNAME "i2c-parport-light"
+
+static struct platform_device *pdev;
+
+static u16 base;
+module_param_hw(base, ushort, ioport, 0);
+MODULE_PARM_DESC(base, "Base I/O address");
+
+static int irq;
+module_param_hw(irq, int, irq, 0);
+MODULE_PARM_DESC(irq, "IRQ (optional)");
+
+/* ----- Low-level parallel port access ----------------------------------- */
+
+static inline void port_write(unsigned char p, unsigned char d)
+{
+ outb(d, base+p);
+}
+
+static inline unsigned char port_read(unsigned char p)
+{
+ return inb(base+p);
+}
+
+/* ----- Unified line operation functions --------------------------------- */
+
+static inline void line_set(int state, const struct lineop *op)
+{
+ u8 oldval = port_read(op->port);
+
+ /* Touch only the bit(s) needed */
+ if ((op->inverted && !state) || (!op->inverted && state))
+ port_write(op->port, oldval | op->val);
+ else
+ port_write(op->port, oldval & ~op->val);
+}
+
+static inline int line_get(const struct lineop *op)
+{
+ u8 oldval = port_read(op->port);
+
+ return ((op->inverted && (oldval & op->val) != op->val)
+ || (!op->inverted && (oldval & op->val) == op->val));
+}
+
+/* ----- I2C algorithm call-back functions and structures ----------------- */
+
+static void parport_setscl(void *data, int state)
+{
+ line_set(state, &adapter_parm[type].setscl);
+}
+
+static void parport_setsda(void *data, int state)
+{
+ line_set(state, &adapter_parm[type].setsda);
+}
+
+static int parport_getscl(void *data)
+{
+ return line_get(&adapter_parm[type].getscl);
+}
+
+static int parport_getsda(void *data)
+{
+ return line_get(&adapter_parm[type].getsda);
+}
+
+/* Encapsulate the functions above in the correct structure
+ Note that getscl will be set to NULL by the attaching code for adapters
+ that cannot read SCL back */
+static struct i2c_algo_bit_data parport_algo_data = {
+ .setsda = parport_setsda,
+ .setscl = parport_setscl,
+ .getsda = parport_getsda,
+ .getscl = parport_getscl,
+ .udelay = 50,
+ .timeout = HZ,
+};
+
+/* ----- Driver registration ---------------------------------------------- */
+
+static struct i2c_adapter parport_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON,
+ .algo_data = &parport_algo_data,
+ .name = "Parallel port adapter (light)",
+};
+
+/* SMBus alert support */
+static struct i2c_smbus_alert_setup alert_data = {
+};
+static struct i2c_client *ara;
+static struct lineop parport_ctrl_irq = {
+ .val = (1 << 4),
+ .port = PORT_CTRL,
+};
+
+static int i2c_parport_probe(struct platform_device *pdev)
+{
+ int err;
+
+ /* Reset hardware to a sane state (SCL and SDA high) */
+ parport_setsda(NULL, 1);
+ parport_setscl(NULL, 1);
+ /* Other init if needed (power on...) */
+ if (adapter_parm[type].init.val) {
+ line_set(1, &adapter_parm[type].init);
+ /* Give powered devices some time to settle */
+ msleep(100);
+ }
+
+ parport_adapter.dev.parent = &pdev->dev;
+ err = i2c_bit_add_bus(&parport_adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to register with I2C\n");
+ return err;
+ }
+
+ /* Setup SMBus alert if supported */
+ if (adapter_parm[type].smbus_alert && irq) {
+ alert_data.irq = irq;
+ ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data);
+ if (ara)
+ line_set(1, &parport_ctrl_irq);
+ else
+ dev_warn(&pdev->dev, "Failed to register ARA client\n");
+ }
+
+ return 0;
+}
+
+static int i2c_parport_remove(struct platform_device *pdev)
+{
+ if (ara) {
+ line_set(0, &parport_ctrl_irq);
+ i2c_unregister_device(ara);
+ ara = NULL;
+ }
+ i2c_del_adapter(&parport_adapter);
+
+ /* Un-init if needed (power off...) */
+ if (adapter_parm[type].init.val)
+ line_set(0, &adapter_parm[type].init);
+
+ return 0;
+}
+
+static struct platform_driver i2c_parport_driver = {
+ .driver = {
+ .name = DRVNAME,
+ },
+ .probe = i2c_parport_probe,
+ .remove = i2c_parport_remove,
+};
+
+static int __init i2c_parport_device_add(u16 address)
+{
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, -1);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
+static int __init i2c_parport_init(void)
+{
+ int err;
+
+ if (type < 0) {
+ printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
+ return -ENODEV;
+ }
+
+ if (type >= ARRAY_SIZE(adapter_parm)) {
+ printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
+ return -ENODEV;
+ }
+
+ if (base == 0) {
+ pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
+ base = DEFAULT_BASE;
+ }
+
+ if (!request_region(base, 3, DRVNAME))
+ return -EBUSY;
+
+ if (irq != 0)
+ pr_info(DRVNAME ": using irq %d\n", irq);
+
+ if (!adapter_parm[type].getscl.val)
+ parport_algo_data.getscl = NULL;
+
+ /* Sets global pdev as a side effect */
+ err = i2c_parport_device_add(base);
+ if (err)
+ goto exit_release;
+
+ err = platform_driver_register(&i2c_parport_driver);
+ if (err)
+ goto exit_device;
+
+ return 0;
+
+exit_device:
+ platform_device_unregister(pdev);
+exit_release:
+ release_region(base, 3);
+ return err;
+}
+
+static void __exit i2c_parport_exit(void)
+{
+ platform_driver_unregister(&i2c_parport_driver);
+ platform_device_unregister(pdev);
+ release_region(base, 3);
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("I2C bus over parallel port (light)");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_parport_init);
+module_exit(i2c_parport_exit);
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
new file mode 100644
index 000000000..319209a07
--- /dev/null
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -0,0 +1,330 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport.c I2C bus over parallel port *
+ * ------------------------------------------------------------------------ *
+ Copyright (C) 2003-2011 Jean Delvare <jdelvare@suse.de>
+
+ Based on older i2c-philips-par.c driver
+ Copyright (C) 1995-2000 Simon G. Vogl
+ With some changes from:
+ Frodo Looijaard <frodol@dds.nl>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ * ------------------------------------------------------------------------ */
+
+#define pr_fmt(fmt) "i2c-parport: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/parport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include "i2c-parport.h"
+
+/* ----- Device list ------------------------------------------------------ */
+
+struct i2c_par {
+ struct pardevice *pdev;
+ struct i2c_adapter adapter;
+ struct i2c_algo_bit_data algo_data;
+ struct i2c_smbus_alert_setup alert_data;
+ struct i2c_client *ara;
+ struct list_head node;
+};
+
+static LIST_HEAD(adapter_list);
+static DEFINE_MUTEX(adapter_list_lock);
+#define MAX_DEVICE 4
+static int parport[MAX_DEVICE] = {0, -1, -1, -1};
+
+
+/* ----- Low-level parallel port access ----------------------------------- */
+
+static void port_write_data(struct parport *p, unsigned char d)
+{
+ parport_write_data(p, d);
+}
+
+static void port_write_control(struct parport *p, unsigned char d)
+{
+ parport_write_control(p, d);
+}
+
+static unsigned char port_read_data(struct parport *p)
+{
+ return parport_read_data(p);
+}
+
+static unsigned char port_read_status(struct parport *p)
+{
+ return parport_read_status(p);
+}
+
+static unsigned char port_read_control(struct parport *p)
+{
+ return parport_read_control(p);
+}
+
+static void (* const port_write[])(struct parport *, unsigned char) = {
+ port_write_data,
+ NULL,
+ port_write_control,
+};
+
+static unsigned char (* const port_read[])(struct parport *) = {
+ port_read_data,
+ port_read_status,
+ port_read_control,
+};
+
+/* ----- Unified line operation functions --------------------------------- */
+
+static inline void line_set(struct parport *data, int state,
+ const struct lineop *op)
+{
+ u8 oldval = port_read[op->port](data);
+
+ /* Touch only the bit(s) needed */
+ if ((op->inverted && !state) || (!op->inverted && state))
+ port_write[op->port](data, oldval | op->val);
+ else
+ port_write[op->port](data, oldval & ~op->val);
+}
+
+static inline int line_get(struct parport *data,
+ const struct lineop *op)
+{
+ u8 oldval = port_read[op->port](data);
+
+ return ((op->inverted && (oldval & op->val) != op->val)
+ || (!op->inverted && (oldval & op->val) == op->val));
+}
+
+/* ----- I2C algorithm call-back functions and structures ----------------- */
+
+static void parport_setscl(void *data, int state)
+{
+ line_set((struct parport *) data, state, &adapter_parm[type].setscl);
+}
+
+static void parport_setsda(void *data, int state)
+{
+ line_set((struct parport *) data, state, &adapter_parm[type].setsda);
+}
+
+static int parport_getscl(void *data)
+{
+ return line_get((struct parport *) data, &adapter_parm[type].getscl);
+}
+
+static int parport_getsda(void *data)
+{
+ return line_get((struct parport *) data, &adapter_parm[type].getsda);
+}
+
+/* Encapsulate the functions above in the correct structure.
+ Note that this is only a template, from which the real structures are
+ copied. The attaching code will set getscl to NULL for adapters that
+ cannot read SCL back, and will also make the data field point to
+ the parallel port structure. */
+static const struct i2c_algo_bit_data parport_algo_data = {
+ .setsda = parport_setsda,
+ .setscl = parport_setscl,
+ .getsda = parport_getsda,
+ .getscl = parport_getscl,
+ .udelay = 10, /* ~50 kbps */
+ .timeout = HZ,
+};
+
+/* ----- I2c and parallel port call-back functions and structures --------- */
+
+static void i2c_parport_irq(void *data)
+{
+ struct i2c_par *adapter = data;
+ struct i2c_client *ara = adapter->ara;
+
+ if (ara) {
+ dev_dbg(&ara->dev, "SMBus alert received\n");
+ i2c_handle_smbus_alert(ara);
+ } else
+ dev_dbg(&adapter->adapter.dev,
+ "SMBus alert received but no ARA client!\n");
+}
+
+static void i2c_parport_attach(struct parport *port)
+{
+ struct i2c_par *adapter;
+ int i;
+ struct pardev_cb i2c_parport_cb;
+
+ for (i = 0; i < MAX_DEVICE; i++) {
+ if (parport[i] == -1)
+ continue;
+ if (port->number == parport[i])
+ break;
+ }
+ if (i == MAX_DEVICE) {
+ pr_debug("Not using parport%d.\n", port->number);
+ return;
+ }
+
+ adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
+ if (!adapter)
+ return;
+ memset(&i2c_parport_cb, 0, sizeof(i2c_parport_cb));
+ i2c_parport_cb.flags = PARPORT_FLAG_EXCL;
+ i2c_parport_cb.irq_func = i2c_parport_irq;
+ i2c_parport_cb.private = adapter;
+
+ pr_debug("attaching to %s\n", port->name);
+ parport_disable_irq(port);
+ adapter->pdev = parport_register_dev_model(port, "i2c-parport",
+ &i2c_parport_cb, i);
+ if (!adapter->pdev) {
+ pr_err("Unable to register with parport\n");
+ goto err_free;
+ }
+
+ /* Fill the rest of the structure */
+ adapter->adapter.owner = THIS_MODULE;
+ adapter->adapter.class = I2C_CLASS_HWMON;
+ strlcpy(adapter->adapter.name, "Parallel port adapter",
+ sizeof(adapter->adapter.name));
+ adapter->algo_data = parport_algo_data;
+ /* Slow down if we can't sense SCL */
+ if (!adapter_parm[type].getscl.val) {
+ adapter->algo_data.getscl = NULL;
+ adapter->algo_data.udelay = 50; /* ~10 kbps */
+ }
+ adapter->algo_data.data = port;
+ adapter->adapter.algo_data = &adapter->algo_data;
+ adapter->adapter.dev.parent = port->physport->dev;
+
+ if (parport_claim_or_block(adapter->pdev) < 0) {
+ dev_err(&adapter->pdev->dev,
+ "Could not claim parallel port\n");
+ goto err_unregister;
+ }
+
+ /* Reset hardware to a sane state (SCL and SDA high) */
+ parport_setsda(port, 1);
+ parport_setscl(port, 1);
+ /* Other init if needed (power on...) */
+ if (adapter_parm[type].init.val) {
+ line_set(port, 1, &adapter_parm[type].init);
+ /* Give powered devices some time to settle */
+ msleep(100);
+ }
+
+ if (i2c_bit_add_bus(&adapter->adapter) < 0) {
+ dev_err(&adapter->pdev->dev, "Unable to register with I2C\n");
+ goto err_unregister;
+ }
+
+ /* Setup SMBus alert if supported */
+ if (adapter_parm[type].smbus_alert) {
+ adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
+ &adapter->alert_data);
+ if (adapter->ara)
+ parport_enable_irq(port);
+ else
+ dev_warn(&adapter->pdev->dev,
+ "Failed to register ARA client\n");
+ }
+
+ /* Add the new adapter to the list */
+ mutex_lock(&adapter_list_lock);
+ list_add_tail(&adapter->node, &adapter_list);
+ mutex_unlock(&adapter_list_lock);
+ return;
+
+ err_unregister:
+ parport_release(adapter->pdev);
+ parport_unregister_device(adapter->pdev);
+ err_free:
+ kfree(adapter);
+}
+
+static void i2c_parport_detach(struct parport *port)
+{
+ struct i2c_par *adapter, *_n;
+
+ /* Walk the list */
+ mutex_lock(&adapter_list_lock);
+ list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
+ if (adapter->pdev->port == port) {
+ if (adapter->ara) {
+ parport_disable_irq(port);
+ i2c_unregister_device(adapter->ara);
+ }
+ i2c_del_adapter(&adapter->adapter);
+
+ /* Un-init if needed (power off...) */
+ if (adapter_parm[type].init.val)
+ line_set(port, 0, &adapter_parm[type].init);
+
+ parport_release(adapter->pdev);
+ parport_unregister_device(adapter->pdev);
+ list_del(&adapter->node);
+ kfree(adapter);
+ }
+ }
+ mutex_unlock(&adapter_list_lock);
+}
+
+static struct parport_driver i2c_parport_driver = {
+ .name = "i2c-parport",
+ .match_port = i2c_parport_attach,
+ .detach = i2c_parport_detach,
+ .devmodel = true,
+};
+
+/* ----- Module loading, unloading and information ------------------------ */
+
+static int __init i2c_parport_init(void)
+{
+ if (type < 0) {
+ pr_warn("adapter type unspecified\n");
+ return -ENODEV;
+ }
+
+ if (type >= ARRAY_SIZE(adapter_parm)) {
+ pr_warn("invalid type (%d)\n", type);
+ return -ENODEV;
+ }
+
+ return parport_register_driver(&i2c_parport_driver);
+}
+
+static void __exit i2c_parport_exit(void)
+{
+ parport_unregister_driver(&i2c_parport_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("I2C bus over parallel port");
+MODULE_LICENSE("GPL");
+
+module_param_array(parport, int, NULL, 0);
+MODULE_PARM_DESC(parport,
+ "List of parallel ports to bind to, by index.\n"
+ " Atmost " __stringify(MAX_DEVICE) " devices are supported.\n"
+ " Default is one device connected to parport0.\n"
+);
+
+module_init(i2c_parport_init);
+module_exit(i2c_parport_exit);
diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h
new file mode 100644
index 000000000..84a6616b0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-parport.h
@@ -0,0 +1,114 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport.h I2C bus over parallel port *
+ * ------------------------------------------------------------------------ *
+ Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ * ------------------------------------------------------------------------ */
+
+#define PORT_DATA 0
+#define PORT_STAT 1
+#define PORT_CTRL 2
+
+struct lineop {
+ u8 val;
+ u8 port;
+ u8 inverted;
+};
+
+struct adapter_parm {
+ struct lineop setsda;
+ struct lineop setscl;
+ struct lineop getsda;
+ struct lineop getscl;
+ struct lineop init;
+ unsigned int smbus_alert:1;
+};
+
+static const struct adapter_parm adapter_parm[] = {
+ /* type 0: Philips adapter */
+ {
+ .setsda = { 0x80, PORT_DATA, 1 },
+ .setscl = { 0x08, PORT_CTRL, 0 },
+ .getsda = { 0x80, PORT_STAT, 0 },
+ .getscl = { 0x08, PORT_STAT, 0 },
+ },
+ /* type 1: home brew teletext adapter */
+ {
+ .setsda = { 0x02, PORT_DATA, 0 },
+ .setscl = { 0x01, PORT_DATA, 0 },
+ .getsda = { 0x80, PORT_STAT, 1 },
+ },
+ /* type 2: Velleman K8000 adapter */
+ {
+ .setsda = { 0x02, PORT_CTRL, 1 },
+ .setscl = { 0x08, PORT_CTRL, 1 },
+ .getsda = { 0x10, PORT_STAT, 0 },
+ },
+ /* type 3: ELV adapter */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x40, PORT_STAT, 1 },
+ .getscl = { 0x08, PORT_STAT, 1 },
+ },
+ /* type 4: ADM1032 evaluation board */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x10, PORT_STAT, 1 },
+ .init = { 0xf0, PORT_DATA, 0 },
+ .smbus_alert = 1,
+ },
+ /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x10, PORT_STAT, 1 },
+ },
+ /* type 6: Barco LPT->DVI (K5800236) adapter */
+ {
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x20, PORT_STAT, 0 },
+ .getscl = { 0x40, PORT_STAT, 0 },
+ .init = { 0xfc, PORT_DATA, 0 },
+ },
+ /* type 7: One For All JP1 parallel port adapter */
+ {
+ .setsda = { 0x01, PORT_DATA, 0 },
+ .setscl = { 0x02, PORT_DATA, 0 },
+ .getsda = { 0x80, PORT_STAT, 1 },
+ .init = { 0x04, PORT_DATA, 1 },
+ },
+ /* type 8: VCT-jig */
+ {
+ .setsda = { 0x04, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x40, PORT_STAT, 0 },
+ .getscl = { 0x80, PORT_STAT, 1 },
+ },
+};
+
+static int type = -1;
+module_param(type, int, 0);
+MODULE_PARM_DESC(type,
+ "Type of adapter:\n"
+ " 0 = Philips adapter\n"
+ " 1 = home brew teletext adapter\n"
+ " 2 = Velleman K8000 adapter\n"
+ " 3 = ELV adapter\n"
+ " 4 = ADM1032 evaluation board\n"
+ " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
+ " 6 = Barco LPT->DVI (K5800236) adapter\n"
+ " 7 = One For All JP1 parallel port adapter\n"
+ " 8 = VCT-jig\n"
+);
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
new file mode 100644
index 000000000..46e739913
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * SMBus host driver for PA Semi PWRficient
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+static struct pci_driver pasemi_smb_driver;
+
+struct pasemi_smbus {
+ struct pci_dev *dev;
+ struct i2c_adapter adapter;
+ unsigned long base;
+ int size;
+};
+
+/* Register offsets */
+#define REG_MTXFIFO 0x00
+#define REG_MRXFIFO 0x04
+#define REG_SMSTA 0x14
+#define REG_CTL 0x1c
+
+/* Register defs */
+#define MTXFIFO_READ 0x00000400
+#define MTXFIFO_STOP 0x00000200
+#define MTXFIFO_START 0x00000100
+#define MTXFIFO_DATA_M 0x000000ff
+
+#define MRXFIFO_EMPTY 0x00000100
+#define MRXFIFO_DATA_M 0x000000ff
+
+#define SMSTA_XEN 0x08000000
+#define SMSTA_MTN 0x00200000
+
+#define CTL_MRR 0x00000400
+#define CTL_MTR 0x00000200
+#define CTL_CLK_M 0x000000ff
+
+#define CLK_100K_DIV 84
+#define CLK_400K_DIV 21
+
+static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
+{
+ dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n",
+ smbus->base + reg, val);
+ outl(val, smbus->base + reg);
+}
+
+static inline int reg_read(struct pasemi_smbus *smbus, int reg)
+{
+ int ret;
+ ret = inl(smbus->base + reg);
+ dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n",
+ smbus->base + reg, ret);
+ return ret;
+}
+
+#define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg))
+#define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO)
+
+static void pasemi_smb_clear(struct pasemi_smbus *smbus)
+{
+ unsigned int status;
+
+ status = reg_read(smbus, REG_SMSTA);
+ reg_write(smbus, REG_SMSTA, status);
+}
+
+static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
+{
+ int timeout = 10;
+ unsigned int status;
+
+ status = reg_read(smbus, REG_SMSTA);
+
+ while (!(status & SMSTA_XEN) && timeout--) {
+ msleep(1);
+ status = reg_read(smbus, REG_SMSTA);
+ }
+
+ /* Got NACK? */
+ if (status & SMSTA_MTN)
+ return -ENXIO;
+
+ if (timeout < 0) {
+ dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
+ reg_write(smbus, REG_SMSTA, status);
+ return -ETIME;
+ }
+
+ /* Clear XEN */
+ reg_write(smbus, REG_SMSTA, SMSTA_XEN);
+
+ return 0;
+}
+
+static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
+ struct i2c_msg *msg, int stop)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ int read, i, err;
+ u32 rd;
+
+ read = msg->flags & I2C_M_RD ? 1 : 0;
+
+ TXFIFO_WR(smbus, MTXFIFO_START | i2c_8bit_addr_from_msg(msg));
+
+ if (read) {
+ TXFIFO_WR(smbus, msg->len | MTXFIFO_READ |
+ (stop ? MTXFIFO_STOP : 0));
+
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+
+ for (i = 0; i < msg->len; i++) {
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ msg->buf[i] = rd & MRXFIFO_DATA_M;
+ }
+ } else {
+ for (i = 0; i < msg->len - 1; i++)
+ TXFIFO_WR(smbus, msg->buf[i]);
+
+ TXFIFO_WR(smbus, msg->buf[msg->len-1] |
+ (stop ? MTXFIFO_STOP : 0));
+
+ if (stop) {
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+ }
+ }
+
+ return 0;
+
+ reset_out:
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+ return err;
+}
+
+static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ int ret, i;
+
+ pasemi_smb_clear(smbus);
+
+ ret = 0;
+
+ for (i = 0; i < num && !ret; i++)
+ ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
+
+ return ret ? ret : num;
+}
+
+static int pasemi_smb_xfer(struct i2c_adapter *adapter,
+ u16 addr, unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ unsigned int rd;
+ int read_flag, err;
+ int len = 0, i;
+
+ /* All our ops take 8-bit shifted addresses */
+ addr <<= 1;
+ read_flag = read_write == I2C_SMBUS_READ;
+
+ pasemi_smb_clear(smbus);
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START |
+ MTXFIFO_STOP);
+ break;
+ case I2C_SMBUS_BYTE:
+ TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START);
+ if (read_write)
+ TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ);
+ else
+ TXFIFO_WR(smbus, MTXFIFO_STOP | command);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP);
+ } else {
+ TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte);
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP);
+ } else {
+ TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8));
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 1 | MTXFIFO_READ);
+ rd = RXFIFO_RD(smbus);
+ len = min_t(u8, (rd & MRXFIFO_DATA_M),
+ I2C_SMBUS_BLOCK_MAX);
+ TXFIFO_WR(smbus, len | MTXFIFO_READ |
+ MTXFIFO_STOP);
+ } else {
+ len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX);
+ TXFIFO_WR(smbus, len);
+ for (i = 1; i < len; i++)
+ TXFIFO_WR(smbus, data->block[i]);
+ TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP);
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ read_write = I2C_SMBUS_READ;
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ);
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1);
+ read_write = I2C_SMBUS_READ;
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ TXFIFO_WR(smbus, len);
+ for (i = 1; i <= len; i++)
+ TXFIFO_WR(smbus, data->block[i]);
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ);
+ TXFIFO_WR(smbus, MTXFIFO_READ | 1);
+ rd = RXFIFO_RD(smbus);
+ len = min_t(u8, (rd & MRXFIFO_DATA_M),
+ I2C_SMBUS_BLOCK_MAX - len);
+ TXFIFO_WR(smbus, len | MTXFIFO_READ | MTXFIFO_STOP);
+ break;
+
+ default:
+ dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+ return -EINVAL;
+ }
+
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->byte = rd & MRXFIFO_DATA_M;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->word = rd & MRXFIFO_DATA_M;
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->word |= (rd & MRXFIFO_DATA_M) << 8;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ data->block[0] = len;
+ for (i = 1; i <= len; i ++) {
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->block[i] = rd & MRXFIFO_DATA_M;
+ }
+ break;
+ }
+
+ return 0;
+
+ reset_out:
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+ return err;
+}
+
+static u32 pasemi_smb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .master_xfer = pasemi_i2c_xfer,
+ .smbus_xfer = pasemi_smb_xfer,
+ .functionality = pasemi_smb_func,
+};
+
+static int pasemi_smb_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct pasemi_smbus *smbus;
+ int error;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+ return -ENODEV;
+
+ smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL);
+ if (!smbus)
+ return -ENOMEM;
+
+ smbus->dev = dev;
+ smbus->base = pci_resource_start(dev, 0);
+ smbus->size = pci_resource_len(dev, 0);
+
+ if (!request_region(smbus->base, smbus->size,
+ pasemi_smb_driver.name)) {
+ error = -EBUSY;
+ goto out_kfree;
+ }
+
+ smbus->adapter.owner = THIS_MODULE;
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+ "PA Semi SMBus adapter at 0x%lx", smbus->base);
+ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+
+ /* set up the sysfs linkage to our parent device */
+ smbus->adapter.dev.parent = &dev->dev;
+
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+
+ error = i2c_add_adapter(&smbus->adapter);
+ if (error)
+ goto out_release_region;
+
+ pci_set_drvdata(dev, smbus);
+
+ return 0;
+
+ out_release_region:
+ release_region(smbus->base, smbus->size);
+ out_kfree:
+ kfree(smbus);
+ return error;
+}
+
+static void pasemi_smb_remove(struct pci_dev *dev)
+{
+ struct pasemi_smbus *smbus = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&smbus->adapter);
+ release_region(smbus->base, smbus->size);
+ kfree(smbus);
+}
+
+static const struct pci_device_id pasemi_smb_ids[] = {
+ { PCI_DEVICE(0x1959, 0xa003) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_smb_ids);
+
+static struct pci_driver pasemi_smb_driver = {
+ .name = "i2c-pasemi",
+ .id_table = pasemi_smb_ids,
+ .probe = pasemi_smb_probe,
+ .remove = pasemi_smb_remove,
+};
+
+module_pci_driver(pasemi_smb_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
new file mode 100644
index 000000000..946ac646d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -0,0 +1,212 @@
+/*
+ * i2c-pca-isa.c driver for PCA9564 on ISA boards
+ * Copyright (C) 2004 Arcom Control Systems
+ * Copyright (C) 2008 Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/isa.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#define DRIVER "i2c-pca-isa"
+#define IO_SIZE 4
+
+static unsigned long base;
+static int irq = -1;
+
+/* Data sheet recommends 59kHz for 100kHz operation due to variation
+ * in the actual clock rate */
+static int clock = 59000;
+
+static struct i2c_adapter pca_isa_ops;
+static wait_queue_head_t pca_wait;
+
+static void pca_isa_writebyte(void *pd, int reg, int val)
+{
+#ifdef DEBUG_IO
+ static char *names[] = { "T/O", "DAT", "ADR", "CON" };
+ printk(KERN_DEBUG "*** write %s at %#lx <= %#04x\n", names[reg],
+ base+reg, val);
+#endif
+ outb(val, base+reg);
+}
+
+static int pca_isa_readbyte(void *pd, int reg)
+{
+ int res = inb(base+reg);
+#ifdef DEBUG_IO
+ {
+ static char *names[] = { "STA", "DAT", "ADR", "CON" };
+ printk(KERN_DEBUG "*** read %s => %#04x\n", names[reg], res);
+ }
+#endif
+ return res;
+}
+
+static int pca_isa_waitforcompletion(void *pd)
+{
+ unsigned long timeout;
+ long ret;
+
+ if (irq > -1) {
+ ret = wait_event_timeout(pca_wait,
+ pca_isa_readbyte(pd, I2C_PCA_CON)
+ & I2C_PCA_CON_SI, pca_isa_ops.timeout);
+ } else {
+ /* Do polling */
+ timeout = jiffies + pca_isa_ops.timeout;
+ do {
+ ret = time_before(jiffies, timeout);
+ if (pca_isa_readbyte(pd, I2C_PCA_CON)
+ & I2C_PCA_CON_SI)
+ break;
+ udelay(100);
+ } while (ret);
+ }
+
+ return ret > 0;
+}
+
+static void pca_isa_resetchip(void *pd)
+{
+ /* apparently only an external reset will do it. not a lot can be done */
+ printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
+}
+
+static irqreturn_t pca_handler(int this_irq, void *dev_id) {
+ wake_up(&pca_wait);
+ return IRQ_HANDLED;
+}
+
+static struct i2c_algo_pca_data pca_isa_data = {
+ /* .data intentionally left NULL, not needed with ISA */
+ .write_byte = pca_isa_writebyte,
+ .read_byte = pca_isa_readbyte,
+ .wait_for_completion = pca_isa_waitforcompletion,
+ .reset_chip = pca_isa_resetchip,
+};
+
+static struct i2c_adapter pca_isa_ops = {
+ .owner = THIS_MODULE,
+ .algo_data = &pca_isa_data,
+ .name = "PCA9564/PCA9665 ISA Adapter",
+ .timeout = HZ,
+};
+
+static int pca_isa_match(struct device *dev, unsigned int id)
+{
+ int match = base != 0;
+
+ if (match) {
+ if (irq <= -1)
+ dev_warn(dev, "Using polling mode (specify irq)\n");
+ } else
+ dev_err(dev, "Please specify I/O base\n");
+
+ return match;
+}
+
+static int pca_isa_probe(struct device *dev, unsigned int id)
+{
+ init_waitqueue_head(&pca_wait);
+
+ dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
+
+#ifdef CONFIG_PPC
+ if (check_legacy_ioport(base)) {
+ dev_err(dev, "I/O address %#08lx is not available\n", base);
+ goto out;
+ }
+#endif
+
+ if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
+ dev_err(dev, "I/O address %#08lx is in use\n", base);
+ goto out;
+ }
+
+ if (irq > -1) {
+ if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
+ dev_err(dev, "Request irq%d failed\n", irq);
+ goto out_region;
+ }
+ }
+
+ pca_isa_data.i2c_clock = clock;
+ if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
+ dev_err(dev, "Failed to add i2c bus\n");
+ goto out_irq;
+ }
+
+ return 0;
+
+ out_irq:
+ if (irq > -1)
+ free_irq(irq, &pca_isa_ops);
+ out_region:
+ release_region(base, IO_SIZE);
+ out:
+ return -ENODEV;
+}
+
+static int pca_isa_remove(struct device *dev, unsigned int id)
+{
+ i2c_del_adapter(&pca_isa_ops);
+
+ if (irq > -1) {
+ disable_irq(irq);
+ free_irq(irq, &pca_isa_ops);
+ }
+ release_region(base, IO_SIZE);
+
+ return 0;
+}
+
+static struct isa_driver pca_isa_driver = {
+ .match = pca_isa_match,
+ .probe = pca_isa_probe,
+ .remove = pca_isa_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER,
+ }
+};
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
+MODULE_LICENSE("GPL");
+
+module_param_hw(base, ulong, ioport, 0);
+MODULE_PARM_DESC(base, "I/O base address");
+module_param_hw(irq, int, irq, 0);
+MODULE_PARM_DESC(irq, "IRQ");
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
+ "For PCA9564: 330000,288000,217000,146000,"
+ "88000,59000,44000,36000\n"
+ "\t\tFor PCA9665:\tStandard: 60300 - 100099\n"
+ "\t\t\t\tFast: 100100 - 400099\n"
+ "\t\t\t\tFast+: 400100 - 10000099\n"
+ "\t\t\t\tTurbo: Up to 1265800");
+module_isa_driver(pca_isa_driver, 1);
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
new file mode 100644
index 000000000..f50afa8e3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -0,0 +1,262 @@
+/*
+ * i2c_pca_platform.c
+ *
+ * Platform driver for the PCA9564 I2C controller.
+ *
+ * Copyright (C) 2008 Pengutronix
+ *
+ * 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/slab.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/platform_data/i2c-pca-platform.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/irq.h>
+
+struct i2c_pca_pf_data {
+ void __iomem *reg_base;
+ int irq; /* if 0, use polling */
+ struct gpio_desc *gpio;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_algo_pca_data algo_data;
+ unsigned long io_base;
+ unsigned long io_size;
+};
+
+/* Read/Write functions for different register alignments */
+
+static int i2c_pca_pf_readbyte8(void *pd, int reg)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ return ioread8(i2c->reg_base + reg);
+}
+
+static int i2c_pca_pf_readbyte16(void *pd, int reg)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ return ioread8(i2c->reg_base + reg * 2);
+}
+
+static int i2c_pca_pf_readbyte32(void *pd, int reg)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ return ioread8(i2c->reg_base + reg * 4);
+}
+
+static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ iowrite8(val, i2c->reg_base + reg);
+}
+
+static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ iowrite8(val, i2c->reg_base + reg * 2);
+}
+
+static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ iowrite8(val, i2c->reg_base + reg * 4);
+}
+
+
+static int i2c_pca_pf_waitforcompletion(void *pd)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+ unsigned long timeout;
+ long ret;
+
+ if (i2c->irq) {
+ ret = wait_event_timeout(i2c->wait,
+ i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+ & I2C_PCA_CON_SI, i2c->adap.timeout);
+ } else {
+ /* Do polling */
+ timeout = jiffies + i2c->adap.timeout;
+ do {
+ ret = time_before(jiffies, timeout);
+ if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+ & I2C_PCA_CON_SI)
+ break;
+ udelay(100);
+ } while (ret);
+ }
+
+ return ret > 0;
+}
+
+static void i2c_pca_pf_dummyreset(void *pd)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+
+ dev_warn(&i2c->adap.dev, "No reset-pin found. Chip may get stuck!\n");
+}
+
+static void i2c_pca_pf_resetchip(void *pd)
+{
+ struct i2c_pca_pf_data *i2c = pd;
+
+ gpiod_set_value(i2c->gpio, 1);
+ ndelay(100);
+ gpiod_set_value(i2c->gpio, 0);
+}
+
+static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
+{
+ struct i2c_pca_pf_data *i2c = dev_id;
+
+ if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
+ return IRQ_NONE;
+
+ wake_up(&i2c->wait);
+
+ return IRQ_HANDLED;
+}
+
+
+static int i2c_pca_pf_probe(struct platform_device *pdev)
+{
+ struct i2c_pca_pf_data *i2c;
+ struct resource *res;
+ struct i2c_pca9564_pf_platform_data *platform_data =
+ dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ int ret = 0;
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+ /* If irq is 0, we do polling. */
+ if (irq < 0)
+ irq = 0;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->reg_base))
+ return PTR_ERR(i2c->reg_base);
+
+
+ init_waitqueue_head(&i2c->wait);
+
+ i2c->io_base = res->start;
+ i2c->io_size = resource_size(res);
+ i2c->irq = irq;
+
+ i2c->adap.nr = pdev->id;
+ i2c->adap.owner = THIS_MODULE;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "PCA9564/PCA9665 at 0x%08lx",
+ (unsigned long) res->start);
+ i2c->adap.algo_data = &i2c->algo_data;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = np;
+
+ i2c->gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(i2c->gpio))
+ return PTR_ERR(i2c->gpio);
+
+ i2c->adap.timeout = HZ;
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency",
+ &i2c->algo_data.i2c_clock);
+ if (ret)
+ i2c->algo_data.i2c_clock = 59000;
+
+ if (platform_data) {
+ i2c->adap.timeout = platform_data->timeout;
+ i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
+ }
+
+ i2c->algo_data.data = i2c;
+ i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
+ if (i2c->gpio)
+ i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
+ else
+ i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
+
+ switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
+ case IORESOURCE_MEM_32BIT:
+ i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
+ i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
+ break;
+ case IORESOURCE_MEM_16BIT:
+ i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
+ i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
+ break;
+ case IORESOURCE_MEM_8BIT:
+ default:
+ i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
+ i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
+ break;
+ }
+
+ if (irq) {
+ ret = devm_request_irq(&pdev->dev, irq, i2c_pca_pf_handler,
+ IRQF_TRIGGER_FALLING, pdev->name, i2c);
+ if (ret)
+ return ret;
+ }
+
+ ret = i2c_pca_add_numbered_bus(&i2c->adap);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, i2c);
+
+ dev_info(&pdev->dev, "registered.\n");
+
+ return 0;
+}
+
+static int i2c_pca_pf_remove(struct platform_device *pdev)
+{
+ struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id i2c_pca_of_match_table[] = {
+ { .compatible = "nxp,pca9564" },
+ { .compatible = "nxp,pca9665" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, i2c_pca_of_match_table);
+#endif
+
+static struct platform_driver i2c_pca_pf_driver = {
+ .probe = i2c_pca_pf_probe,
+ .remove = i2c_pca_pf_remove,
+ .driver = {
+ .name = "i2c-pca-platform",
+ .of_match_table = of_match_ptr(i2c_pca_of_match_table),
+ },
+};
+
+module_platform_driver(i2c_pca_pf_driver);
+
+MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
new file mode 100644
index 000000000..f1c79f9b3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -0,0 +1,1019 @@
+/*
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ Supports:
+ Intel PIIX4, 440MX
+ Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
+ ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
+ AMD Hudson-2, ML, CZ
+ SMSC Victory66
+
+ Note: we assume there can only be one device, with one or more
+ SMBus interfaces.
+ The device can register multiple i2c_adapters (up to PIIX4_MAX_ADAPTERS).
+ For devices supporting multiple ports the i2c_adapter should provide
+ an i2c_algorithm to access them.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/* PIIX4 SMBus address offsets */
+#define SMBHSTSTS (0 + piix4_smba)
+#define SMBHSLVSTS (1 + piix4_smba)
+#define SMBHSTCNT (2 + piix4_smba)
+#define SMBHSTCMD (3 + piix4_smba)
+#define SMBHSTADD (4 + piix4_smba)
+#define SMBHSTDAT0 (5 + piix4_smba)
+#define SMBHSTDAT1 (6 + piix4_smba)
+#define SMBBLKDAT (7 + piix4_smba)
+#define SMBSLVCNT (8 + piix4_smba)
+#define SMBSHDWCMD (9 + piix4_smba)
+#define SMBSLVEVT (0xA + piix4_smba)
+#define SMBSLVDAT (0xC + piix4_smba)
+
+/* count for request_region */
+#define SMBIOSIZE 9
+
+/* PCI Address Constants */
+#define SMBBA 0x090
+#define SMBHSTCFG 0x0D2
+#define SMBSLVC 0x0D3
+#define SMBSHDW1 0x0D4
+#define SMBSHDW2 0x0D5
+#define SMBREV 0x0D6
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+#define ENABLE_INT9 0
+
+/* PIIX4 constants */
+#define PIIX4_QUICK 0x00
+#define PIIX4_BYTE 0x04
+#define PIIX4_BYTE_DATA 0x08
+#define PIIX4_WORD_DATA 0x0C
+#define PIIX4_BLOCK_DATA 0x14
+
+/* Multi-port constants */
+#define PIIX4_MAX_ADAPTERS 4
+
+/* SB800 constants */
+#define SB800_PIIX4_SMB_IDX 0xcd6
+
+#define KERNCZ_IMC_IDX 0x3e
+#define KERNCZ_IMC_DATA 0x3f
+
+/*
+ * SB800 port is selected by bits 2:1 of the smb_en register (0x2c)
+ * or the smb_sel register (0x2e), depending on bit 0 of register 0x2f.
+ * Hudson-2/Bolton port is always selected by bits 2:1 of register 0x2f.
+ */
+#define SB800_PIIX4_PORT_IDX 0x2c
+#define SB800_PIIX4_PORT_IDX_ALT 0x2e
+#define SB800_PIIX4_PORT_IDX_SEL 0x2f
+#define SB800_PIIX4_PORT_IDX_MASK 0x06
+#define SB800_PIIX4_PORT_IDX_SHIFT 1
+
+/* On kerncz and Hudson2, SmBus0Sel is at bit 20:19 of PMx00 DecodeEn */
+#define SB800_PIIX4_PORT_IDX_KERNCZ 0x02
+#define SB800_PIIX4_PORT_IDX_MASK_KERNCZ 0x18
+#define SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ 3
+
+/* insmod parameters */
+
+/* If force is set to anything different from 0, we forcibly enable the
+ PIIX4. DANGEROUS! */
+static int force;
+module_param (force, int, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!");
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the PIIX4 at the given address. VERY DANGEROUS! */
+static int force_addr;
+module_param_hw(force_addr, int, ioport, 0);
+MODULE_PARM_DESC(force_addr,
+ "Forcibly enable the PIIX4 at the given address. "
+ "EXTREMELY DANGEROUS!");
+
+static int srvrworks_csb5_delay;
+static struct pci_driver piix4_driver;
+
+static const struct dmi_system_id piix4_dmi_blacklist[] = {
+ {
+ .ident = "Sapphire AM2RD790",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "SAPPHIRE Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "PC-AM2RD790"),
+ },
+ },
+ {
+ .ident = "DFI Lanparty UT 790FX",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "DFI Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "LP UT 790FX"),
+ },
+ },
+ { }
+};
+
+/* The IBM entry is in a separate table because we only check it
+ on Intel-based systems */
+static const struct dmi_system_id piix4_dmi_ibm[] = {
+ {
+ .ident = "IBM",
+ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
+ },
+ { },
+};
+
+/*
+ * SB800 globals
+ */
+static u8 piix4_port_sel_sb800;
+static u8 piix4_port_mask_sb800;
+static u8 piix4_port_shift_sb800;
+static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = {
+ " port 0", " port 2", " port 3", " port 4"
+};
+static const char *piix4_aux_port_name_sb800 = " port 1";
+
+struct i2c_piix4_adapdata {
+ unsigned short smba;
+
+ /* SB800 */
+ bool sb800_main;
+ bool notify_imc;
+ u8 port; /* Port number, shifted */
+};
+
+static int piix4_setup(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id)
+{
+ unsigned char temp;
+ unsigned short piix4_smba;
+
+ if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
+ (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
+ srvrworks_csb5_delay = 1;
+
+ /* On some motherboards, it was reported that accessing the SMBus
+ caused severe hardware problems */
+ if (dmi_check_system(piix4_dmi_blacklist)) {
+ dev_err(&PIIX4_dev->dev,
+ "Accessing the SMBus on this system is unsafe!\n");
+ return -EPERM;
+ }
+
+ /* Don't access SMBus on IBM systems which get corrupted eeproms */
+ if (dmi_check_system(piix4_dmi_ibm) &&
+ PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
+ dev_err(&PIIX4_dev->dev, "IBM system detected; this module "
+ "may corrupt your serial eeprom! Refusing to load "
+ "module!\n");
+ return -EPERM;
+ }
+
+ /* Determine the address of the SMBus areas */
+ if (force_addr) {
+ piix4_smba = force_addr & 0xfff0;
+ force = 0;
+ } else {
+ pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
+ piix4_smba &= 0xfff0;
+ if(piix4_smba == 0) {
+ dev_err(&PIIX4_dev->dev, "SMBus base address "
+ "uninitialized - upgrade BIOS or use "
+ "force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+ }
+
+ if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+ return -ENODEV;
+
+ if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+ dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
+ piix4_smba);
+ return -EBUSY;
+ }
+
+ pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
+
+ /* If force_addr is set, we program the new address here. Just to make
+ sure, we disable the PIIX4 first. */
+ if (force_addr) {
+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
+ pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
+ dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to "
+ "new address %04x!\n", piix4_smba);
+ } else if ((temp & 1) == 0) {
+ if (force) {
+ /* This should never need to be done, but has been
+ * noted that many Dell machines have the SMBus
+ * interface on the PIIX4 disabled!? NOTE: This assumes
+ * I/O space and other allocations WERE done by the
+ * Bios! Don't complain if your hardware does weird
+ * things after enabling this. :') Check for Bios
+ * updates before resorting to this.
+ */
+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
+ temp | 1);
+ dev_notice(&PIIX4_dev->dev,
+ "WARNING: SMBus interface has been FORCEFULLY ENABLED!\n");
+ } else {
+ dev_err(&PIIX4_dev->dev,
+ "SMBus Host Controller not enabled!\n");
+ release_region(piix4_smba, SMBIOSIZE);
+ return -ENODEV;
+ }
+ }
+
+ if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2))
+ dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus\n");
+ else if ((temp & 0x0E) == 0)
+ dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus\n");
+ else
+ dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration "
+ "(or code out of date)!\n");
+
+ pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
+ dev_info(&PIIX4_dev->dev,
+ "SMBus Host Controller at 0x%x, revision %d\n",
+ piix4_smba, temp);
+
+ return piix4_smba;
+}
+
+static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id, u8 aux)
+{
+ unsigned short piix4_smba;
+ u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status, port_sel;
+ u8 i2ccfg, i2ccfg_offset = 0x10;
+
+ /* SB800 and later SMBus does not support forcing address */
+ if (force || force_addr) {
+ dev_err(&PIIX4_dev->dev, "SMBus does not support "
+ "forcing address!\n");
+ return -EINVAL;
+ }
+
+ /* Determine the address of the SMBus areas */
+ if ((PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+ PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
+ PIIX4_dev->revision >= 0x41) ||
+ (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+ PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS &&
+ PIIX4_dev->revision >= 0x49))
+ smb_en = 0x00;
+ else
+ smb_en = (aux) ? 0x28 : 0x2c;
+
+ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) {
+ dev_err(&PIIX4_dev->dev,
+ "SMB base address index region 0x%x already in use.\n",
+ SB800_PIIX4_SMB_IDX);
+ return -EBUSY;
+ }
+
+ outb_p(smb_en, SB800_PIIX4_SMB_IDX);
+ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+ outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
+ smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+ release_region(SB800_PIIX4_SMB_IDX, 2);
+
+ if (!smb_en) {
+ smb_en_status = smba_en_lo & 0x10;
+ piix4_smba = smba_en_hi << 8;
+ if (aux)
+ piix4_smba |= 0x20;
+ } else {
+ smb_en_status = smba_en_lo & 0x01;
+ piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+ }
+
+ if (!smb_en_status) {
+ dev_err(&PIIX4_dev->dev,
+ "SMBus Host Controller not enabled!\n");
+ return -ENODEV;
+ }
+
+ if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+ return -ENODEV;
+
+ if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+ dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
+ piix4_smba);
+ return -EBUSY;
+ }
+
+ /* Aux SMBus does not support IRQ information */
+ if (aux) {
+ dev_info(&PIIX4_dev->dev,
+ "Auxiliary SMBus Host Controller at 0x%x\n",
+ piix4_smba);
+ return piix4_smba;
+ }
+
+ /* Request the SMBus I2C bus config region */
+ if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) {
+ dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
+ "0x%x already in use!\n", piix4_smba + i2ccfg_offset);
+ release_region(piix4_smba, SMBIOSIZE);
+ return -EBUSY;
+ }
+ i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
+ release_region(piix4_smba + i2ccfg_offset, 1);
+
+ if (i2ccfg & 1)
+ dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus\n");
+ else
+ dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus\n");
+
+ dev_info(&PIIX4_dev->dev,
+ "SMBus Host Controller at 0x%x, revision %d\n",
+ piix4_smba, i2ccfg >> 4);
+
+ /* Find which register is used for port selection */
+ if (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD) {
+ if (PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS ||
+ (PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
+ PIIX4_dev->revision >= 0x1F)) {
+ piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_KERNCZ;
+ piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK_KERNCZ;
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ;
+ } else {
+ piix4_port_sel_sb800 = SB800_PIIX4_PORT_IDX_ALT;
+ piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+ }
+ } else {
+ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2,
+ "sb800_piix4_smb")) {
+ release_region(piix4_smba, SMBIOSIZE);
+ return -EBUSY;
+ }
+
+ outb_p(SB800_PIIX4_PORT_IDX_SEL, SB800_PIIX4_SMB_IDX);
+ port_sel = inb_p(SB800_PIIX4_SMB_IDX + 1);
+ piix4_port_sel_sb800 = (port_sel & 0x01) ?
+ SB800_PIIX4_PORT_IDX_ALT :
+ SB800_PIIX4_PORT_IDX;
+ piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
+ piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
+ release_region(SB800_PIIX4_SMB_IDX, 2);
+ }
+
+ dev_info(&PIIX4_dev->dev,
+ "Using register 0x%02x for SMBus port selection\n",
+ (unsigned int)piix4_port_sel_sb800);
+
+ return piix4_smba;
+}
+
+static int piix4_setup_aux(struct pci_dev *PIIX4_dev,
+ const struct pci_device_id *id,
+ unsigned short base_reg_addr)
+{
+ /* Set up auxiliary SMBus controllers found on some
+ * AMD chipsets e.g. SP5100 (SB700 derivative) */
+
+ unsigned short piix4_smba;
+
+ /* Read address of auxiliary SMBus controller */
+ pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
+ if ((piix4_smba & 1) == 0) {
+ dev_dbg(&PIIX4_dev->dev,
+ "Auxiliary SMBus controller not enabled\n");
+ return -ENODEV;
+ }
+
+ piix4_smba &= 0xfff0;
+ if (piix4_smba == 0) {
+ dev_dbg(&PIIX4_dev->dev,
+ "Auxiliary SMBus base address uninitialized\n");
+ return -ENODEV;
+ }
+
+ if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+ return -ENODEV;
+
+ if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+ dev_err(&PIIX4_dev->dev, "Auxiliary SMBus region 0x%x "
+ "already in use!\n", piix4_smba);
+ return -EBUSY;
+ }
+
+ dev_info(&PIIX4_dev->dev,
+ "Auxiliary SMBus Host Controller at 0x%x\n",
+ piix4_smba);
+
+ return piix4_smba;
+}
+
+static int piix4_transaction(struct i2c_adapter *piix4_adapter)
+{
+ struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
+ unsigned short piix4_smba = adapdata->smba;
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+ dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). "
+ "Resetting...\n", temp);
+ outb_p(temp, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+ dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&piix4_adapter->dev, "Successful!\n");
+ }
+ }
+
+ /* start the transaction by setting bit 6 */
+ outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
+
+ /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
+ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */
+ usleep_range(2000, 2100);
+ else
+ usleep_range(250, 500);
+
+ while ((++timeout < MAX_TIMEOUT) &&
+ ((temp = inb_p(SMBHSTSTS)) & 0x01))
+ usleep_range(250, 500);
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout == MAX_TIMEOUT) {
+ dev_err(&piix4_adapter->dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+
+ if (temp & 0x10) {
+ result = -EIO;
+ dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n");
+ }
+
+ if (temp & 0x08) {
+ result = -EIO;
+ dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be "
+ "locked until next hard reset. (sorry!)\n");
+ /* Clock stops and slave is stuck in mid-transmission */
+ }
+
+ if (temp & 0x04) {
+ result = -ENXIO;
+ dev_dbg(&piix4_adapter->dev, "Error: no response!\n");
+ }
+
+ if (inb_p(SMBHSTSTS) != 0x00)
+ outb_p(inb(SMBHSTSTS), SMBHSTSTS);
+
+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+ dev_err(&piix4_adapter->dev, "Failed reset at end of "
+ "transaction (%02x)\n", temp);
+ }
+ dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+ unsigned short piix4_smba = adapdata->smba;
+ int i, len;
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ size = PIIX4_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ size = PIIX4_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ size = PIIX4_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = PIIX4_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ outb_p(len, SMBHSTDAT0);
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ size = PIIX4_BLOCK_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
+
+ status = piix4_transaction(adap);
+ if (status)
+ return status;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
+ return 0;
+
+
+ switch (size) {
+ case PIIX4_BYTE:
+ case PIIX4_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case PIIX4_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case PIIX4_BLOCK_DATA:
+ data->block[0] = inb_p(SMBHSTDAT0);
+ if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb_p(SMBBLKDAT);
+ break;
+ }
+ return 0;
+}
+
+static uint8_t piix4_imc_read(uint8_t idx)
+{
+ outb_p(idx, KERNCZ_IMC_IDX);
+ return inb_p(KERNCZ_IMC_DATA);
+}
+
+static void piix4_imc_write(uint8_t idx, uint8_t value)
+{
+ outb_p(idx, KERNCZ_IMC_IDX);
+ outb_p(value, KERNCZ_IMC_DATA);
+}
+
+static int piix4_imc_sleep(void)
+{
+ int timeout = MAX_TIMEOUT;
+
+ if (!request_muxed_region(KERNCZ_IMC_IDX, 2, "smbus_kerncz_imc"))
+ return -EBUSY;
+
+ /* clear response register */
+ piix4_imc_write(0x82, 0x00);
+ /* request ownership flag */
+ piix4_imc_write(0x83, 0xB4);
+ /* kick off IMC Mailbox command 96 */
+ piix4_imc_write(0x80, 0x96);
+
+ while (timeout--) {
+ if (piix4_imc_read(0x82) == 0xfa) {
+ release_region(KERNCZ_IMC_IDX, 2);
+ return 0;
+ }
+ usleep_range(1000, 2000);
+ }
+
+ release_region(KERNCZ_IMC_IDX, 2);
+ return -ETIMEDOUT;
+}
+
+static void piix4_imc_wakeup(void)
+{
+ int timeout = MAX_TIMEOUT;
+
+ if (!request_muxed_region(KERNCZ_IMC_IDX, 2, "smbus_kerncz_imc"))
+ return;
+
+ /* clear response register */
+ piix4_imc_write(0x82, 0x00);
+ /* release ownership flag */
+ piix4_imc_write(0x83, 0xB5);
+ /* kick off IMC Mailbox command 96 */
+ piix4_imc_write(0x80, 0x96);
+
+ while (timeout--) {
+ if (piix4_imc_read(0x82) == 0xfa)
+ break;
+ usleep_range(1000, 2000);
+ }
+
+ release_region(KERNCZ_IMC_IDX, 2);
+}
+
+/*
+ * Handles access to multiple SMBus ports on the SB800.
+ * The port is selected by bits 2:1 of the smb_en register (0x2c).
+ * Returns negative errno on error.
+ *
+ * Note: The selected port must be returned to the initial selection to avoid
+ * problems on certain systems.
+ */
+static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+ unsigned short piix4_smba = adapdata->smba;
+ int retries = MAX_TIMEOUT;
+ int smbslvcnt;
+ u8 smba_en_lo;
+ u8 port;
+ int retval;
+
+ if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb"))
+ return -EBUSY;
+
+ /* Request the SMBUS semaphore, avoid conflicts with the IMC */
+ smbslvcnt = inb_p(SMBSLVCNT);
+ do {
+ outb_p(smbslvcnt | 0x10, SMBSLVCNT);
+
+ /* Check the semaphore status */
+ smbslvcnt = inb_p(SMBSLVCNT);
+ if (smbslvcnt & 0x10)
+ break;
+
+ usleep_range(1000, 2000);
+ } while (--retries);
+ /* SMBus is still owned by the IMC, we give up */
+ if (!retries) {
+ retval = -EBUSY;
+ goto release;
+ }
+
+ /*
+ * Notify the IMC (Integrated Micro Controller) if required.
+ * Among other responsibilities, the IMC is in charge of monitoring
+ * the System fans and temperature sensors, and act accordingly.
+ * All this is done through SMBus and can/will collide
+ * with our transactions if they are long (BLOCK_DATA).
+ * Therefore we need to request the ownership flag during those
+ * transactions.
+ */
+ if ((size == I2C_SMBUS_BLOCK_DATA) && adapdata->notify_imc) {
+ int ret;
+
+ ret = piix4_imc_sleep();
+ switch (ret) {
+ case -EBUSY:
+ dev_warn(&adap->dev,
+ "IMC base address index region 0x%x already in use.\n",
+ KERNCZ_IMC_IDX);
+ break;
+ case -ETIMEDOUT:
+ dev_warn(&adap->dev,
+ "Failed to communicate with the IMC.\n");
+ break;
+ default:
+ break;
+ }
+
+ /* If IMC communication fails do not retry */
+ if (ret) {
+ dev_warn(&adap->dev,
+ "Continuing without IMC notification.\n");
+ adapdata->notify_imc = false;
+ }
+ }
+
+ outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
+ smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
+
+ port = adapdata->port;
+ if ((smba_en_lo & piix4_port_mask_sb800) != port)
+ outb_p((smba_en_lo & ~piix4_port_mask_sb800) | port,
+ SB800_PIIX4_SMB_IDX + 1);
+
+ retval = piix4_access(adap, addr, flags, read_write,
+ command, size, data);
+
+ outb_p(smba_en_lo, SB800_PIIX4_SMB_IDX + 1);
+
+ /* Release the semaphore */
+ outb_p(smbslvcnt | 0x20, SMBSLVCNT);
+
+ if ((size == I2C_SMBUS_BLOCK_DATA) && adapdata->notify_imc)
+ piix4_imc_wakeup();
+
+release:
+ release_region(SB800_PIIX4_SMB_IDX, 2);
+ return retval;
+}
+
+static u32 piix4_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = piix4_access,
+ .functionality = piix4_func,
+};
+
+static const struct i2c_algorithm piix4_smbus_algorithm_sb800 = {
+ .smbus_xfer = piix4_access_sb800,
+ .functionality = piix4_func,
+};
+
+static const struct pci_device_id piix4_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB5) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_HT1100LD) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, piix4_ids);
+
+static struct i2c_adapter *piix4_main_adapters[PIIX4_MAX_ADAPTERS];
+static struct i2c_adapter *piix4_aux_adapter;
+
+static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
+ bool sb800_main, u8 port, bool notify_imc,
+ const char *name, struct i2c_adapter **padap)
+{
+ struct i2c_adapter *adap;
+ struct i2c_piix4_adapdata *adapdata;
+ int retval;
+
+ adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+ if (adap == NULL) {
+ release_region(smba, SMBIOSIZE);
+ return -ENOMEM;
+ }
+
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = sb800_main ? &piix4_smbus_algorithm_sb800
+ : &smbus_algorithm;
+
+ adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL);
+ if (adapdata == NULL) {
+ kfree(adap);
+ release_region(smba, SMBIOSIZE);
+ return -ENOMEM;
+ }
+
+ adapdata->smba = smba;
+ adapdata->sb800_main = sb800_main;
+ adapdata->port = port << piix4_port_shift_sb800;
+ adapdata->notify_imc = notify_imc;
+
+ /* set up the sysfs linkage to our parent device */
+ adap->dev.parent = &dev->dev;
+
+ snprintf(adap->name, sizeof(adap->name),
+ "SMBus PIIX4 adapter%s at %04x", name, smba);
+
+ i2c_set_adapdata(adap, adapdata);
+
+ retval = i2c_add_adapter(adap);
+ if (retval) {
+ kfree(adapdata);
+ kfree(adap);
+ release_region(smba, SMBIOSIZE);
+ return retval;
+ }
+
+ *padap = adap;
+ return 0;
+}
+
+static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba,
+ bool notify_imc)
+{
+ struct i2c_piix4_adapdata *adapdata;
+ int port;
+ int retval;
+
+ for (port = 0; port < PIIX4_MAX_ADAPTERS; port++) {
+ retval = piix4_add_adapter(dev, smba, true, port, notify_imc,
+ piix4_main_port_names_sb800[port],
+ &piix4_main_adapters[port]);
+ if (retval < 0)
+ goto error;
+ }
+
+ return retval;
+
+error:
+ dev_err(&dev->dev,
+ "Error setting up SB800 adapters. Unregistering!\n");
+ while (--port >= 0) {
+ adapdata = i2c_get_adapdata(piix4_main_adapters[port]);
+ if (adapdata->smba) {
+ i2c_del_adapter(piix4_main_adapters[port]);
+ kfree(adapdata);
+ kfree(piix4_main_adapters[port]);
+ piix4_main_adapters[port] = NULL;
+ }
+ }
+
+ return retval;
+}
+
+static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int retval;
+ bool is_sb800 = false;
+
+ if ((dev->vendor == PCI_VENDOR_ID_ATI &&
+ dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+ dev->revision >= 0x40) ||
+ dev->vendor == PCI_VENDOR_ID_AMD) {
+ bool notify_imc = false;
+ is_sb800 = true;
+
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) {
+ u8 imc;
+
+ /*
+ * Detect if IMC is active or not, this method is
+ * described on coreboot's AMD IMC notes
+ */
+ pci_bus_read_config_byte(dev->bus, PCI_DEVFN(0x14, 3),
+ 0x40, &imc);
+ if (imc & 0x80)
+ notify_imc = true;
+ }
+
+ /* base address location etc changed in SB800 */
+ retval = piix4_setup_sb800(dev, id, 0);
+ if (retval < 0)
+ return retval;
+
+ /*
+ * Try to register multiplexed main SMBus adapter,
+ * give up if we can't
+ */
+ retval = piix4_add_adapters_sb800(dev, retval, notify_imc);
+ if (retval < 0)
+ return retval;
+ } else {
+ retval = piix4_setup(dev, id);
+ if (retval < 0)
+ return retval;
+
+ /* Try to register main SMBus adapter, give up if we can't */
+ retval = piix4_add_adapter(dev, retval, false, 0, false, "",
+ &piix4_main_adapters[0]);
+ if (retval < 0)
+ return retval;
+ }
+
+ /* Check for auxiliary SMBus on some AMD chipsets */
+ retval = -ENODEV;
+
+ if (dev->vendor == PCI_VENDOR_ID_ATI &&
+ dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS) {
+ if (dev->revision < 0x40) {
+ retval = piix4_setup_aux(dev, id, 0x58);
+ } else {
+ /* SB800 added aux bus too */
+ retval = piix4_setup_sb800(dev, id, 1);
+ }
+ }
+
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ (dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS ||
+ dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) {
+ retval = piix4_setup_sb800(dev, id, 1);
+ }
+
+ if (retval > 0) {
+ /* Try to add the aux adapter if it exists,
+ * piix4_add_adapter will clean up if this fails */
+ piix4_add_adapter(dev, retval, false, 0, false,
+ is_sb800 ? piix4_aux_port_name_sb800 : "",
+ &piix4_aux_adapter);
+ }
+
+ return 0;
+}
+
+static void piix4_adap_remove(struct i2c_adapter *adap)
+{
+ struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+
+ if (adapdata->smba) {
+ i2c_del_adapter(adap);
+ if (adapdata->port == (0 << piix4_port_shift_sb800))
+ release_region(adapdata->smba, SMBIOSIZE);
+ kfree(adapdata);
+ kfree(adap);
+ }
+}
+
+static void piix4_remove(struct pci_dev *dev)
+{
+ int port = PIIX4_MAX_ADAPTERS;
+
+ while (--port >= 0) {
+ if (piix4_main_adapters[port]) {
+ piix4_adap_remove(piix4_main_adapters[port]);
+ piix4_main_adapters[port] = NULL;
+ }
+ }
+
+ if (piix4_aux_adapter) {
+ piix4_adap_remove(piix4_aux_adapter);
+ piix4_aux_adapter = NULL;
+ }
+}
+
+static struct pci_driver piix4_driver = {
+ .name = "piix4_smbus",
+ .id_table = piix4_ids,
+ .probe = piix4_probe,
+ .remove = piix4_remove,
+};
+
+module_pci_driver(piix4_driver);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+ "Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("PIIX4 SMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 000000000..0829cb696
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,600 @@
+/*
+ * Specific bus support for PMC-TWI compliant implementation on MSP71xx.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#define DRV_NAME "pmcmsptwi"
+
+#define MSP_TWI_SF_CLK_REG_OFFSET 0x00
+#define MSP_TWI_HS_CLK_REG_OFFSET 0x04
+#define MSP_TWI_CFG_REG_OFFSET 0x08
+#define MSP_TWI_CMD_REG_OFFSET 0x0c
+#define MSP_TWI_ADD_REG_OFFSET 0x10
+#define MSP_TWI_DAT_0_REG_OFFSET 0x14
+#define MSP_TWI_DAT_1_REG_OFFSET 0x18
+#define MSP_TWI_INT_STS_REG_OFFSET 0x1c
+#define MSP_TWI_INT_MSK_REG_OFFSET 0x20
+#define MSP_TWI_BUSY_REG_OFFSET 0x24
+
+#define MSP_TWI_INT_STS_DONE (1 << 0)
+#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1)
+#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2)
+#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3)
+#define MSP_TWI_INT_STS_BUSY (1 << 4)
+#define MSP_TWI_INT_STS_ALL 0x1f
+
+#define MSP_MAX_BYTES_PER_RW 8
+#define MSP_MAX_POLL 5
+#define MSP_POLL_DELAY 10
+#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY)
+
+/* IO Operation macros */
+#define pmcmsptwi_readl __raw_readl
+#define pmcmsptwi_writel __raw_writel
+
+/* TWI command type */
+enum pmcmsptwi_cmd_type {
+ MSP_TWI_CMD_WRITE = 0, /* Write only */
+ MSP_TWI_CMD_READ = 1, /* Read only */
+ MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */
+};
+
+/* The possible results of the xferCmd */
+enum pmcmsptwi_xfer_result {
+ MSP_TWI_XFER_OK = 0,
+ MSP_TWI_XFER_TIMEOUT,
+ MSP_TWI_XFER_BUSY,
+ MSP_TWI_XFER_DATA_COLLISION,
+ MSP_TWI_XFER_NO_RESPONSE,
+ MSP_TWI_XFER_LOST_ARBITRATION,
+};
+
+/* Corresponds to a PMCTWI clock configuration register */
+struct pmcmsptwi_clock {
+ u8 filter; /* Bits 15:12, default = 0x03 */
+ u16 clock; /* Bits 9:0, default = 0x001f */
+};
+
+struct pmcmsptwi_clockcfg {
+ struct pmcmsptwi_clock standard; /* The standard/fast clock config */
+ struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
+};
+
+/* Corresponds to the main TWI configuration register */
+struct pmcmsptwi_cfg {
+ u8 arbf; /* Bits 15:12, default=0x03 */
+ u8 nak; /* Bits 11:8, default=0x03 */
+ u8 add10; /* Bit 7, default=0x00 */
+ u8 mst_code; /* Bits 6:4, default=0x00 */
+ u8 arb; /* Bit 1, default=0x01 */
+ u8 highspeed; /* Bit 0, default=0x00 */
+};
+
+/* A single pmctwi command to issue */
+struct pmcmsptwi_cmd {
+ u16 addr; /* The slave address (7 or 10 bits) */
+ enum pmcmsptwi_cmd_type type; /* The command type */
+ u8 write_len; /* Number of bytes in the write buffer */
+ u8 read_len; /* Number of bytes in the read buffer */
+ u8 *write_data; /* Buffer of characters to send */
+ u8 *read_data; /* Buffer to fill with incoming data */
+};
+
+/* The private data */
+struct pmcmsptwi_data {
+ void __iomem *iobase; /* iomapped base for IO */
+ int irq; /* IRQ to use (0 disables) */
+ struct completion wait; /* Completion for xfer */
+ struct mutex lock; /* Used for threadsafeness */
+ enum pmcmsptwi_xfer_result last_result; /* result of last xfer */
+};
+
+/* The default settings */
+static const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
+ .standard = {
+ .filter = 0x3,
+ .clock = 0x1f,
+ },
+ .highspeed = {
+ .filter = 0x3,
+ .clock = 0x1f,
+ },
+};
+
+static const struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
+ .arbf = 0x03,
+ .nak = 0x03,
+ .add10 = 0x00,
+ .mst_code = 0x00,
+ .arb = 0x01,
+ .highspeed = 0x00,
+};
+
+static struct pmcmsptwi_data pmcmsptwi_data;
+
+static struct i2c_adapter pmcmsptwi_adapter;
+
+/* inline helper functions */
+static inline u32 pmcmsptwi_clock_to_reg(
+ const struct pmcmsptwi_clock *clock)
+{
+ return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
+}
+
+static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
+{
+ return ((cfg->arbf & 0xf) << 12) |
+ ((cfg->nak & 0xf) << 8) |
+ ((cfg->add10 & 0x1) << 7) |
+ ((cfg->mst_code & 0x7) << 4) |
+ ((cfg->arb & 0x1) << 1) |
+ (cfg->highspeed & 0x1);
+}
+
+static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
+{
+ cfg->arbf = (reg >> 12) & 0xf;
+ cfg->nak = (reg >> 8) & 0xf;
+ cfg->add10 = (reg >> 7) & 0x1;
+ cfg->mst_code = (reg >> 4) & 0x7;
+ cfg->arb = (reg >> 1) & 0x1;
+ cfg->highspeed = reg & 0x1;
+}
+
+/*
+ * Sets the current clock configuration
+ */
+static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
+ data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
+ pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
+ data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Gets the current TWI bus configuration
+ */
+static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
+ data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Sets the current TWI bus configuration
+ */
+static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
+ data->iobase + MSP_TWI_CFG_REG_OFFSET);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Parses the 'int_sts' register and returns a well-defined error code
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
+{
+ if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Lost arbitration\n");
+ return MSP_TWI_XFER_LOST_ARBITRATION;
+ } else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: No response\n");
+ return MSP_TWI_XFER_NO_RESPONSE;
+ } else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Data collision\n");
+ return MSP_TWI_XFER_DATA_COLLISION;
+ } else if (reg & MSP_TWI_INT_STS_BUSY) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Bus busy\n");
+ return MSP_TWI_XFER_BUSY;
+ }
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
+ return MSP_TWI_XFER_OK;
+}
+
+/*
+ * In interrupt mode, handle the interrupt.
+ * NOTE: Assumes data->lock is held.
+ */
+static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
+{
+ struct pmcmsptwi_data *data = ptr;
+
+ u32 reason = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
+ if (!(reason & MSP_TWI_INT_STS_DONE))
+ return IRQ_NONE;
+
+ data->last_result = pmcmsptwi_get_result(reason);
+ complete(&data->wait);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Probe for and register the device and return 0 if there is one.
+ */
+static int pmcmsptwi_probe(struct platform_device *pldev)
+{
+ struct resource *res;
+ int rc = -ENODEV;
+
+ /* get the static platform resources */
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pldev->dev, "IOMEM resource not found\n");
+ goto ret_err;
+ }
+
+ /* reserve the memory region */
+ if (!request_mem_region(res->start, resource_size(res),
+ pldev->name)) {
+ dev_err(&pldev->dev,
+ "Unable to get memory/io address region 0x%08x\n",
+ res->start);
+ rc = -EBUSY;
+ goto ret_err;
+ }
+
+ /* remap the memory */
+ pmcmsptwi_data.iobase = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!pmcmsptwi_data.iobase) {
+ dev_err(&pldev->dev,
+ "Unable to ioremap address 0x%08x\n", res->start);
+ rc = -EIO;
+ goto ret_unreserve;
+ }
+
+ /* request the irq */
+ pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
+ if (pmcmsptwi_data.irq) {
+ rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
+ IRQF_SHARED, pldev->name, &pmcmsptwi_data);
+ if (rc == 0) {
+ /*
+ * Enable 'DONE' interrupt only.
+ *
+ * If you enable all interrupts, you will get one on
+ * error and another when the operation completes.
+ * This way you only have to handle one interrupt,
+ * but you can still check all result flags.
+ */
+ pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
+ pmcmsptwi_data.iobase +
+ MSP_TWI_INT_MSK_REG_OFFSET);
+ } else {
+ dev_warn(&pldev->dev,
+ "Could not assign TWI IRQ handler "
+ "to irq %d (continuing with poll)\n",
+ pmcmsptwi_data.irq);
+ pmcmsptwi_data.irq = 0;
+ }
+ }
+
+ init_completion(&pmcmsptwi_data.wait);
+ mutex_init(&pmcmsptwi_data.lock);
+
+ pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
+ pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
+
+ printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
+
+ pmcmsptwi_adapter.dev.parent = &pldev->dev;
+ platform_set_drvdata(pldev, &pmcmsptwi_adapter);
+ i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
+
+ rc = i2c_add_adapter(&pmcmsptwi_adapter);
+ if (rc)
+ goto ret_unmap;
+
+ return 0;
+
+ret_unmap:
+ if (pmcmsptwi_data.irq) {
+ pmcmsptwi_writel(0,
+ pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+ free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+ }
+
+ iounmap(pmcmsptwi_data.iobase);
+
+ret_unreserve:
+ release_mem_region(res->start, resource_size(res));
+
+ret_err:
+ return rc;
+}
+
+/*
+ * Release the device and return 0 if there is one.
+ */
+static int pmcmsptwi_remove(struct platform_device *pldev)
+{
+ struct resource *res;
+
+ i2c_del_adapter(&pmcmsptwi_adapter);
+
+ if (pmcmsptwi_data.irq) {
+ pmcmsptwi_writel(0,
+ pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+ free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+ }
+
+ iounmap(pmcmsptwi_data.iobase);
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ return 0;
+}
+
+/*
+ * Polls the 'busy' register until the command is complete.
+ * NOTE: Assumes data->lock is held.
+ */
+static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
+{
+ int i;
+
+ for (i = 0; i < MSP_MAX_POLL; i++) {
+ u32 val = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_BUSY_REG_OFFSET);
+ if (val == 0) {
+ u32 reason = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ pmcmsptwi_writel(reason, data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ data->last_result = pmcmsptwi_get_result(reason);
+ return;
+ }
+ udelay(MSP_POLL_DELAY);
+ }
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
+ data->last_result = MSP_TWI_XFER_TIMEOUT;
+}
+
+/*
+ * Do the transfer (low level):
+ * May use interrupt-driven or polling, depending on if an IRQ is
+ * presently registered.
+ * NOTE: Assumes data->lock is held.
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
+ u32 reg, struct pmcmsptwi_data *data)
+{
+ dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
+ pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
+ if (data->irq) {
+ unsigned long timeleft = wait_for_completion_timeout(
+ &data->wait, MSP_IRQ_TIMEOUT);
+ if (timeleft == 0) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: IRQ timeout\n");
+ complete(&data->wait);
+ data->last_result = MSP_TWI_XFER_TIMEOUT;
+ }
+ } else
+ pmcmsptwi_poll_complete(data);
+
+ return data->last_result;
+}
+
+/*
+ * Helper routine, converts 'pmctwi_cmd' struct to register format
+ */
+static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
+{
+ return ((cmd->type & 0x3) << 8) |
+ (((cmd->write_len - 1) & 0x7) << 4) |
+ ((cmd->read_len - 1) & 0x7);
+}
+
+/*
+ * Do the transfer (high level)
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
+ struct pmcmsptwi_cmd *cmd,
+ struct pmcmsptwi_data *data)
+{
+ enum pmcmsptwi_xfer_result retval;
+
+ mutex_lock(&data->lock);
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Setting address to 0x%04x\n", cmd->addr);
+ pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
+
+ if (cmd->type == MSP_TWI_CMD_WRITE ||
+ cmd->type == MSP_TWI_CMD_WRITE_READ) {
+ u64 tmp = be64_to_cpup((__be64 *)cmd->write_data);
+ tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
+ dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
+ pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
+ data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
+ if (cmd->write_len > 4)
+ pmcmsptwi_writel(tmp >> 32,
+ data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
+ }
+
+ retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
+ if (retval != MSP_TWI_XFER_OK)
+ goto xfer_err;
+
+ if (cmd->type == MSP_TWI_CMD_READ ||
+ cmd->type == MSP_TWI_CMD_WRITE_READ) {
+ int i;
+ u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
+ u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
+ MSP_TWI_DAT_0_REG_OFFSET);
+ if (cmd->read_len > 4)
+ tmp |= (u64)pmcmsptwi_readl(data->iobase +
+ MSP_TWI_DAT_1_REG_OFFSET) << 32;
+ tmp &= rmsk;
+ dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
+
+ for (i = 0; i < cmd->read_len; i++)
+ cmd->read_data[i] = tmp >> i;
+ }
+
+xfer_err:
+ mutex_unlock(&data->lock);
+
+ return retval;
+}
+
+/* -- Algorithm functions -- */
+
+/*
+ * Sends an i2c command out on the adapter
+ */
+static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int num)
+{
+ struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
+ struct pmcmsptwi_cmd cmd;
+ struct pmcmsptwi_cfg oldcfg, newcfg;
+ int ret;
+
+ if (num == 2) {
+ struct i2c_msg *nextmsg = msg + 1;
+
+ cmd.type = MSP_TWI_CMD_WRITE_READ;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ cmd.read_len = nextmsg->len;
+ cmd.read_data = nextmsg->buf;
+ } else if (msg->flags & I2C_M_RD) {
+ cmd.type = MSP_TWI_CMD_READ;
+ cmd.read_len = msg->len;
+ cmd.read_data = msg->buf;
+ cmd.write_len = 0;
+ cmd.write_data = NULL;
+ } else {
+ cmd.type = MSP_TWI_CMD_WRITE;
+ cmd.read_len = 0;
+ cmd.read_data = NULL;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ }
+
+ cmd.addr = msg->addr;
+
+ if (msg->flags & I2C_M_TEN) {
+ pmcmsptwi_get_twi_config(&newcfg, data);
+ memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
+
+ /* Set the special 10-bit address flag */
+ newcfg.add10 = 1;
+
+ pmcmsptwi_set_twi_config(&newcfg, data);
+ }
+
+ /* Execute the command */
+ ret = pmcmsptwi_xfer_cmd(&cmd, data);
+
+ if (msg->flags & I2C_M_TEN)
+ pmcmsptwi_set_twi_config(&oldcfg, data);
+
+ dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n",
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
+ (ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed");
+
+ if (ret != MSP_TWI_XFER_OK) {
+ /*
+ * TODO: We could potentially loop and retry in the case
+ * of MSP_TWI_XFER_TIMEOUT.
+ */
+ return -EIO;
+ }
+
+ return num;
+}
+
+static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN,
+ .max_write_len = MSP_MAX_BYTES_PER_RW,
+ .max_read_len = MSP_MAX_BYTES_PER_RW,
+ .max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW,
+ .max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW,
+};
+
+/* -- Initialization -- */
+
+static const struct i2c_algorithm pmcmsptwi_algo = {
+ .master_xfer = pmcmsptwi_master_xfer,
+ .functionality = pmcmsptwi_i2c_func,
+};
+
+static struct i2c_adapter pmcmsptwi_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &pmcmsptwi_algo,
+ .quirks = &pmcmsptwi_i2c_quirks,
+ .name = DRV_NAME,
+};
+
+static struct platform_driver pmcmsptwi_driver = {
+ .probe = pmcmsptwi_probe,
+ .remove = pmcmsptwi_remove,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+module_platform_driver(pmcmsptwi_driver);
+
+MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
new file mode 100644
index 000000000..6e0e546ef
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -0,0 +1,792 @@
+/*
+ * Provides I2C support for Philips PNX010x/PNX4008 boards.
+ *
+ * Authors: Dennis Kovalev <dkovalev@ru.mvista.com>
+ * Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#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
+#define I2C_PNX_REGION_SIZE 0x100
+
+struct i2c_pnx_mif {
+ int ret; /* Return value */
+ int mode; /* Interface mode */
+ struct completion complete; /* I/O completion */
+ struct timer_list timer; /* Timeout */
+ u8 * buf; /* Data buffer */
+ int len; /* Length of data buffer */
+ int order; /* RX Bytes to order via TX */
+};
+
+struct i2c_pnx_algo_data {
+ void __iomem *ioaddr;
+ struct i2c_pnx_mif mif;
+ int last;
+ struct clk *clk;
+ struct i2c_adapter adapter;
+ int irq;
+ u32 timeout;
+};
+
+enum {
+ mstatus_tdi = 0x00000001,
+ mstatus_afi = 0x00000002,
+ mstatus_nai = 0x00000004,
+ mstatus_drmi = 0x00000008,
+ mstatus_active = 0x00000020,
+ mstatus_scl = 0x00000040,
+ mstatus_sda = 0x00000080,
+ mstatus_rff = 0x00000100,
+ mstatus_rfe = 0x00000200,
+ mstatus_tff = 0x00000400,
+ mstatus_tfe = 0x00000800,
+};
+
+enum {
+ mcntrl_tdie = 0x00000001,
+ mcntrl_afie = 0x00000002,
+ mcntrl_naie = 0x00000004,
+ mcntrl_drmie = 0x00000008,
+ mcntrl_drsie = 0x00000010,
+ mcntrl_rffie = 0x00000020,
+ mcntrl_daie = 0x00000040,
+ mcntrl_tffie = 0x00000080,
+ mcntrl_reset = 0x00000100,
+ mcntrl_cdbmode = 0x00000400,
+};
+
+enum {
+ rw_bit = 1 << 0,
+ start_bit = 1 << 8,
+ stop_bit = 1 << 9,
+};
+
+#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
+#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
+#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
+#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
+#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
+#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
+
+static inline int wait_timeout(struct i2c_pnx_algo_data *data)
+{
+ long timeout = data->timeout;
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(data)) & mstatus_active)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline int wait_reset(struct i2c_pnx_algo_data *data)
+{
+ long timeout = data->timeout;
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
+ mdelay(1);
+ timeout--;
+ }
+ return (timeout <= 0);
+}
+
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
+{
+ struct timer_list *timer = &alg_data->mif.timer;
+ unsigned long expires = msecs_to_jiffies(alg_data->timeout);
+
+ if (expires <= 1)
+ expires = 2;
+
+ del_timer_sync(timer);
+
+ dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
+ jiffies, expires);
+
+ timer->expires = jiffies + expires;
+
+ add_timer(timer);
+}
+
+/**
+ * i2c_pnx_start - start a device
+ * @slave_addr: slave address
+ * @adap: pointer to adapter structure
+ *
+ * Generate a START signal in the desired mode.
+ */
+static int i2c_pnx_start(unsigned char slave_addr,
+ struct i2c_pnx_algo_data *alg_data)
+{
+ dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__,
+ slave_addr, alg_data->mif.mode);
+
+ /* Check for 7 bit slave addresses only */
+ if (slave_addr & ~0x7f) {
+ dev_err(&alg_data->adapter.dev,
+ "%s: Invalid slave address %x. Only 7-bit addresses are supported\n",
+ alg_data->adapter.name, slave_addr);
+ return -EINVAL;
+ }
+
+ /* First, make sure bus is idle */
+ if (wait_timeout(alg_data)) {
+ /* Somebody else is monopolizing the bus */
+ dev_err(&alg_data->adapter.dev,
+ "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
+ alg_data->adapter.name, slave_addr,
+ ioread32(I2C_REG_CTL(alg_data)),
+ ioread32(I2C_REG_STS(alg_data)));
+ return -EBUSY;
+ } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
+ /* Sorry, we lost the bus */
+ dev_err(&alg_data->adapter.dev,
+ "%s: Arbitration failure. Slave addr = %02x\n",
+ alg_data->adapter.name, slave_addr);
+ return -EIO;
+ }
+
+ /*
+ * OK, I2C is enabled and we have the bus.
+ * Clear the current TDI and AFI status flags.
+ */
+ iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
+ I2C_REG_STS(alg_data));
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__,
+ (slave_addr << 1) | start_bit | alg_data->mif.mode);
+
+ /* Write the slave address, START bit and R/W bit */
+ iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
+ I2C_REG_TX(alg_data));
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__);
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_stop - stop a device
+ * @adap: pointer to I2C adapter structure
+ *
+ * Generate a STOP signal to terminate the master transaction.
+ */
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
+{
+ /* Only 1 msec max timeout due to interrupt context */
+ long timeout = 1000;
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ /* Write a STOP bit to TX FIFO */
+ iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
+
+ /* Wait until the STOP is seen. */
+ while (timeout > 0 &&
+ (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) {
+ /* may be called from interrupt context */
+ udelay(1);
+ timeout--;
+ }
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+}
+
+/**
+ * i2c_pnx_master_xmit - transmit data to slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Sends one byte of data to the slave
+ */
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
+{
+ u32 val;
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (alg_data->mif.len > 0) {
+ /* We still have something to talk about... */
+ val = *alg_data->mif.buf++;
+
+ if (alg_data->mif.len == 1)
+ val |= stop_bit;
+
+ alg_data->mif.len--;
+ iowrite32(val, I2C_REG_TX(alg_data));
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n",
+ __func__, val, alg_data->mif.len + 1);
+
+ if (alg_data->mif.len == 0) {
+ if (alg_data->last) {
+ /* Wait until the STOP is seen. */
+ if (wait_timeout(alg_data))
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
+ }
+ /* Disable master interrupts */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ del_timer_sync(&alg_data->mif.timer);
+
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine.\n",
+ __func__);
+
+ complete(&alg_data->mif.complete);
+ }
+ } else if (alg_data->mif.len == 0) {
+ /* zero-sized transfer */
+ i2c_pnx_stop(alg_data);
+
+ /* Disable master interrupts. */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+ ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+ I2C_REG_CTL(alg_data));
+
+ /* Stop timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Waking up xfer routine after zero-xfer.\n",
+ __func__);
+
+ complete(&alg_data->mif.complete);
+ }
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+/**
+ * i2c_pnx_master_rcv - receive data from slave
+ * @adap: pointer to I2C adapter structure
+ *
+ * Reads one byte data from the slave
+ */
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
+{
+ unsigned int val = 0;
+ u32 ctl = 0;
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ /* Check, whether there is already data,
+ * or we didn't 'ask' for it yet.
+ */
+ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
+ /* 'Asking' is done asynchronously, e.g. dummy TX of several
+ * bytes is done before the first actual RX arrives in FIFO.
+ * Therefore, ordered bytes (via TX) are counted separately.
+ */
+ if (alg_data->mif.order) {
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Write dummy data to fill Rx-fifo...\n",
+ __func__);
+
+ if (alg_data->mif.order == 1) {
+ /* Last byte, do not acknowledge next rcv. */
+ val |= stop_bit;
+
+ /*
+ * Enable interrupt RFDAIE (data in Rx fifo),
+ * and disable DRMIE (need data for Tx)
+ */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl |= mcntrl_rffie | mcntrl_daie;
+ ctl &= ~mcntrl_drmie;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ }
+
+ /*
+ * Now we'll 'ask' for data:
+ * For each byte we want to receive, we must
+ * write a (dummy) byte to the Tx-FIFO.
+ */
+ iowrite32(val, I2C_REG_TX(alg_data));
+ alg_data->mif.order--;
+ }
+ return 0;
+ }
+
+ /* Handle data. */
+ if (alg_data->mif.len > 0) {
+ val = ioread32(I2C_REG_RX(alg_data));
+ *alg_data->mif.buf++ = (u8) (val & 0xff);
+ dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n",
+ __func__, val, alg_data->mif.len);
+
+ alg_data->mif.len--;
+ if (alg_data->mif.len == 0) {
+ if (alg_data->last)
+ /* Wait until the STOP is seen. */
+ if (wait_timeout(alg_data))
+ dev_err(&alg_data->adapter.dev,
+ "The bus is still active after timeout\n");
+
+ /* Disable master interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie | mcntrl_daie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Kill timer. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ }
+ }
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ return 0;
+}
+
+static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
+{
+ struct i2c_pnx_algo_data *alg_data = dev_id;
+ u32 stat, ctl;
+
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): mstat = %x mctrl = %x, mode = %d\n",
+ __func__,
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)),
+ alg_data->mif.mode);
+ stat = ioread32(I2C_REG_STS(alg_data));
+
+ /* let's see what kind of event this is */
+ if (stat & mstatus_afi) {
+ /* We lost arbitration in the midst of a transfer */
+ alg_data->mif.ret = -EIO;
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else if (stat & mstatus_nai) {
+ /* Slave did not acknowledge, generate a STOP */
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Slave did not acknowledge, generating a STOP.\n",
+ __func__);
+ i2c_pnx_stop(alg_data);
+
+ /* Disable master interrupts. */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+ mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ /* Our return value. */
+ alg_data->mif.ret = -EIO;
+
+ /* Stop timer, to prevent timeout. */
+ del_timer_sync(&alg_data->mif.timer);
+ complete(&alg_data->mif.complete);
+ } else {
+ /*
+ * Two options:
+ * - Master Tx needs data.
+ * - There is data in the Rx-fifo
+ * The latter is only the case if we have requested for data,
+ * via a dummy write. (See 'i2c_pnx_master_rcv'.)
+ * We therefore check, as a sanity check, whether that interrupt
+ * has been enabled.
+ */
+ if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
+ if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
+ i2c_pnx_master_xmit(alg_data);
+ } else if (alg_data->mif.mode == I2C_SMBUS_READ) {
+ i2c_pnx_master_rcv(alg_data);
+ }
+ }
+ }
+
+ /* Clear TDI and AFI bits */
+ stat = ioread32(I2C_REG_STS(alg_data));
+ iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
+
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): exiting, stat = %x ctrl = %x.\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_pnx_timeout(struct timer_list *t)
+{
+ struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer);
+ u32 ctl;
+
+ dev_err(&alg_data->adapter.dev,
+ "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n",
+ ioread32(I2C_REG_STS(alg_data)),
+ ioread32(I2C_REG_CTL(alg_data)));
+
+ /* Reset master and disable interrupts */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie);
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+ ctl |= mcntrl_reset;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ wait_reset(alg_data);
+ alg_data->mif.ret = -EIO;
+ complete(&alg_data->mif.complete);
+}
+
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
+{
+ u32 stat;
+
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
+ dev_err(&alg_data->adapter.dev,
+ "%s: Bus is still active after xfer. Reset it...\n",
+ alg_data->adapter.name);
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(alg_data);
+ } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
+ /* If there is data in the fifo's after transfer,
+ * flush fifo's by reset.
+ */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(alg_data);
+ } else if (stat & mstatus_nai) {
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+ I2C_REG_CTL(alg_data));
+ wait_reset(alg_data);
+ }
+}
+
+/**
+ * i2c_pnx_xfer - generic transfer entry point
+ * @adap: pointer to I2C adapter structure
+ * @msgs: array of messages
+ * @num: number of messages
+ *
+ * Initiates the transfer
+ */
+static int
+i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *pmsg;
+ int rc = 0, completed = 0, i;
+ struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+ u32 stat;
+
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): entering: %d messages, stat = %04x.\n",
+ __func__, num, ioread32(I2C_REG_STS(alg_data)));
+
+ bus_reset_if_active(alg_data);
+
+ /* Process transactions in a loop. */
+ for (i = 0; rc >= 0 && i < num; i++) {
+ u8 addr;
+
+ pmsg = &msgs[i];
+ addr = pmsg->addr;
+
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&alg_data->adapter.dev,
+ "%s: 10 bits addr not supported!\n",
+ alg_data->adapter.name);
+ rc = -EINVAL;
+ break;
+ }
+
+ alg_data->mif.buf = pmsg->buf;
+ alg_data->mif.len = pmsg->len;
+ alg_data->mif.order = pmsg->len;
+ alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
+ I2C_SMBUS_READ : I2C_SMBUS_WRITE;
+ alg_data->mif.ret = 0;
+ alg_data->last = (i == num - 1);
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+ __func__, alg_data->mif.mode, alg_data->mif.len);
+
+ i2c_pnx_arm_timer(alg_data);
+
+ /* initialize the completion var */
+ init_completion(&alg_data->mif.complete);
+
+ /* Enable master interrupt */
+ iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie |
+ mcntrl_naie | mcntrl_drmie,
+ I2C_REG_CTL(alg_data));
+
+ /* Put start-code and slave-address on the bus. */
+ rc = i2c_pnx_start(addr, alg_data);
+ if (rc < 0)
+ break;
+
+ /* Wait for completion */
+ wait_for_completion(&alg_data->mif.complete);
+
+ if (!(rc = alg_data->mif.ret))
+ completed++;
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Complete, return code = %d.\n",
+ __func__, rc);
+
+ /* Clear TDI and AFI bits in case they are set. */
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
+ dev_dbg(&alg_data->adapter.dev,
+ "%s: TDI still set... clearing now.\n",
+ alg_data->adapter.name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
+ dev_dbg(&alg_data->adapter.dev,
+ "%s: AFI still set... clearing now.\n",
+ alg_data->adapter.name);
+ iowrite32(stat, I2C_REG_STS(alg_data));
+ }
+ }
+
+ bus_reset_if_active(alg_data);
+
+ /* Cleanup to be sure... */
+ alg_data->mif.buf = NULL;
+ alg_data->mif.len = 0;
+ alg_data->mif.order = 0;
+
+ dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
+ __func__, ioread32(I2C_REG_STS(alg_data)));
+
+ if (completed != num)
+ return ((rc < 0) ? rc : -EREMOTEIO);
+
+ return num;
+}
+
+static u32 i2c_pnx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm pnx_algorithm = {
+ .master_xfer = i2c_pnx_xfer,
+ .functionality = i2c_pnx_func,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int i2c_pnx_controller_suspend(struct device *dev)
+{
+ struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(alg_data->clk);
+
+ return 0;
+}
+
+static int i2c_pnx_controller_resume(struct device *dev)
+{
+ struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(alg_data->clk);
+}
+
+static SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
+ i2c_pnx_controller_suspend, i2c_pnx_controller_resume);
+#define PNX_I2C_PM (&i2c_pnx_pm)
+#else
+#define PNX_I2C_PM NULL
+#endif
+
+static int i2c_pnx_probe(struct platform_device *pdev)
+{
+ unsigned long tmp;
+ int ret = 0;
+ struct i2c_pnx_algo_data *alg_data;
+ unsigned long freq;
+ struct resource *res;
+ u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
+
+ alg_data = devm_kzalloc(&pdev->dev, sizeof(*alg_data), GFP_KERNEL);
+ if (!alg_data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, alg_data);
+
+ alg_data->adapter.dev.parent = &pdev->dev;
+ alg_data->adapter.algo = &pnx_algorithm;
+ alg_data->adapter.algo_data = alg_data;
+ alg_data->adapter.nr = pdev->id;
+
+ alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
+#ifdef CONFIG_OF
+ alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
+ if (pdev->dev.of_node) {
+ of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &speed);
+ /*
+ * At this point, it is planned to add an OF timeout property.
+ * As soon as there is a consensus about how to call and handle
+ * this, sth. like the following can be put here:
+ *
+ * of_property_read_u32(pdev->dev.of_node, "timeout",
+ * &alg_data->timeout);
+ */
+ }
+#endif
+ alg_data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(alg_data->clk))
+ return PTR_ERR(alg_data->clk);
+
+ timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0);
+
+ snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
+ "%s", pdev->name);
+
+ /* Register I/O resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ alg_data->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(alg_data->ioaddr))
+ return PTR_ERR(alg_data->ioaddr);
+
+ ret = clk_prepare_enable(alg_data->clk);
+ if (ret)
+ return ret;
+
+ freq = clk_get_rate(alg_data->clk);
+
+ /*
+ * Clock Divisor High This value is the number of system clocks
+ * the serial clock (SCL) will be high.
+ * For example, if the system clock period is 50 ns and the maximum
+ * desired serial period is 10000 ns (100 kHz), then CLKHI would be
+ * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value
+ * programmed into CLKHI will vary from this slightly due to
+ * variations in the output pad's rise and fall times as well as
+ * the deglitching filter length.
+ */
+
+ tmp = (freq / speed) / 2 - 2;
+ if (tmp > 0x3FF)
+ tmp = 0x3FF;
+ iowrite32(tmp, I2C_REG_CKH(alg_data));
+ iowrite32(tmp, I2C_REG_CKL(alg_data));
+
+ iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
+ if (wait_reset(alg_data)) {
+ ret = -ENODEV;
+ goto out_clock;
+ }
+ init_completion(&alg_data->mif.complete);
+
+ alg_data->irq = platform_get_irq(pdev, 0);
+ if (alg_data->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
+ ret = alg_data->irq;
+ goto out_clock;
+ }
+ ret = devm_request_irq(&pdev->dev, alg_data->irq, i2c_pnx_interrupt,
+ 0, pdev->name, alg_data);
+ if (ret)
+ goto out_clock;
+
+ /* Register this adapter with the I2C subsystem */
+ ret = i2c_add_numbered_adapter(&alg_data->adapter);
+ if (ret < 0)
+ goto out_clock;
+
+ dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
+ alg_data->adapter.name, res->start, alg_data->irq);
+
+ return 0;
+
+out_clock:
+ clk_disable_unprepare(alg_data->clk);
+ return ret;
+}
+
+static int i2c_pnx_remove(struct platform_device *pdev)
+{
+ struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&alg_data->adapter);
+ clk_disable_unprepare(alg_data->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id i2c_pnx_of_match[] = {
+ { .compatible = "nxp,pnx-i2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
+#endif
+
+static struct platform_driver i2c_pnx_driver = {
+ .driver = {
+ .name = "pnx-i2c",
+ .of_match_table = of_match_ptr(i2c_pnx_of_match),
+ .pm = PNX_I2C_PM,
+ },
+ .probe = i2c_pnx_probe,
+ .remove = i2c_pnx_remove,
+};
+
+static int __init i2c_adap_pnx_init(void)
+{
+ return platform_driver_register(&i2c_pnx_driver);
+}
+
+static void __exit i2c_adap_pnx_exit(void)
+{
+ platform_driver_unregister(&i2c_pnx_driver);
+}
+
+MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
+MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pnx-i2c");
+
+/* We need to make sure I2C is initialized before USB */
+subsys_initcall(i2c_adap_pnx_init);
+module_exit(i2c_adap_pnx_exit);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
new file mode 100644
index 000000000..f2a206752
--- /dev/null
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -0,0 +1,464 @@
+/*
+ i2c Support for Apple SMU Controller
+
+ Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
+ <benh@kernel.crashing.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <asm/prom.h>
+#include <asm/pmac_low_i2c.h>
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
+MODULE_LICENSE("GPL");
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
+ u16 addr,
+ unsigned short flags,
+ char read_write,
+ u8 command,
+ int size,
+ union i2c_smbus_data* data)
+{
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
+ int rc = 0;
+ int read = (read_write == I2C_SMBUS_READ);
+ int addrdir = (addr << 1) | read;
+ int mode, subsize, len;
+ u32 subaddr;
+ u8 *buf;
+ u8 local[2];
+
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+ mode = pmac_i2c_mode_std;
+ subsize = 0;
+ subaddr = 0;
+ } else {
+ mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+ subsize = 1;
+ subaddr = command;
+ }
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ buf = NULL;
+ len = 0;
+ break;
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ buf = &data->byte;
+ len = 1;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (!read) {
+ local[0] = data->word & 0xff;
+ local[1] = (data->word >> 8) & 0xff;
+ }
+ buf = local;
+ len = 2;
+ break;
+
+ /* Note that these are broken vs. the expected smbus API where
+ * on reads, the length is actually returned from the function,
+ * but I think the current API makes no sense and I don't want
+ * any driver that I haven't verified for correctness to go
+ * anywhere near a pmac i2c bus anyway ...
+ *
+ * I'm also not completely sure what kind of phases to do between
+ * the actual command and the data (what I am _supposed_ to do that
+ * is). For now, I assume writes are a single stream and reads have
+ * a repeat start/addr phase (but not stop in between)
+ */
+ case I2C_SMBUS_BLOCK_DATA:
+ buf = data->block;
+ len = data->block[0] + 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ buf = &data->block[1];
+ len = data->block[0];
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+ return rc;
+ }
+
+ rc = pmac_i2c_setmode(bus, mode);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ mode, rc);
+ goto bail;
+ }
+
+ rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+ if (rc) {
+ if (rc == -ENXIO)
+ dev_dbg(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, "
+ "err %d\n", addrdir >> 1, size, rc);
+ else
+ dev_err(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, "
+ "err %d\n", addrdir >> 1, size, rc);
+ goto bail;
+ }
+
+ if (size == I2C_SMBUS_WORD_DATA && read) {
+ data->word = ((u16)local[1]) << 8;
+ data->word |= local[0];
+ }
+
+ bail:
+ pmac_i2c_close(bus);
+ return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint. This driver only support single
+ * messages (for "lame i2c" transfers). Anything else should use the smbus
+ * entry point
+ */
+static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
+ int rc = 0;
+ int addrdir;
+
+ if (msgs->flags & I2C_M_TEN)
+ return -EINVAL;
+ addrdir = i2c_8bit_addr_from_msg(msgs);
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+ return rc;
+ }
+ rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ pmac_i2c_mode_std, rc);
+ goto bail;
+ }
+ rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ if (rc < 0) {
+ if (rc == -ENXIO)
+ dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to",
+ addrdir >> 1, rc);
+ else
+ dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to",
+ addrdir >> 1, rc);
+ }
+ bail:
+ pmac_i2c_close(bus);
+ return rc < 0 ? rc : 1;
+}
+
+static u32 i2c_powermac_func(struct i2c_adapter * adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
+}
+
+/* For now, we only handle smbus */
+static const struct i2c_algorithm i2c_powermac_algorithm = {
+ .smbus_xfer = i2c_powermac_smbus_xfer,
+ .master_xfer = i2c_powermac_master_xfer,
+ .functionality = i2c_powermac_func,
+};
+
+static const struct i2c_adapter_quirks i2c_powermac_quirks = {
+ .max_num_msgs = 1,
+};
+
+static int i2c_powermac_remove(struct platform_device *dev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(dev);
+
+ i2c_del_adapter(adapter);
+ memset(adapter, 0, sizeof(*adapter));
+
+ return 0;
+}
+
+static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
+ struct pmac_i2c_bus *bus,
+ struct device_node *node)
+{
+ const __be32 *prop;
+ int len;
+
+ /* First check for valid "reg" */
+ prop = of_get_property(node, "reg", &len);
+ if (prop && (len >= sizeof(int)))
+ return (be32_to_cpup(prop) & 0xff) >> 1;
+
+ /* Then check old-style "i2c-address" */
+ prop = of_get_property(node, "i2c-address", &len);
+ if (prop && (len >= sizeof(int)))
+ return (be32_to_cpup(prop) & 0xff) >> 1;
+
+ /* Now handle some devices with missing "reg" properties */
+ if (!strcmp(node->name, "cereal"))
+ return 0x60;
+ else if (!strcmp(node->name, "deq"))
+ return 0x34;
+
+ dev_warn(&adap->dev, "No i2c address for %pOF\n", node);
+
+ return 0xffffffff;
+}
+
+static void i2c_powermac_create_one(struct i2c_adapter *adap,
+ const char *type,
+ u32 addr)
+{
+ struct i2c_board_info info = {};
+ struct i2c_client *newdev;
+
+ strncpy(info.type, type, sizeof(info.type));
+ info.addr = addr;
+ newdev = i2c_new_device(adap, &info);
+ if (!newdev)
+ dev_err(&adap->dev,
+ "i2c-powermac: Failure to register missing %s\n",
+ type);
+}
+
+static void i2c_powermac_add_missing(struct i2c_adapter *adap,
+ struct pmac_i2c_bus *bus,
+ bool found_onyx)
+{
+ struct device_node *busnode = pmac_i2c_get_bus_node(bus);
+ int rc;
+
+ /* Check for the onyx audio codec */
+#define ONYX_REG_CONTROL 67
+ if (of_device_is_compatible(busnode, "k2-i2c") && !found_onyx) {
+ union i2c_smbus_data data;
+
+ rc = i2c_smbus_xfer(adap, 0x46, 0, I2C_SMBUS_READ,
+ ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,
+ &data);
+ if (rc >= 0)
+ i2c_powermac_create_one(adap, "MAC,pcm3052", 0x46);
+
+ rc = i2c_smbus_xfer(adap, 0x47, 0, I2C_SMBUS_READ,
+ ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,
+ &data);
+ if (rc >= 0)
+ i2c_powermac_create_one(adap, "MAC,pcm3052", 0x47);
+ }
+}
+
+static bool i2c_powermac_get_type(struct i2c_adapter *adap,
+ struct device_node *node,
+ u32 addr, char *type, int type_size)
+{
+ char tmp[16];
+
+ /* Note: we to _NOT_ want the standard
+ * i2c drivers to match with any of our powermac stuff
+ * unless they have been specifically modified to handle
+ * it on a case by case basis. For example, for thermal
+ * control, things like lm75 etc... shall match with their
+ * corresponding windfarm drivers, _NOT_ the generic ones,
+ * so we force a prefix of AAPL, onto the modalias to
+ * make that happen
+ */
+
+ /* First try proper modalias */
+ if (of_modalias_node(node, tmp, sizeof(tmp)) >= 0) {
+ snprintf(type, type_size, "MAC,%s", tmp);
+ return true;
+ }
+
+ /* Now look for known workarounds */
+ if (!strcmp(node->name, "deq")) {
+ /* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
+ if (addr == 0x34) {
+ snprintf(type, type_size, "MAC,tas3001");
+ return true;
+ } else if (addr == 0x35) {
+ snprintf(type, type_size, "MAC,tas3004");
+ return true;
+ }
+ }
+
+ dev_err(&adap->dev, "i2c-powermac: modalias failure on %pOF\n", node);
+ return false;
+}
+
+static void i2c_powermac_register_devices(struct i2c_adapter *adap,
+ struct pmac_i2c_bus *bus)
+{
+ struct i2c_client *newdev;
+ struct device_node *node;
+ bool found_onyx = 0;
+
+ /*
+ * In some cases we end up with the via-pmu node itself, in this
+ * case we skip this function completely as the device-tree will
+ * not contain anything useful.
+ */
+ if (!strcmp(adap->dev.of_node->name, "via-pmu"))
+ return;
+
+ for_each_child_of_node(adap->dev.of_node, node) {
+ struct i2c_board_info info = {};
+ u32 addr;
+
+ /* Get address & channel */
+ addr = i2c_powermac_get_addr(adap, bus, node);
+ if (addr == 0xffffffff)
+ continue;
+
+ /* Multibus setup, check channel */
+ if (!pmac_i2c_match_adapter(node, adap))
+ continue;
+
+ dev_dbg(&adap->dev, "i2c-powermac: register %pOF\n", node);
+
+ /*
+ * Keep track of some device existence to handle
+ * workarounds later.
+ */
+ if (of_device_is_compatible(node, "pcm3052"))
+ found_onyx = true;
+
+ /* Make up a modalias */
+ if (!i2c_powermac_get_type(adap, node, addr,
+ info.type, sizeof(info.type))) {
+ continue;
+ }
+
+ /* Fill out the rest of the info structure */
+ info.addr = addr;
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+
+ newdev = i2c_new_device(adap, &info);
+ if (!newdev) {
+ dev_err(&adap->dev, "i2c-powermac: Failure to register"
+ " %pOF\n", node);
+ of_node_put(node);
+ /* We do not dispose of the interrupt mapping on
+ * purpose. It's not necessary (interrupt cannot be
+ * re-used) and somebody else might have grabbed it
+ * via direct DT lookup so let's not bother
+ */
+ continue;
+ }
+ }
+
+ /* Additional workarounds */
+ i2c_powermac_add_missing(adap, bus, found_onyx);
+}
+
+static int i2c_powermac_probe(struct platform_device *dev)
+{
+ struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev);
+ struct device_node *parent = NULL;
+ struct i2c_adapter *adapter;
+ const char *basename;
+ int rc;
+
+ if (bus == NULL)
+ return -EINVAL;
+ adapter = pmac_i2c_get_adapter(bus);
+
+ /* Ok, now we need to make up a name for the interface that will
+ * match what we used to do in the past, that is basically the
+ * controller's parent device node for keywest. PMU didn't have a
+ * naming convention and SMU has a different one
+ */
+ switch(pmac_i2c_get_type(bus)) {
+ case pmac_i2c_bus_keywest:
+ parent = of_get_parent(pmac_i2c_get_controller(bus));
+ if (parent == NULL)
+ return -EINVAL;
+ basename = parent->name;
+ break;
+ case pmac_i2c_bus_pmu:
+ basename = "pmu";
+ break;
+ case pmac_i2c_bus_smu:
+ /* This is not what we used to do but I'm fixing drivers at
+ * the same time as this change
+ */
+ basename = "smu";
+ break;
+ default:
+ return -EINVAL;
+ }
+ snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+ pmac_i2c_get_channel(bus));
+ of_node_put(parent);
+
+ platform_set_drvdata(dev, adapter);
+ adapter->algo = &i2c_powermac_algorithm;
+ adapter->quirks = &i2c_powermac_quirks;
+ i2c_set_adapdata(adapter, bus);
+ adapter->dev.parent = &dev->dev;
+
+ /* Clear of_node to skip automatic registration of i2c child nodes */
+ adapter->dev.of_node = NULL;
+ rc = i2c_add_adapter(adapter);
+ if (rc) {
+ printk(KERN_ERR "i2c-powermac: Adapter %s registration "
+ "failed\n", adapter->name);
+ memset(adapter, 0, sizeof(*adapter));
+ return rc;
+ }
+
+ printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
+
+ /* Use custom child registration due to Apple device-tree funkyness */
+ adapter->dev.of_node = dev->dev.of_node;
+ i2c_powermac_register_devices(adapter, bus);
+
+ return 0;
+}
+
+static struct platform_driver i2c_powermac_driver = {
+ .probe = i2c_powermac_probe,
+ .remove = i2c_powermac_remove,
+ .driver = {
+ .name = "i2c-powermac",
+ .bus = &platform_bus_type,
+ },
+};
+
+module_platform_driver(i2c_powermac_driver);
+
+MODULE_ALIAS("platform:i2c-powermac");
diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c
new file mode 100644
index 000000000..287088b8c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-puv3.c
@@ -0,0 +1,278 @@
+/*
+ * I2C driver for PKUnity-v3 SoC
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ * Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short poll_status(unsigned long bit)
+{
+ int loop_cntr = 1000;
+
+ if (bit & I2C_STATUS_TFNF) {
+ do {
+ udelay(10);
+ } while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0));
+ } else {
+ /* RXRDY handler */
+ do {
+ if (readl(I2C_TAR) == I2C_TAR_EEPROM)
+ msleep(20);
+ else
+ udelay(10);
+ } while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0));
+ }
+
+ return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ int i2c_reg = *buf;
+
+ /* Read data */
+ while (length--) {
+ if (!poll_status(I2C_STATUS_TFNF)) {
+ dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* send addr */
+ writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+ /* get ready to next write */
+ i2c_reg++;
+
+ /* send read CMD */
+ writel(I2C_DATACMD_READ, I2C_DATACMD);
+
+ /* wait until the Rx FIFO have available */
+ if (!poll_status(I2C_STATUS_RFNE)) {
+ dev_dbg(&adap->dev, "RXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* read the data to buf */
+ *buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK);
+ buf++;
+ }
+
+ return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ int i2c_reg = *buf;
+
+ /* Do nothing but storing the reg_num to a static variable */
+ if (i2c_reg == -1) {
+ printk(KERN_WARNING "Error i2c reg\n");
+ return -ETIMEDOUT;
+ }
+
+ if (length == 1)
+ return 0;
+
+ buf++;
+ length--;
+ while (length--) {
+ /* send addr */
+ writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+ /* send write CMD */
+ writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+ /* wait until the Rx FIFO have available */
+ msleep(20);
+
+ /* read the data to buf */
+ i2c_reg++;
+ buf++;
+ }
+
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ */
+static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+ int num)
+{
+ int i, ret;
+ unsigned char swap;
+
+ /* Disable i2c */
+ writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
+
+ /* Set the work mode and speed*/
+ writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON);
+
+ writel(pmsg->addr, I2C_TAR);
+
+ /* Enable i2c */
+ writel(I2C_ENABLE_ENABLE, I2C_ENABLE);
+
+ dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num);
+
+ for (i = 0; i < num; i++) {
+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+ pmsg->flags & I2C_M_RD ? "read" : "writ",
+ pmsg->len, pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+ if (pmsg->len && pmsg->buf) { /* sanity check */
+ if (pmsg->flags & I2C_M_RD)
+ ret = xfer_read(adap, pmsg->buf, pmsg->len);
+ else
+ ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+ if (ret)
+ return ret;
+
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+
+ /* XXX: fixup be16_to_cpu in bq27x00_battery.c */
+ if (pmsg->addr == I2C_TAR_PWIC) {
+ swap = pmsg->buf[0];
+ pmsg->buf[0] = pmsg->buf[1];
+ pmsg->buf[1] = swap;
+ }
+
+ return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 puv3_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm puv3_i2c_algorithm = {
+ .master_xfer = puv3_i2c_xfer,
+ .functionality = puv3_i2c_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int puv3_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct resource *mem;
+ int rc;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+
+ if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c"))
+ return -EBUSY;
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "can't allocate interface!\n");
+ rc = -ENOMEM;
+ goto fail_nomem;
+ }
+ snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x",
+ mem->start);
+ adapter->algo = &puv3_i2c_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+
+ platform_set_drvdata(pdev, adapter);
+
+ adapter->nr = pdev->id;
+ rc = i2c_add_numbered_adapter(adapter);
+ if (rc)
+ goto fail_add_adapter;
+
+ dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n");
+ return 0;
+
+fail_add_adapter:
+ kfree(adapter);
+fail_nomem:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return rc;
+}
+
+static int puv3_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ i2c_del_adapter(adapter);
+
+ put_device(&pdev->dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int puv3_i2c_suspend(struct device *dev)
+{
+ int poll_count;
+ /* Disable the IIC */
+ writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
+ for (poll_count = 0; poll_count < 50; poll_count++) {
+ if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE)
+ udelay(25);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL);
+#define PUV3_I2C_PM (&puv3_i2c_pm)
+
+#else
+#define PUV3_I2C_PM NULL
+#endif
+
+static struct platform_driver puv3_i2c_driver = {
+ .probe = puv3_i2c_probe,
+ .remove = puv3_i2c_remove,
+ .driver = {
+ .name = "PKUnity-v3-I2C",
+ .pm = PUV3_I2C_PM,
+ }
+};
+
+module_platform_driver(puv3_i2c_driver);
+
+MODULE_DESCRIPTION("PKUnity v3 I2C driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:puv3_i2c");
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
new file mode 100644
index 000000000..72ea8f4c6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -0,0 +1,154 @@
+/*
+ * CE4100 PCI-I2C glue code for PXA's driver
+ * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ * License: GPL v2
+ *
+ * The CE4100's I2C device is more or less the same one as found on PXA.
+ * It does not support slave mode, the register slightly moved. This PCI
+ * device provides three bars, every contains a single I2C controller.
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-pxa.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#define CE4100_PCI_I2C_DEVS 3
+
+struct ce4100_devices {
+ struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
+};
+
+static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
+{
+ struct platform_device *pdev;
+ struct i2c_pxa_platform_data pdata;
+ struct resource res[2];
+ struct device_node *child;
+ static int devnum;
+ int ret;
+
+ memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
+ memset(&res, 0, sizeof(res));
+
+ res[0].flags = IORESOURCE_MEM;
+ res[0].start = pci_resource_start(dev, bar);
+ res[0].end = pci_resource_end(dev, bar);
+
+ res[1].flags = IORESOURCE_IRQ;
+ res[1].start = dev->irq;
+ res[1].end = dev->irq;
+
+ for_each_child_of_node(dev->dev.of_node, child) {
+ const void *prop;
+ struct resource r;
+ int ret;
+
+ ret = of_address_to_resource(child, 0, &r);
+ if (ret < 0)
+ continue;
+ if (r.start != res[0].start)
+ continue;
+ if (r.end != res[0].end)
+ continue;
+ if (r.flags != res[0].flags)
+ continue;
+
+ prop = of_get_property(child, "fast-mode", NULL);
+ if (prop)
+ pdata.fast_mode = 1;
+
+ break;
+ }
+
+ if (!child) {
+ dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
+ bar);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pdev = platform_device_alloc("ce4100-i2c", devnum);
+ if (!pdev) {
+ of_node_put(child);
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdev->dev.parent = &dev->dev;
+ pdev->dev.of_node = child;
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret)
+ goto err;
+
+ ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (ret)
+ goto err;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto err;
+ devnum++;
+ return pdev;
+err:
+ platform_device_put(pdev);
+out:
+ return ERR_PTR(ret);
+}
+
+static int ce4100_i2c_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+ int i;
+ struct ce4100_devices *sds;
+
+ ret = pci_enable_device_mem(dev);
+ if (ret)
+ return ret;
+
+ if (!dev->dev.of_node) {
+ dev_err(&dev->dev, "Missing device tree node.\n");
+ return -EINVAL;
+ }
+ sds = kzalloc(sizeof(*sds), GFP_KERNEL);
+ if (!sds) {
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
+ sds->pdev[i] = add_i2c_device(dev, i);
+ if (IS_ERR(sds->pdev[i])) {
+ ret = PTR_ERR(sds->pdev[i]);
+ while (--i >= 0)
+ platform_device_unregister(sds->pdev[i]);
+ goto err_dev_add;
+ }
+ }
+ pci_set_drvdata(dev, sds);
+ return 0;
+
+err_dev_add:
+ kfree(sds);
+err_mem:
+ pci_disable_device(dev);
+ return ret;
+}
+
+static const struct pci_device_id ce4100_i2c_devices[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
+ { },
+};
+
+static struct pci_driver ce4100_i2c_driver = {
+ .driver = {
+ .suppress_bind_attrs = true,
+ },
+ .name = "ce4100_i2c",
+ .id_table = ce4100_i2c_devices,
+ .probe = ce4100_i2c_probe,
+};
+builtin_pci_driver(ce4100_i2c_driver);
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
new file mode 100644
index 000000000..c10ae4778
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -0,0 +1,1398 @@
+/*
+ * i2c_adap_pxa.c
+ *
+ * I2C adapter for the PXA I2C bus access.
+ *
+ * Copyright (C) 2002 Intrinsyc Software Inc.
+ * Copyright (C) 2004-2005 Deep Blue Solutions 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.
+ *
+ * History:
+ * Apr 2002: Initial version [CS]
+ * Jun 2002: Properly separated algo/adap [FB]
+ * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
+ * Jan 2003: added limited signal handling [Kai-Uwe Bloem]
+ * Sep 2004: Major rework to ensure efficient bus handling [RMK]
+ * Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood]
+ * Feb 2005: Rework slave mode handling [RMK]
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/i2c-pxa.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/platform_data/i2c-pxa.h>
+
+#include <asm/irq.h>
+
+struct pxa_reg_layout {
+ u32 ibmr;
+ u32 idbr;
+ u32 icr;
+ u32 isr;
+ u32 isar;
+ u32 ilcr;
+ u32 iwcr;
+ u32 fm;
+ u32 hs;
+};
+
+enum pxa_i2c_types {
+ REGS_PXA2XX,
+ REGS_PXA3XX,
+ REGS_CE4100,
+ REGS_PXA910,
+ REGS_A3700,
+};
+
+#define ICR_BUSMODE_FM (1 << 16) /* shifted fast mode for armada-3700 */
+#define ICR_BUSMODE_HS (1 << 17) /* shifted high speed mode for armada-3700 */
+
+/*
+ * I2C registers definitions
+ */
+static struct pxa_reg_layout pxa_reg_layout[] = {
+ [REGS_PXA2XX] = {
+ .ibmr = 0x00,
+ .idbr = 0x08,
+ .icr = 0x10,
+ .isr = 0x18,
+ .isar = 0x20,
+ },
+ [REGS_PXA3XX] = {
+ .ibmr = 0x00,
+ .idbr = 0x04,
+ .icr = 0x08,
+ .isr = 0x0c,
+ .isar = 0x10,
+ },
+ [REGS_CE4100] = {
+ .ibmr = 0x14,
+ .idbr = 0x0c,
+ .icr = 0x00,
+ .isr = 0x04,
+ /* no isar register */
+ },
+ [REGS_PXA910] = {
+ .ibmr = 0x00,
+ .idbr = 0x08,
+ .icr = 0x10,
+ .isr = 0x18,
+ .isar = 0x20,
+ .ilcr = 0x28,
+ .iwcr = 0x30,
+ },
+ [REGS_A3700] = {
+ .ibmr = 0x00,
+ .idbr = 0x04,
+ .icr = 0x08,
+ .isr = 0x0c,
+ .isar = 0x10,
+ .fm = ICR_BUSMODE_FM,
+ .hs = ICR_BUSMODE_HS,
+ },
+};
+
+static const struct platform_device_id i2c_pxa_id_table[] = {
+ { "pxa2xx-i2c", REGS_PXA2XX },
+ { "pxa3xx-pwri2c", REGS_PXA3XX },
+ { "ce4100-i2c", REGS_CE4100 },
+ { "pxa910-i2c", REGS_PXA910 },
+ { "armada-3700-i2c", REGS_A3700 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
+
+/*
+ * I2C bit definitions
+ */
+
+#define ICR_START (1 << 0) /* start bit */
+#define ICR_STOP (1 << 1) /* stop bit */
+#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */
+#define ICR_TB (1 << 3) /* transfer byte bit */
+#define ICR_MA (1 << 4) /* master abort */
+#define ICR_SCLE (1 << 5) /* master clock enable */
+#define ICR_IUE (1 << 6) /* unit enable */
+#define ICR_GCD (1 << 7) /* general call disable */
+#define ICR_ITEIE (1 << 8) /* enable tx interrupts */
+#define ICR_IRFIE (1 << 9) /* enable rx interrupts */
+#define ICR_BEIE (1 << 10) /* enable bus error ints */
+#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */
+#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */
+#define ICR_SADIE (1 << 13) /* slave address detected int enable */
+#define ICR_UR (1 << 14) /* unit reset */
+#define ICR_FM (1 << 15) /* fast mode */
+#define ICR_HS (1 << 16) /* High Speed mode */
+#define ICR_GPIOEN (1 << 19) /* enable GPIO mode for SCL in HS */
+
+#define ISR_RWM (1 << 0) /* read/write mode */
+#define ISR_ACKNAK (1 << 1) /* ack/nak status */
+#define ISR_UB (1 << 2) /* unit busy */
+#define ISR_IBB (1 << 3) /* bus busy */
+#define ISR_SSD (1 << 4) /* slave stop detected */
+#define ISR_ALD (1 << 5) /* arbitration loss detected */
+#define ISR_ITE (1 << 6) /* tx buffer empty */
+#define ISR_IRF (1 << 7) /* rx buffer full */
+#define ISR_GCAD (1 << 8) /* general call address detected */
+#define ISR_SAD (1 << 9) /* slave address detected */
+#define ISR_BED (1 << 10) /* bus error no ACK/NAK */
+
+/* bit field shift & mask */
+#define ILCR_SLV_SHIFT 0
+#define ILCR_SLV_MASK (0x1FF << ILCR_SLV_SHIFT)
+#define ILCR_FLV_SHIFT 9
+#define ILCR_FLV_MASK (0x1FF << ILCR_FLV_SHIFT)
+#define ILCR_HLVL_SHIFT 18
+#define ILCR_HLVL_MASK (0x1FF << ILCR_HLVL_SHIFT)
+#define ILCR_HLVH_SHIFT 27
+#define ILCR_HLVH_MASK (0x1F << ILCR_HLVH_SHIFT)
+
+#define IWCR_CNT_SHIFT 0
+#define IWCR_CNT_MASK (0x1F << IWCR_CNT_SHIFT)
+#define IWCR_HS_CNT1_SHIFT 5
+#define IWCR_HS_CNT1_MASK (0x1F << IWCR_HS_CNT1_SHIFT)
+#define IWCR_HS_CNT2_SHIFT 10
+#define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT)
+
+struct pxa_i2c {
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int msg_idx;
+ unsigned int msg_ptr;
+ unsigned int slave_addr;
+ unsigned int req_slave_addr;
+
+ struct i2c_adapter adap;
+ struct clk *clk;
+#ifdef CONFIG_I2C_PXA_SLAVE
+ struct i2c_slave_client *slave;
+#endif
+
+ unsigned int irqlogidx;
+ u32 isrlog[32];
+ u32 icrlog[32];
+
+ void __iomem *reg_base;
+ void __iomem *reg_ibmr;
+ void __iomem *reg_idbr;
+ void __iomem *reg_icr;
+ void __iomem *reg_isr;
+ void __iomem *reg_isar;
+ void __iomem *reg_ilcr;
+ void __iomem *reg_iwcr;
+
+ unsigned long iobase;
+ unsigned long iosize;
+
+ int irq;
+ unsigned int use_pio :1;
+ unsigned int fast_mode :1;
+ unsigned int high_mode:1;
+ unsigned char master_code;
+ unsigned long rate;
+ bool highmode_enter;
+ u32 fm_mask;
+ u32 hs_mask;
+};
+
+#define _IBMR(i2c) ((i2c)->reg_ibmr)
+#define _IDBR(i2c) ((i2c)->reg_idbr)
+#define _ICR(i2c) ((i2c)->reg_icr)
+#define _ISR(i2c) ((i2c)->reg_isr)
+#define _ISAR(i2c) ((i2c)->reg_isar)
+#define _ILCR(i2c) ((i2c)->reg_ilcr)
+#define _IWCR(i2c) ((i2c)->reg_iwcr)
+
+/*
+ * I2C Slave mode address
+ */
+#define I2C_PXA_SLAVE_ADDR 0x1
+
+#ifdef DEBUG
+
+struct bits {
+ u32 mask;
+ const char *set;
+ const char *unset;
+};
+#define PXA_BIT(m, s, u) { .mask = m, .set = s, .unset = u }
+
+static inline void
+decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
+{
+ printk("%s %08x: ", prefix, val);
+ while (num--) {
+ const char *str = val & bits->mask ? bits->set : bits->unset;
+ if (str)
+ printk("%s ", str);
+ bits++;
+ }
+}
+
+static const struct bits isr_bits[] = {
+ PXA_BIT(ISR_RWM, "RX", "TX"),
+ PXA_BIT(ISR_ACKNAK, "NAK", "ACK"),
+ PXA_BIT(ISR_UB, "Bsy", "Rdy"),
+ PXA_BIT(ISR_IBB, "BusBsy", "BusRdy"),
+ PXA_BIT(ISR_SSD, "SlaveStop", NULL),
+ PXA_BIT(ISR_ALD, "ALD", NULL),
+ PXA_BIT(ISR_ITE, "TxEmpty", NULL),
+ PXA_BIT(ISR_IRF, "RxFull", NULL),
+ PXA_BIT(ISR_GCAD, "GenCall", NULL),
+ PXA_BIT(ISR_SAD, "SlaveAddr", NULL),
+ PXA_BIT(ISR_BED, "BusErr", NULL),
+};
+
+static void decode_ISR(unsigned int val)
+{
+ decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val);
+ printk("\n");
+}
+
+static const struct bits icr_bits[] = {
+ PXA_BIT(ICR_START, "START", NULL),
+ PXA_BIT(ICR_STOP, "STOP", NULL),
+ PXA_BIT(ICR_ACKNAK, "ACKNAK", NULL),
+ PXA_BIT(ICR_TB, "TB", NULL),
+ PXA_BIT(ICR_MA, "MA", NULL),
+ PXA_BIT(ICR_SCLE, "SCLE", "scle"),
+ PXA_BIT(ICR_IUE, "IUE", "iue"),
+ PXA_BIT(ICR_GCD, "GCD", NULL),
+ PXA_BIT(ICR_ITEIE, "ITEIE", NULL),
+ PXA_BIT(ICR_IRFIE, "IRFIE", NULL),
+ PXA_BIT(ICR_BEIE, "BEIE", NULL),
+ PXA_BIT(ICR_SSDIE, "SSDIE", NULL),
+ PXA_BIT(ICR_ALDIE, "ALDIE", NULL),
+ PXA_BIT(ICR_SADIE, "SADIE", NULL),
+ PXA_BIT(ICR_UR, "UR", "ur"),
+};
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static void decode_ICR(unsigned int val)
+{
+ decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val);
+ printk("\n");
+}
+#endif
+
+static unsigned int i2c_debug = DEBUG;
+
+static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
+{
+ dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno,
+ readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+}
+
+#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__)
+
+static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
+{
+ unsigned int i;
+ struct device *dev = &i2c->adap.dev;
+
+ dev_err(dev, "slave_0x%x error: %s\n",
+ i2c->req_slave_addr >> 1, why);
+ dev_err(dev, "msg_num: %d msg_idx: %d msg_ptr: %d\n",
+ i2c->msg_num, i2c->msg_idx, i2c->msg_ptr);
+ dev_err(dev, "IBMR: %08x IDBR: %08x ICR: %08x ISR: %08x\n",
+ readl(_IBMR(i2c)), readl(_IDBR(i2c)), readl(_ICR(i2c)),
+ readl(_ISR(i2c)));
+ dev_err(dev, "log:");
+ for (i = 0; i < i2c->irqlogidx; i++)
+ pr_cont(" [%03x:%05x]", i2c->isrlog[i], i2c->icrlog[i]);
+ pr_cont("\n");
+}
+
+#else /* ifdef DEBUG */
+
+#define i2c_debug 0
+
+#define show_state(i2c) do { } while (0)
+#define decode_ISR(val) do { } while (0)
+#define decode_ICR(val) do { } while (0)
+#define i2c_pxa_scream_blue_murder(i2c, why) do { } while (0)
+
+#endif /* ifdef DEBUG / else */
+
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
+
+static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
+{
+ return !(readl(_ICR(i2c)) & ICR_SCLE);
+}
+
+static void i2c_pxa_abort(struct pxa_i2c *i2c)
+{
+ int i = 250;
+
+ if (i2c_pxa_is_slavemode(i2c)) {
+ dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__);
+ return;
+ }
+
+ while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+ unsigned long icr = readl(_ICR(i2c));
+
+ icr &= ~ICR_START;
+ icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
+
+ writel(icr, _ICR(i2c));
+
+ show_state(i2c);
+
+ mdelay(1);
+ i --;
+ }
+
+ writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
+ _ICR(i2c));
+}
+
+static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
+{
+ int timeout = DEF_TIMEOUT;
+
+ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+ if ((readl(_ISR(i2c)) & ISR_SAD) != 0)
+ timeout += 4;
+
+ msleep(2);
+ show_state(i2c);
+ }
+
+ if (timeout < 0)
+ show_state(i2c);
+
+ return timeout < 0 ? I2C_RETRY : 0;
+}
+
+static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
+{
+ unsigned long timeout = jiffies + HZ*4;
+
+ while (time_before(jiffies, timeout)) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+
+ if (readl(_ISR(i2c)) & ISR_SAD) {
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__);
+ goto out;
+ }
+
+ /* wait for unit and bus being not busy, and we also do a
+ * quick check of the i2c lines themselves to ensure they've
+ * gone high...
+ */
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) {
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+ return 1;
+ }
+
+ msleep(1);
+ }
+
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+ out:
+ return 0;
+}
+
+static int i2c_pxa_set_master(struct pxa_i2c *i2c)
+{
+ if (i2c_debug)
+ dev_dbg(&i2c->adap.dev, "setting to bus master\n");
+
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) {
+ dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__);
+ if (!i2c_pxa_wait_master(i2c)) {
+ dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__);
+ return I2C_RETRY;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+ return 0;
+}
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
+{
+ unsigned long timeout = jiffies + HZ*1;
+
+ /* wait for stop */
+
+ show_state(i2c);
+
+ while (time_before(jiffies, timeout)) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+
+ if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 ||
+ (readl(_ISR(i2c)) & ISR_SAD) != 0 ||
+ (readl(_ICR(i2c)) & ICR_SCLE) == 0) {
+ if (i2c_debug > 1)
+ dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+ return 1;
+ }
+
+ msleep(1);
+ }
+
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+ return 0;
+}
+
+/*
+ * clear the hold on the bus, and take of anything else
+ * that has been configured
+ */
+static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
+{
+ show_state(i2c);
+
+ if (errcode < 0) {
+ udelay(100); /* simple delay */
+ } else {
+ /* we need to wait for the stop condition to end */
+
+ /* if we where in stop, then clear... */
+ if (readl(_ICR(i2c)) & ICR_STOP) {
+ udelay(100);
+ writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c));
+ }
+
+ if (!i2c_pxa_wait_slave(i2c)) {
+ dev_err(&i2c->adap.dev, "%s: wait timedout\n",
+ __func__);
+ return;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+
+ if (i2c_debug) {
+ dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c)));
+ decode_ICR(readl(_ICR(i2c)));
+ }
+}
+#else
+#define i2c_pxa_set_slave(i2c, err) do { } while (0)
+#endif
+
+static void i2c_pxa_reset(struct pxa_i2c *i2c)
+{
+ pr_debug("Resetting I2C Controller Unit\n");
+
+ /* abort any transfer currently under way */
+ i2c_pxa_abort(i2c);
+
+ /* reset according to 9.8 */
+ writel(ICR_UR, _ICR(i2c));
+ writel(I2C_ISR_INIT, _ISR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
+
+ if (i2c->reg_isar && IS_ENABLED(CONFIG_I2C_PXA_SLAVE))
+ writel(i2c->slave_addr, _ISAR(i2c));
+
+ /* set control register values */
+ writel(I2C_ICR_INIT | (i2c->fast_mode ? i2c->fm_mask : 0), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | (i2c->high_mode ? i2c->hs_mask : 0), _ICR(i2c));
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+ dev_info(&i2c->adap.dev, "Enabling slave mode\n");
+ writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c));
+#endif
+
+ i2c_pxa_set_slave(i2c, 0);
+
+ /* enable unit */
+ writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c));
+ udelay(100);
+}
+
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+/*
+ * PXA I2C Slave mode
+ */
+
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+ if (isr & ISR_BED) {
+ /* what should we do here? */
+ } else {
+ int ret = 0;
+
+ if (i2c->slave != NULL)
+ ret = i2c->slave->read(i2c->slave->data);
+
+ writel(ret, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */
+ }
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+ unsigned int byte = readl(_IDBR(i2c));
+
+ if (i2c->slave != NULL)
+ i2c->slave->write(i2c->slave->data, byte);
+
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+ int timeout;
+
+ if (i2c_debug > 0)
+ dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n",
+ (isr & ISR_RWM) ? 'r' : 't');
+
+ if (i2c->slave != NULL)
+ i2c->slave->event(i2c->slave->data,
+ (isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE);
+
+ /*
+ * slave could interrupt in the middle of us generating a
+ * start condition... if this happens, we'd better back off
+ * and stop holding the poor thing up
+ */
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+
+ timeout = 0x10000;
+
+ while (1) {
+ if ((readl(_IBMR(i2c)) & 2) == 2)
+ break;
+
+ timeout--;
+
+ if (timeout <= 0) {
+ dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+ break;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+ if (i2c_debug > 2)
+ dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n");
+
+ if (i2c->slave != NULL)
+ i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP);
+
+ if (i2c_debug > 2)
+ dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n");
+
+ /*
+ * If we have a master-mode message waiting,
+ * kick it off now that the slave has completed.
+ */
+ if (i2c->msg)
+ i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#else
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+ if (isr & ISR_BED) {
+ /* what should we do here? */
+ } else {
+ writel(0, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+ }
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+ int timeout;
+
+ /*
+ * slave could interrupt in the middle of us generating a
+ * start condition... if this happens, we'd better back off
+ * and stop holding the poor thing up
+ */
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
+
+ timeout = 0x10000;
+
+ while (1) {
+ if ((readl(_IBMR(i2c)) & 2) == 2)
+ break;
+
+ timeout--;
+
+ if (timeout <= 0) {
+ dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+ break;
+ }
+ }
+
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+ if (i2c->msg)
+ i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#endif
+
+/*
+ * PXA I2C Master mode
+ */
+
+static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg)
+{
+ unsigned int addr = (msg->addr & 0x7f) << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ return addr;
+}
+
+static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
+{
+ u32 icr;
+
+ /*
+ * Step 1: target slave address into IDBR
+ */
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+ i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg);
+
+ /*
+ * Step 2: initiate the write.
+ */
+ icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+ writel(icr | ICR_START | ICR_TB, _ICR(i2c));
+}
+
+static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+{
+ u32 icr;
+
+ /* Clear the START, STOP, ACK, TB and MA flags */
+ icr = readl(_ICR(i2c));
+ icr &= ~(ICR_START | ICR_STOP | ICR_ACKNAK | ICR_TB | ICR_MA);
+ writel(icr, _ICR(i2c));
+}
+
+static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
+{
+ /* make timeout the same as for interrupt based functions */
+ long timeout = 2 * DEF_TIMEOUT;
+
+ /*
+ * Wait for the bus to become free.
+ */
+ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+ udelay(1000);
+ show_state(i2c);
+ }
+
+ if (timeout < 0) {
+ show_state(i2c);
+ dev_err(&i2c->adap.dev,
+ "i2c_pxa: timeout waiting for bus free\n");
+ return I2C_RETRY;
+ }
+
+ /*
+ * Set master mode.
+ */
+ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+
+ return 0;
+}
+
+/*
+ * PXA I2C send master code
+ * 1. Load master code to IDBR and send it.
+ * Note for HS mode, set ICR [GPIOEN].
+ * 2. Wait until win arbitration.
+ */
+static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c)
+{
+ u32 icr;
+ long timeout;
+
+ spin_lock_irq(&i2c->lock);
+ i2c->highmode_enter = true;
+ writel(i2c->master_code, _IDBR(i2c));
+
+ icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+ icr |= ICR_GPIOEN | ICR_START | ICR_TB | ICR_ITEIE;
+ writel(icr, _ICR(i2c));
+
+ spin_unlock_irq(&i2c->lock);
+ timeout = wait_event_timeout(i2c->wait,
+ i2c->highmode_enter == false, HZ * 1);
+
+ i2c->highmode_enter = false;
+
+ return (timeout == 0) ? I2C_RETRY : 0;
+}
+
+static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
+ struct i2c_msg *msg, int num)
+{
+ unsigned long timeout = 500000; /* 5 seconds */
+ int ret = 0;
+
+ ret = i2c_pxa_pio_set_master(i2c);
+ if (ret)
+ goto out;
+
+ i2c->msg = msg;
+ i2c->msg_num = num;
+ i2c->msg_idx = 0;
+ i2c->msg_ptr = 0;
+ i2c->irqlogidx = 0;
+
+ i2c_pxa_start_message(i2c);
+
+ while (i2c->msg_num > 0 && --timeout) {
+ i2c_pxa_handler(0, i2c);
+ udelay(10);
+ }
+
+ i2c_pxa_stop_message(i2c);
+
+ /*
+ * We place the return code in i2c->msg_idx.
+ */
+ ret = i2c->msg_idx;
+
+out:
+ if (timeout == 0) {
+ i2c_pxa_scream_blue_murder(i2c, "timeout");
+ ret = I2C_RETRY;
+ }
+
+ return ret;
+}
+
+/*
+ * We are protected by the adapter bus mutex.
+ */
+static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
+{
+ long timeout;
+ int ret;
+
+ /*
+ * Wait for the bus to become free.
+ */
+ ret = i2c_pxa_wait_bus_not_busy(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
+ goto out;
+ }
+
+ /*
+ * Set master mode.
+ */
+ ret = i2c_pxa_set_master(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret);
+ goto out;
+ }
+
+ if (i2c->high_mode) {
+ ret = i2c_pxa_send_mastercode(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "i2c_pxa_send_mastercode timeout\n");
+ goto out;
+ }
+ }
+
+ spin_lock_irq(&i2c->lock);
+
+ i2c->msg = msg;
+ i2c->msg_num = num;
+ i2c->msg_idx = 0;
+ i2c->msg_ptr = 0;
+ i2c->irqlogidx = 0;
+
+ i2c_pxa_start_message(i2c);
+
+ spin_unlock_irq(&i2c->lock);
+
+ /*
+ * The rest of the processing occurs in the interrupt handler.
+ */
+ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+ i2c_pxa_stop_message(i2c);
+
+ /*
+ * We place the return code in i2c->msg_idx.
+ */
+ ret = i2c->msg_idx;
+
+ if (!timeout && i2c->msg_num) {
+ i2c_pxa_scream_blue_murder(i2c, "timeout");
+ ret = I2C_RETRY;
+ }
+
+ out:
+ return ret;
+}
+
+static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct pxa_i2c *i2c = adap->algo_data;
+ int ret, i;
+
+ /* If the I2C controller is disabled we need to reset it
+ (probably due to a suspend/resume destroying state). We do
+ this here as we can then avoid worrying about resuming the
+ controller before its users. */
+ if (!(readl(_ICR(i2c)) & ICR_IUE))
+ i2c_pxa_reset(i2c);
+
+ for (i = adap->retries; i >= 0; i--) {
+ ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+ if (ret != I2C_RETRY)
+ goto out;
+
+ if (i2c_debug)
+ dev_dbg(&adap->dev, "Retrying transmission\n");
+ udelay(100);
+ }
+ i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+ ret = -EREMOTEIO;
+ out:
+ i2c_pxa_set_slave(i2c, ret);
+ return ret;
+}
+
+/*
+ * i2c_pxa_master_complete - complete the message and wake up.
+ */
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
+{
+ i2c->msg_ptr = 0;
+ i2c->msg = NULL;
+ i2c->msg_idx ++;
+ i2c->msg_num = 0;
+ if (ret)
+ i2c->msg_idx = ret;
+ if (!i2c->use_pio)
+ wake_up(&i2c->wait);
+}
+
+static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+ again:
+ /*
+ * If ISR_ALD is set, we lost arbitration.
+ */
+ if (isr & ISR_ALD) {
+ /*
+ * Do we need to do anything here? The PXA docs
+ * are vague about what happens.
+ */
+ i2c_pxa_scream_blue_murder(i2c, "ALD set");
+
+ /*
+ * We ignore this error. We seem to see spurious ALDs
+ * for seemingly no reason. If we handle them as I think
+ * they should, we end up causing an I2C error, which
+ * is painful for some systems.
+ */
+ return; /* ignore */
+ }
+
+ if ((isr & ISR_BED) &&
+ (!((i2c->msg->flags & I2C_M_IGNORE_NAK) &&
+ (isr & ISR_ACKNAK)))) {
+ int ret = BUS_ERROR;
+
+ /*
+ * I2C bus error - either the device NAK'd us, or
+ * something more serious happened. If we were NAK'd
+ * on the initial address phase, we can retry.
+ */
+ if (isr & ISR_ACKNAK) {
+ if (i2c->msg_ptr == 0 && i2c->msg_idx == 0)
+ ret = I2C_RETRY;
+ else
+ ret = XFER_NAKED;
+ }
+ i2c_pxa_master_complete(i2c, ret);
+ } else if (isr & ISR_RWM) {
+ /*
+ * Read mode. We have just sent the address byte, and
+ * now we must initiate the transfer.
+ */
+ if (i2c->msg_ptr == i2c->msg->len - 1 &&
+ i2c->msg_idx == i2c->msg_num - 1)
+ icr |= ICR_STOP | ICR_ACKNAK;
+
+ icr |= ICR_ALDIE | ICR_TB;
+ } else if (i2c->msg_ptr < i2c->msg->len) {
+ /*
+ * Write mode. Write the next data byte.
+ */
+ writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c));
+
+ icr |= ICR_ALDIE | ICR_TB;
+
+ /*
+ * If this is the last byte of the last message or last byte
+ * of any message with I2C_M_STOP (e.g. SCCB), send a STOP.
+ */
+ if ((i2c->msg_ptr == i2c->msg->len) &&
+ ((i2c->msg->flags & I2C_M_STOP) ||
+ (i2c->msg_idx == i2c->msg_num - 1)))
+ icr |= ICR_STOP;
+
+ } else if (i2c->msg_idx < i2c->msg_num - 1) {
+ /*
+ * Next segment of the message.
+ */
+ i2c->msg_ptr = 0;
+ i2c->msg_idx ++;
+ i2c->msg++;
+
+ /*
+ * If we aren't doing a repeated start and address,
+ * go back and try to send the next byte. Note that
+ * we do not support switching the R/W direction here.
+ */
+ if (i2c->msg->flags & I2C_M_NOSTART)
+ goto again;
+
+ /*
+ * Write the next address.
+ */
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+ i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg);
+
+ /*
+ * And trigger a repeated start, and send the byte.
+ */
+ icr &= ~ICR_ALDIE;
+ icr |= ICR_START | ICR_TB;
+ } else {
+ if (i2c->msg->len == 0) {
+ /*
+ * Device probes have a message length of zero
+ * and need the bus to be reset before it can
+ * be used again.
+ */
+ i2c_pxa_reset(i2c);
+ }
+ i2c_pxa_master_complete(i2c, 0);
+ }
+
+ i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+ writel(icr, _ICR(i2c));
+ show_state(i2c);
+}
+
+static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+ /*
+ * Read the byte.
+ */
+ i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c));
+
+ if (i2c->msg_ptr < i2c->msg->len) {
+ /*
+ * If this is the last byte of the last
+ * message, send a STOP.
+ */
+ if (i2c->msg_ptr == i2c->msg->len - 1)
+ icr |= ICR_STOP | ICR_ACKNAK;
+
+ icr |= ICR_ALDIE | ICR_TB;
+ } else {
+ i2c_pxa_master_complete(i2c, 0);
+ }
+
+ i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+ writel(icr, _ICR(i2c));
+}
+
+#define VALID_INT_SOURCE (ISR_SSD | ISR_ALD | ISR_ITE | ISR_IRF | \
+ ISR_SAD | ISR_BED)
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
+{
+ struct pxa_i2c *i2c = dev_id;
+ u32 isr = readl(_ISR(i2c));
+
+ if (!(isr & VALID_INT_SOURCE))
+ return IRQ_NONE;
+
+ if (i2c_debug > 2 && 0) {
+ dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+ __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
+ decode_ISR(isr);
+ }
+
+ if (i2c->irqlogidx < ARRAY_SIZE(i2c->isrlog))
+ i2c->isrlog[i2c->irqlogidx++] = isr;
+
+ show_state(i2c);
+
+ /*
+ * Always clear all pending IRQs.
+ */
+ writel(isr & VALID_INT_SOURCE, _ISR(i2c));
+
+ if (isr & ISR_SAD)
+ i2c_pxa_slave_start(i2c, isr);
+ if (isr & ISR_SSD)
+ i2c_pxa_slave_stop(i2c);
+
+ if (i2c_pxa_is_slavemode(i2c)) {
+ if (isr & ISR_ITE)
+ i2c_pxa_slave_txempty(i2c, isr);
+ if (isr & ISR_IRF)
+ i2c_pxa_slave_rxfull(i2c, isr);
+ } else if (i2c->msg && (!i2c->highmode_enter)) {
+ if (isr & ISR_ITE)
+ i2c_pxa_irq_txempty(i2c, isr);
+ if (isr & ISR_IRF)
+ i2c_pxa_irq_rxfull(i2c, isr);
+ } else if ((isr & ISR_ITE) && i2c->highmode_enter) {
+ i2c->highmode_enter = false;
+ wake_up(&i2c->wait);
+ } else {
+ i2c_pxa_scream_blue_murder(i2c, "spurious irq");
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct pxa_i2c *i2c = adap->algo_data;
+ int ret, i;
+
+ for (i = adap->retries; i >= 0; i--) {
+ ret = i2c_pxa_do_xfer(i2c, msgs, num);
+ if (ret != I2C_RETRY)
+ goto out;
+
+ if (i2c_debug)
+ dev_dbg(&adap->dev, "Retrying transmission\n");
+ udelay(100);
+ }
+ i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+ ret = -EREMOTEIO;
+ out:
+ i2c_pxa_set_slave(i2c, ret);
+ return ret;
+}
+
+static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm i2c_pxa_algorithm = {
+ .master_xfer = i2c_pxa_xfer,
+ .functionality = i2c_pxa_functionality,
+};
+
+static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
+ .master_xfer = i2c_pxa_pio_xfer,
+ .functionality = i2c_pxa_functionality,
+};
+
+static const struct of_device_id i2c_pxa_dt_ids[] = {
+ { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
+ { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
+ { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 },
+ { .compatible = "marvell,armada-3700-i2c", .data = (void *)REGS_A3700 },
+ {}
+};
+MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+
+static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
+ enum pxa_i2c_types *i2c_types)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(i2c_pxa_dt_ids, &pdev->dev);
+
+ if (!of_id)
+ return 1;
+
+ /* For device tree we always use the dynamic or alias-assigned ID */
+ i2c->adap.nr = -1;
+
+ if (of_get_property(np, "mrvl,i2c-polling", NULL))
+ i2c->use_pio = 1;
+ if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
+ i2c->fast_mode = 1;
+
+ *i2c_types = (enum pxa_i2c_types)(of_id->data);
+
+ return 0;
+}
+
+static int i2c_pxa_probe_pdata(struct platform_device *pdev,
+ struct pxa_i2c *i2c,
+ enum pxa_i2c_types *i2c_types)
+{
+ struct i2c_pxa_platform_data *plat = dev_get_platdata(&pdev->dev);
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+
+ *i2c_types = id->driver_data;
+ if (plat) {
+ i2c->use_pio = plat->use_pio;
+ i2c->fast_mode = plat->fast_mode;
+ i2c->high_mode = plat->high_mode;
+ i2c->master_code = plat->master_code;
+ if (!i2c->master_code)
+ i2c->master_code = 0xe;
+ i2c->rate = plat->rate;
+ }
+ return 0;
+}
+
+static int i2c_pxa_probe(struct platform_device *dev)
+{
+ struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev);
+ enum pxa_i2c_types i2c_type;
+ struct pxa_i2c *i2c;
+ struct resource *res = NULL;
+ int ret, irq;
+
+ i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ i2c->reg_base = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(i2c->reg_base))
+ return PTR_ERR(i2c->reg_base);
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no irq resource: %d\n", irq);
+ return irq;
+ }
+
+ /* Default adapter num to device id; i2c_pxa_probe_dt can override. */
+ i2c->adap.nr = dev->id;
+
+ ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
+ if (ret > 0)
+ ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
+ if (ret < 0)
+ return ret;
+
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.retries = 5;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name));
+
+ i2c->clk = devm_clk_get(&dev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk));
+ return PTR_ERR(i2c->clk);
+ }
+
+ i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
+ i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+ i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+ i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+ i2c->fm_mask = pxa_reg_layout[i2c_type].fm ? : ICR_FM;
+ i2c->hs_mask = pxa_reg_layout[i2c_type].hs ? : ICR_HS;
+
+ if (i2c_type != REGS_CE4100)
+ i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
+
+ if (i2c_type == REGS_PXA910) {
+ i2c->reg_ilcr = i2c->reg_base + pxa_reg_layout[i2c_type].ilcr;
+ i2c->reg_iwcr = i2c->reg_base + pxa_reg_layout[i2c_type].iwcr;
+ }
+
+ i2c->iobase = res->start;
+ i2c->iosize = resource_size(res);
+
+ i2c->irq = irq;
+
+ i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+ i2c->highmode_enter = false;
+
+ if (plat) {
+#ifdef CONFIG_I2C_PXA_SLAVE
+ i2c->slave_addr = plat->slave_addr;
+ i2c->slave = plat->slave;
+#endif
+ i2c->adap.class = plat->class;
+ }
+
+ if (i2c->high_mode) {
+ if (i2c->rate) {
+ clk_set_rate(i2c->clk, i2c->rate);
+ pr_info("i2c: <%s> set rate to %ld\n",
+ i2c->adap.name, clk_get_rate(i2c->clk));
+ } else
+ pr_warn("i2c: <%s> clock rate not set\n",
+ i2c->adap.name);
+ }
+
+ clk_prepare_enable(i2c->clk);
+
+ if (i2c->use_pio) {
+ i2c->adap.algo = &i2c_pxa_pio_algorithm;
+ } else {
+ i2c->adap.algo = &i2c_pxa_algorithm;
+ ret = devm_request_irq(&dev->dev, irq, i2c_pxa_handler,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ dev_name(&dev->dev), i2c);
+ if (ret) {
+ dev_err(&dev->dev, "failed to request irq: %d\n", ret);
+ goto ereqirq;
+ }
+ }
+
+ i2c_pxa_reset(i2c);
+
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &dev->dev;
+#ifdef CONFIG_OF
+ i2c->adap.dev.of_node = dev->dev.of_node;
+#endif
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0)
+ goto ereqirq;
+
+ platform_set_drvdata(dev, i2c);
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+ dev_info(&i2c->adap.dev, " PXA I2C adapter, slave address %d\n",
+ i2c->slave_addr);
+#else
+ dev_info(&i2c->adap.dev, " PXA I2C adapter\n");
+#endif
+ return 0;
+
+ereqirq:
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int i2c_pxa_remove(struct platform_device *dev)
+{
+ struct pxa_i2c *i2c = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&i2c->adap);
+
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_pxa_suspend_noirq(struct device *dev)
+{
+ struct pxa_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_disable(i2c->clk);
+
+ return 0;
+}
+
+static int i2c_pxa_resume_noirq(struct device *dev)
+{
+ struct pxa_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_enable(i2c->clk);
+ i2c_pxa_reset(i2c);
+
+ return 0;
+}
+
+static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
+ .suspend_noirq = i2c_pxa_suspend_noirq,
+ .resume_noirq = i2c_pxa_resume_noirq,
+};
+
+#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops)
+#else
+#define I2C_PXA_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver i2c_pxa_driver = {
+ .probe = i2c_pxa_probe,
+ .remove = i2c_pxa_remove,
+ .driver = {
+ .name = "pxa2xx-i2c",
+ .pm = I2C_PXA_DEV_PM_OPS,
+ .of_match_table = i2c_pxa_dt_ids,
+ },
+ .id_table = i2c_pxa_id_table,
+};
+
+static int __init i2c_adap_pxa_init(void)
+{
+ return platform_driver_register(&i2c_pxa_driver);
+}
+
+static void __exit i2c_adap_pxa_exit(void)
+{
+ platform_driver_unregister(&i2c_pxa_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2c");
+
+subsys_initcall(i2c_adap_pxa_init);
+module_exit(i2c_adap_pxa_exit);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
new file mode 100644
index 000000000..d7329177b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/qcom-geni-se.h>
+#include <linux/spinlock.h>
+
+#define SE_I2C_TX_TRANS_LEN 0x26c
+#define SE_I2C_RX_TRANS_LEN 0x270
+#define SE_I2C_SCL_COUNTERS 0x278
+
+#define SE_I2C_ERR (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\
+ M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN)
+#define SE_I2C_ABORT BIT(1)
+
+/* M_CMD OP codes for I2C */
+#define I2C_WRITE 0x1
+#define I2C_READ 0x2
+#define I2C_WRITE_READ 0x3
+#define I2C_ADDR_ONLY 0x4
+#define I2C_BUS_CLEAR 0x6
+#define I2C_STOP_ON_BUS 0x7
+/* M_CMD params for I2C */
+#define PRE_CMD_DELAY BIT(0)
+#define TIMESTAMP_BEFORE BIT(1)
+#define STOP_STRETCH BIT(2)
+#define TIMESTAMP_AFTER BIT(3)
+#define POST_COMMAND_DELAY BIT(4)
+#define IGNORE_ADD_NACK BIT(6)
+#define READ_FINISHED_WITH_ACK BIT(7)
+#define BYPASS_ADDR_PHASE BIT(8)
+#define SLV_ADDR_MSK GENMASK(15, 9)
+#define SLV_ADDR_SHFT 9
+/* I2C SCL COUNTER fields */
+#define HIGH_COUNTER_MSK GENMASK(29, 20)
+#define HIGH_COUNTER_SHFT 20
+#define LOW_COUNTER_MSK GENMASK(19, 10)
+#define LOW_COUNTER_SHFT 10
+#define CYCLE_COUNTER_MSK GENMASK(9, 0)
+
+enum geni_i2c_err_code {
+ GP_IRQ0,
+ NACK,
+ GP_IRQ2,
+ BUS_PROTO,
+ ARB_LOST,
+ GP_IRQ5,
+ GENI_OVERRUN,
+ GENI_ILLEGAL_CMD,
+ GENI_ABORT_DONE,
+ GENI_TIMEOUT,
+};
+
+#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
+ << 5)
+
+#define I2C_AUTO_SUSPEND_DELAY 250
+#define KHZ(freq) (1000 * freq)
+#define PACKING_BYTES_PW 4
+
+#define ABORT_TIMEOUT HZ
+#define XFER_TIMEOUT HZ
+#define RST_TIMEOUT HZ
+
+struct geni_i2c_dev {
+ struct geni_se se;
+ u32 tx_wm;
+ int irq;
+ int err;
+ struct i2c_adapter adap;
+ struct completion done;
+ struct i2c_msg *cur;
+ int cur_wr;
+ int cur_rd;
+ spinlock_t lock;
+ u32 clk_freq_out;
+ const struct geni_i2c_clk_fld *clk_fld;
+ int suspended;
+};
+
+struct geni_i2c_err_log {
+ int err;
+ const char *msg;
+};
+
+static const struct geni_i2c_err_log gi2c_log[] = {
+ [GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"},
+ [NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"},
+ [GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"},
+ [BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unepxected start/stop"},
+ [ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"},
+ [GP_IRQ5] = {-EIO, "Unknown I2C err GP IRQ5"},
+ [GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"},
+ [GENI_ILLEGAL_CMD] = {-EIO, "Illegal cmd, check GENI cmd-state machine"},
+ [GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"},
+ [GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"},
+};
+
+struct geni_i2c_clk_fld {
+ u32 clk_freq_out;
+ u8 clk_div;
+ u8 t_high_cnt;
+ u8 t_low_cnt;
+ u8 t_cycle_cnt;
+};
+
+/*
+ * Hardware uses the underlying formula to calculate time periods of
+ * SCL clock cycle. Firmware uses some additional cycles excluded from the
+ * below formula and it is confirmed that the time periods are within
+ * specification limits.
+ *
+ * time of high period of SCL: t_high = (t_high_cnt * clk_div) / source_clock
+ * time of low period of SCL: t_low = (t_low_cnt * clk_div) / source_clock
+ * time of full period of SCL: t_cycle = (t_cycle_cnt * clk_div) / source_clock
+ * clk_freq_out = t / t_cycle
+ * source_clock = 19.2 MHz
+ */
+static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = {
+ {KHZ(100), 7, 10, 11, 26},
+ {KHZ(400), 2, 5, 12, 24},
+ {KHZ(1000), 1, 3, 9, 18},
+};
+
+static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
+{
+ int i;
+ const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map;
+
+ for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) {
+ if (itr->clk_freq_out == gi2c->clk_freq_out) {
+ gi2c->clk_fld = itr;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
+{
+ const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
+ u32 val;
+
+ writel_relaxed(0, gi2c->se.base + SE_GENI_CLK_SEL);
+
+ val = (itr->clk_div << CLK_DIV_SHFT) | SER_CLK_EN;
+ writel_relaxed(val, gi2c->se.base + GENI_SER_M_CLK_CFG);
+
+ val = itr->t_high_cnt << HIGH_COUNTER_SHFT;
+ val |= itr->t_low_cnt << LOW_COUNTER_SHFT;
+ val |= itr->t_cycle_cnt;
+ writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS);
+}
+
+static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c)
+{
+ u32 m_cmd = readl_relaxed(gi2c->se.base + SE_GENI_M_CMD0);
+ u32 m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
+ u32 geni_s = readl_relaxed(gi2c->se.base + SE_GENI_STATUS);
+ u32 geni_ios = readl_relaxed(gi2c->se.base + SE_GENI_IOS);
+ u32 dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
+ u32 rx_st, tx_st;
+
+ if (dma) {
+ rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
+ tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
+ } else {
+ rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
+ tx_st = readl_relaxed(gi2c->se.base + SE_GENI_TX_FIFO_STATUS);
+ }
+ dev_dbg(gi2c->se.dev, "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
+ dma, tx_st, rx_st, m_stat);
+ dev_dbg(gi2c->se.dev, "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
+ m_cmd, geni_s, geni_ios);
+}
+
+static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
+{
+ if (!gi2c->err)
+ gi2c->err = gi2c_log[err].err;
+ if (gi2c->cur)
+ dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
+ gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
+
+ if (err != NACK && err != GENI_ABORT_DONE) {
+ dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
+ geni_i2c_err_misc(gi2c);
+ }
+}
+
+static irqreturn_t geni_i2c_irq(int irq, void *dev)
+{
+ struct geni_i2c_dev *gi2c = dev;
+ int j;
+ u32 m_stat;
+ u32 rx_st;
+ u32 dm_tx_st;
+ u32 dm_rx_st;
+ u32 dma;
+ struct i2c_msg *cur;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gi2c->lock, flags);
+ m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
+ rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
+ dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
+ dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
+ dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
+ cur = gi2c->cur;
+
+ if (!cur ||
+ m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) ||
+ dm_rx_st & (DM_I2C_CB_ERR)) {
+ if (m_stat & M_GP_IRQ_1_EN)
+ geni_i2c_err(gi2c, NACK);
+ if (m_stat & M_GP_IRQ_3_EN)
+ geni_i2c_err(gi2c, BUS_PROTO);
+ if (m_stat & M_GP_IRQ_4_EN)
+ geni_i2c_err(gi2c, ARB_LOST);
+ if (m_stat & M_CMD_OVERRUN_EN)
+ geni_i2c_err(gi2c, GENI_OVERRUN);
+ if (m_stat & M_ILLEGAL_CMD_EN)
+ geni_i2c_err(gi2c, GENI_ILLEGAL_CMD);
+ if (m_stat & M_CMD_ABORT_EN)
+ geni_i2c_err(gi2c, GENI_ABORT_DONE);
+ if (m_stat & M_GP_IRQ_0_EN)
+ geni_i2c_err(gi2c, GP_IRQ0);
+
+ /* Disable the TX Watermark interrupt to stop TX */
+ if (!dma)
+ writel_relaxed(0, gi2c->se.base +
+ SE_GENI_TX_WATERMARK_REG);
+ goto irqret;
+ }
+
+ if (dma) {
+ dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n",
+ dm_tx_st, dm_rx_st);
+ goto irqret;
+ }
+
+ if (cur->flags & I2C_M_RD &&
+ m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
+ u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
+
+ for (j = 0; j < rxcnt; j++) {
+ u32 val;
+ int p = 0;
+
+ val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn);
+ while (gi2c->cur_rd < cur->len && p < sizeof(val)) {
+ cur->buf[gi2c->cur_rd++] = val & 0xff;
+ val >>= 8;
+ p++;
+ }
+ if (gi2c->cur_rd == cur->len)
+ break;
+ }
+ } else if (!(cur->flags & I2C_M_RD) &&
+ m_stat & M_TX_FIFO_WATERMARK_EN) {
+ for (j = 0; j < gi2c->tx_wm; j++) {
+ u32 temp;
+ u32 val = 0;
+ int p = 0;
+
+ while (gi2c->cur_wr < cur->len && p < sizeof(val)) {
+ temp = cur->buf[gi2c->cur_wr++];
+ val |= temp << (p * 8);
+ p++;
+ }
+ writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn);
+ /* TX Complete, Disable the TX Watermark interrupt */
+ if (gi2c->cur_wr == cur->len) {
+ writel_relaxed(0, gi2c->se.base +
+ SE_GENI_TX_WATERMARK_REG);
+ break;
+ }
+ }
+ }
+irqret:
+ if (m_stat)
+ writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR);
+
+ if (dma) {
+ if (dm_tx_st)
+ writel_relaxed(dm_tx_st, gi2c->se.base +
+ SE_DMA_TX_IRQ_CLR);
+ if (dm_rx_st)
+ writel_relaxed(dm_rx_st, gi2c->se.base +
+ SE_DMA_RX_IRQ_CLR);
+ }
+ /* if this is err with done-bit not set, handle that through timeout. */
+ if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN)
+ complete(&gi2c->done);
+ else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE)
+ complete(&gi2c->done);
+ else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
+ complete(&gi2c->done);
+
+ spin_unlock_irqrestore(&gi2c->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
+{
+ u32 val;
+ unsigned long time_left = ABORT_TIMEOUT;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gi2c->lock, flags);
+ geni_i2c_err(gi2c, GENI_TIMEOUT);
+ gi2c->cur = NULL;
+ geni_se_abort_m_cmd(&gi2c->se);
+ spin_unlock_irqrestore(&gi2c->lock, flags);
+ do {
+ time_left = wait_for_completion_timeout(&gi2c->done, time_left);
+ val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
+ } while (!(val & M_CMD_ABORT_EN) && time_left);
+
+ if (!(val & M_CMD_ABORT_EN))
+ dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
+}
+
+static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c)
+{
+ u32 val;
+ unsigned long time_left = RST_TIMEOUT;
+
+ writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST);
+ do {
+ time_left = wait_for_completion_timeout(&gi2c->done, time_left);
+ val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
+ } while (!(val & RX_RESET_DONE) && time_left);
+
+ if (!(val & RX_RESET_DONE))
+ dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n");
+}
+
+static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
+{
+ u32 val;
+ unsigned long time_left = RST_TIMEOUT;
+
+ writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST);
+ do {
+ time_left = wait_for_completion_timeout(&gi2c->done, time_left);
+ val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
+ } while (!(val & TX_RESET_DONE) && time_left);
+
+ if (!(val & TX_RESET_DONE))
+ dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
+}
+
+static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
+ u32 m_param)
+{
+ dma_addr_t rx_dma;
+ enum geni_se_xfer_mode mode;
+ unsigned long time_left = XFER_TIMEOUT;
+ void *dma_buf;
+
+ gi2c->cur = msg;
+ mode = GENI_SE_FIFO;
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
+ if (dma_buf)
+ mode = GENI_SE_DMA;
+
+ geni_se_select_mode(&gi2c->se, mode);
+ writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN);
+ geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param);
+ if (mode == GENI_SE_DMA) {
+ int ret;
+
+ ret = geni_se_rx_dma_prep(&gi2c->se, dma_buf, msg->len,
+ &rx_dma);
+ if (ret) {
+ mode = GENI_SE_FIFO;
+ geni_se_select_mode(&gi2c->se, mode);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
+ }
+ }
+
+ time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
+ if (!time_left)
+ geni_i2c_abort_xfer(gi2c);
+
+ gi2c->cur_rd = 0;
+ if (mode == GENI_SE_DMA) {
+ if (gi2c->err)
+ geni_i2c_rx_fsm_rst(gi2c);
+ geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
+ }
+ return gi2c->err;
+}
+
+static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
+ u32 m_param)
+{
+ dma_addr_t tx_dma;
+ enum geni_se_xfer_mode mode;
+ unsigned long time_left;
+ void *dma_buf;
+
+ gi2c->cur = msg;
+ mode = GENI_SE_FIFO;
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
+ if (dma_buf)
+ mode = GENI_SE_DMA;
+
+ geni_se_select_mode(&gi2c->se, mode);
+ writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN);
+ geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param);
+ if (mode == GENI_SE_DMA) {
+ int ret;
+
+ ret = geni_se_tx_dma_prep(&gi2c->se, dma_buf, msg->len,
+ &tx_dma);
+ if (ret) {
+ mode = GENI_SE_FIFO;
+ geni_se_select_mode(&gi2c->se, mode);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
+ }
+ }
+
+ if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */
+ writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG);
+
+ time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
+ if (!time_left)
+ geni_i2c_abort_xfer(gi2c);
+
+ gi2c->cur_wr = 0;
+ if (mode == GENI_SE_DMA) {
+ if (gi2c->err)
+ geni_i2c_tx_fsm_rst(gi2c);
+ geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
+ }
+ return gi2c->err;
+}
+
+static int geni_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
+ int i, ret;
+
+ gi2c->err = 0;
+ reinit_completion(&gi2c->done);
+ ret = pm_runtime_get_sync(gi2c->se.dev);
+ if (ret < 0) {
+ dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
+ pm_runtime_put_noidle(gi2c->se.dev);
+ /* Set device in suspended since resume failed */
+ pm_runtime_set_suspended(gi2c->se.dev);
+ return ret;
+ }
+
+ qcom_geni_i2c_conf(gi2c);
+ for (i = 0; i < num; i++) {
+ u32 m_param = i < (num - 1) ? STOP_STRETCH : 0;
+
+ m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
+
+ if (msgs[i].flags & I2C_M_RD)
+ ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
+ else
+ ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param);
+
+ if (ret)
+ break;
+ }
+ if (ret == 0)
+ ret = num;
+
+ pm_runtime_mark_last_busy(gi2c->se.dev);
+ pm_runtime_put_autosuspend(gi2c->se.dev);
+ gi2c->cur = NULL;
+ gi2c->err = 0;
+ return ret;
+}
+
+static u32 geni_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm geni_i2c_algo = {
+ .master_xfer = geni_i2c_xfer,
+ .functionality = geni_i2c_func,
+};
+
+static int geni_i2c_probe(struct platform_device *pdev)
+{
+ struct geni_i2c_dev *gi2c;
+ struct resource *res;
+ u32 proto, tx_depth;
+ int ret;
+
+ gi2c = devm_kzalloc(&pdev->dev, sizeof(*gi2c), GFP_KERNEL);
+ if (!gi2c)
+ return -ENOMEM;
+
+ gi2c->se.dev = &pdev->dev;
+ gi2c->se.wrapper = dev_get_drvdata(pdev->dev.parent);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gi2c->se.base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gi2c->se.base))
+ return PTR_ERR(gi2c->se.base);
+
+ gi2c->se.clk = devm_clk_get(&pdev->dev, "se");
+ if (IS_ERR(gi2c->se.clk)) {
+ ret = PTR_ERR(gi2c->se.clk);
+ dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
+ return ret;
+ }
+
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency",
+ &gi2c->clk_freq_out);
+ if (ret) {
+ dev_info(&pdev->dev,
+ "Bus frequency not specified, default to 100kHz.\n");
+ gi2c->clk_freq_out = KHZ(100);
+ }
+
+ gi2c->irq = platform_get_irq(pdev, 0);
+ if (gi2c->irq < 0) {
+ dev_err(&pdev->dev, "IRQ error for i2c-geni\n");
+ return gi2c->irq;
+ }
+
+ ret = geni_i2c_clk_map_idx(gi2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Invalid clk frequency %d Hz: %d\n",
+ gi2c->clk_freq_out, ret);
+ return ret;
+ }
+
+ gi2c->adap.algo = &geni_i2c_algo;
+ init_completion(&gi2c->done);
+ spin_lock_init(&gi2c->lock);
+ platform_set_drvdata(pdev, gi2c);
+ ret = devm_request_irq(&pdev->dev, gi2c->irq, geni_i2c_irq,
+ IRQF_TRIGGER_HIGH, "i2c_geni", gi2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Request_irq failed:%d: err:%d\n",
+ gi2c->irq, ret);
+ return ret;
+ }
+ /* Disable the interrupt so that the system can enter low-power mode */
+ disable_irq(gi2c->irq);
+ i2c_set_adapdata(&gi2c->adap, gi2c);
+ gi2c->adap.dev.parent = &pdev->dev;
+ gi2c->adap.dev.of_node = pdev->dev.of_node;
+ strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
+
+ ret = geni_se_resources_on(&gi2c->se);
+ if (ret) {
+ dev_err(&pdev->dev, "Error turning on resources %d\n", ret);
+ return ret;
+ }
+ proto = geni_se_read_proto(&gi2c->se);
+ tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
+ if (proto != GENI_SE_I2C) {
+ dev_err(&pdev->dev, "Invalid proto %d\n", proto);
+ geni_se_resources_off(&gi2c->se);
+ return -ENXIO;
+ }
+ gi2c->tx_wm = tx_depth - 1;
+ geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
+ geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW,
+ true, true, true);
+ ret = geni_se_resources_off(&gi2c->se);
+ if (ret) {
+ dev_err(&pdev->dev, "Error turning off resources %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
+
+ gi2c->suspended = 1;
+ pm_runtime_set_suspended(gi2c->se.dev);
+ pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(gi2c->se.dev);
+ pm_runtime_enable(gi2c->se.dev);
+
+ ret = i2c_add_adapter(&gi2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
+ pm_runtime_disable(gi2c->se.dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int geni_i2c_remove(struct platform_device *pdev)
+{
+ struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&gi2c->adap);
+ pm_runtime_disable(gi2c->se.dev);
+ return 0;
+}
+
+static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
+{
+ int ret;
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+
+ disable_irq(gi2c->irq);
+ ret = geni_se_resources_off(&gi2c->se);
+ if (ret) {
+ enable_irq(gi2c->irq);
+ return ret;
+
+ } else {
+ gi2c->suspended = 1;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
+{
+ int ret;
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+
+ ret = geni_se_resources_on(&gi2c->se);
+ if (ret)
+ return ret;
+
+ enable_irq(gi2c->irq);
+ gi2c->suspended = 0;
+ return 0;
+}
+
+static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
+{
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+
+ if (!gi2c->suspended) {
+ geni_i2c_runtime_suspend(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops geni_i2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, NULL)
+ SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id geni_i2c_dt_match[] = {
+ { .compatible = "qcom,geni-i2c" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
+
+static struct platform_driver geni_i2c_driver = {
+ .probe = geni_i2c_probe,
+ .remove = geni_i2c_remove,
+ .driver = {
+ .name = "geni_i2c",
+ .pm = &geni_i2c_pm_ops,
+ .of_match_table = geni_i2c_dt_match,
+ },
+};
+
+module_platform_driver(geni_i2c_driver);
+
+MODULE_DESCRIPTION("I2C Controller Driver for GENI based QUP cores");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
new file mode 100644
index 000000000..3417f7dff
--- /dev/null
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -0,0 +1,2004 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+
+/* QUP Registers */
+#define QUP_CONFIG 0x000
+#define QUP_STATE 0x004
+#define QUP_IO_MODE 0x008
+#define QUP_SW_RESET 0x00c
+#define QUP_OPERATIONAL 0x018
+#define QUP_ERROR_FLAGS 0x01c
+#define QUP_ERROR_FLAGS_EN 0x020
+#define QUP_OPERATIONAL_MASK 0x028
+#define QUP_HW_VERSION 0x030
+#define QUP_MX_OUTPUT_CNT 0x100
+#define QUP_OUT_FIFO_BASE 0x110
+#define QUP_MX_WRITE_CNT 0x150
+#define QUP_MX_INPUT_CNT 0x200
+#define QUP_MX_READ_CNT 0x208
+#define QUP_IN_FIFO_BASE 0x218
+#define QUP_I2C_CLK_CTL 0x400
+#define QUP_I2C_STATUS 0x404
+#define QUP_I2C_MASTER_GEN 0x408
+
+/* QUP States and reset values */
+#define QUP_RESET_STATE 0
+#define QUP_RUN_STATE 1
+#define QUP_PAUSE_STATE 3
+#define QUP_STATE_MASK 3
+
+#define QUP_STATE_VALID BIT(2)
+#define QUP_I2C_MAST_GEN BIT(4)
+#define QUP_I2C_FLUSH BIT(6)
+
+#define QUP_OPERATIONAL_RESET 0x000ff0
+#define QUP_I2C_STATUS_RESET 0xfffffc
+
+/* QUP OPERATIONAL FLAGS */
+#define QUP_I2C_NACK_FLAG BIT(3)
+#define QUP_OUT_NOT_EMPTY BIT(4)
+#define QUP_IN_NOT_EMPTY BIT(5)
+#define QUP_OUT_FULL BIT(6)
+#define QUP_OUT_SVC_FLAG BIT(8)
+#define QUP_IN_SVC_FLAG BIT(9)
+#define QUP_MX_OUTPUT_DONE BIT(10)
+#define QUP_MX_INPUT_DONE BIT(11)
+#define OUT_BLOCK_WRITE_REQ BIT(12)
+#define IN_BLOCK_READ_REQ BIT(13)
+
+/* I2C mini core related values */
+#define QUP_NO_INPUT BIT(7)
+#define QUP_CLOCK_AUTO_GATE BIT(13)
+#define I2C_MINI_CORE (2 << 8)
+#define I2C_N_VAL 15
+#define I2C_N_VAL_V2 7
+
+/* Most significant word offset in FIFO port */
+#define QUP_MSW_SHIFT (I2C_N_VAL + 1)
+
+/* Packing/Unpacking words in FIFOs, and IO modes */
+#define QUP_OUTPUT_BLK_MODE (1 << 10)
+#define QUP_OUTPUT_BAM_MODE (3 << 10)
+#define QUP_INPUT_BLK_MODE (1 << 12)
+#define QUP_INPUT_BAM_MODE (3 << 12)
+#define QUP_BAM_MODE (QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE)
+#define QUP_UNPACK_EN BIT(14)
+#define QUP_PACK_EN BIT(15)
+
+#define QUP_REPACK_EN (QUP_UNPACK_EN | QUP_PACK_EN)
+#define QUP_V2_TAGS_EN 1
+
+#define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
+#define QUP_OUTPUT_FIFO_SIZE(x) (((x) >> 2) & 0x07)
+#define QUP_INPUT_BLOCK_SIZE(x) (((x) >> 5) & 0x03)
+#define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07)
+
+/* QUP tags */
+#define QUP_TAG_START (1 << 8)
+#define QUP_TAG_DATA (2 << 8)
+#define QUP_TAG_STOP (3 << 8)
+#define QUP_TAG_REC (4 << 8)
+#define QUP_BAM_INPUT_EOT 0x93
+#define QUP_BAM_FLUSH_STOP 0x96
+
+/* QUP v2 tags */
+#define QUP_TAG_V2_START 0x81
+#define QUP_TAG_V2_DATAWR 0x82
+#define QUP_TAG_V2_DATAWR_STOP 0x83
+#define QUP_TAG_V2_DATARD 0x85
+#define QUP_TAG_V2_DATARD_NACK 0x86
+#define QUP_TAG_V2_DATARD_STOP 0x87
+
+/* Status, Error flags */
+#define I2C_STATUS_WR_BUFFER_FULL BIT(0)
+#define I2C_STATUS_BUS_ACTIVE BIT(8)
+#define I2C_STATUS_ERROR_MASK 0x38000fc
+#define QUP_STATUS_ERROR_FLAGS 0x7c
+
+#define QUP_READ_LIMIT 256
+#define SET_BIT 0x1
+#define RESET_BIT 0x0
+#define ONE_BYTE 0x1
+#define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31)
+
+/* Maximum transfer length for single DMA descriptor */
+#define MX_TX_RX_LEN SZ_64K
+#define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT)
+/* Maximum transfer length for all DMA descriptors */
+#define MX_DMA_TX_RX_LEN (2 * MX_TX_RX_LEN)
+#define MX_DMA_BLOCKS (MX_DMA_TX_RX_LEN / QUP_READ_LIMIT)
+
+/*
+ * Minimum transfer timeout for i2c transfers in seconds. It will be added on
+ * the top of maximum transfer time calculated from i2c bus speed to compensate
+ * the overheads.
+ */
+#define TOUT_MIN 2
+
+/* I2C Frequency Modes */
+#define I2C_STANDARD_FREQ 100000
+#define I2C_FAST_MODE_FREQ 400000
+#define I2C_FAST_MODE_PLUS_FREQ 1000000
+
+/* Default values. Use these if FW query fails */
+#define DEFAULT_CLK_FREQ I2C_STANDARD_FREQ
+#define DEFAULT_SRC_CLK 20000000
+
+/*
+ * Max tags length (start, stop and maximum 2 bytes address) for each QUP
+ * data transfer
+ */
+#define QUP_MAX_TAGS_LEN 4
+/* Max data length for each DATARD tags */
+#define RECV_MAX_DATA_LEN 254
+/* TAG length for DATA READ in RX FIFO */
+#define READ_RX_TAGS_LEN 2
+
+static unsigned int scl_freq;
+module_param_named(scl_freq, scl_freq, uint, 0444);
+MODULE_PARM_DESC(scl_freq, "SCL frequency override");
+
+/*
+ * count: no of blocks
+ * pos: current block number
+ * tx_tag_len: tx tag length for current block
+ * rx_tag_len: rx tag length for current block
+ * data_len: remaining data length for current message
+ * cur_blk_len: data length for current block
+ * total_tx_len: total tx length including tag bytes for current QUP transfer
+ * total_rx_len: total rx length including tag bytes for current QUP transfer
+ * tx_fifo_data_pos: current byte number in TX FIFO word
+ * tx_fifo_free: number of free bytes in current QUP block write.
+ * rx_fifo_data_pos: current byte number in RX FIFO word
+ * fifo_available: number of available bytes in RX FIFO for current
+ * QUP block read
+ * tx_fifo_data: QUP TX FIFO write works on word basis (4 bytes). New byte write
+ * to TX FIFO will be appended in this data and will be written to
+ * TX FIFO when all the 4 bytes are available.
+ * rx_fifo_data: QUP RX FIFO read works on word basis (4 bytes). This will
+ * contains the 4 bytes of RX data.
+ * cur_data: pointer to tell cur data position for current message
+ * cur_tx_tags: pointer to tell cur position in tags
+ * tx_tags_sent: all tx tag bytes have been written in FIFO word
+ * send_last_word: for tx FIFO, last word send is pending in current block
+ * rx_bytes_read: if all the bytes have been read from rx FIFO.
+ * rx_tags_fetched: all the rx tag bytes have been fetched from rx fifo word
+ * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
+ * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
+ * tags: contains tx tag bytes for current QUP transfer
+ */
+struct qup_i2c_block {
+ int count;
+ int pos;
+ int tx_tag_len;
+ int rx_tag_len;
+ int data_len;
+ int cur_blk_len;
+ int total_tx_len;
+ int total_rx_len;
+ int tx_fifo_data_pos;
+ int tx_fifo_free;
+ int rx_fifo_data_pos;
+ int fifo_available;
+ u32 tx_fifo_data;
+ u32 rx_fifo_data;
+ u8 *cur_data;
+ u8 *cur_tx_tags;
+ bool tx_tags_sent;
+ bool send_last_word;
+ bool rx_tags_fetched;
+ bool rx_bytes_read;
+ bool is_tx_blk_mode;
+ bool is_rx_blk_mode;
+ u8 tags[6];
+};
+
+struct qup_i2c_tag {
+ u8 *start;
+ dma_addr_t addr;
+};
+
+struct qup_i2c_bam {
+ struct qup_i2c_tag tag;
+ struct dma_chan *dma;
+ struct scatterlist *sg;
+ unsigned int sg_cnt;
+};
+
+struct qup_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ struct clk *pclk;
+ struct i2c_adapter adap;
+
+ int clk_ctl;
+ int out_fifo_sz;
+ int in_fifo_sz;
+ int out_blk_sz;
+ int in_blk_sz;
+
+ int blk_xfer_limit;
+ unsigned long one_byte_t;
+ unsigned long xfer_timeout;
+ struct qup_i2c_block blk;
+
+ struct i2c_msg *msg;
+ /* Current posion in user message buffer */
+ int pos;
+ /* I2C protocol errors */
+ u32 bus_err;
+ /* QUP core errors */
+ u32 qup_err;
+
+ /* To check if this is the last msg */
+ bool is_last;
+ bool is_smbus_read;
+
+ /* To configure when bus is in run state */
+ u32 config_run;
+
+ /* dma parameters */
+ bool is_dma;
+ /* To check if the current transfer is using DMA */
+ bool use_dma;
+ unsigned int max_xfer_sg_len;
+ unsigned int tag_buf_pos;
+ /* The threshold length above which block mode will be used */
+ unsigned int blk_mode_threshold;
+ struct dma_pool *dpool;
+ struct qup_i2c_tag start_tag;
+ struct qup_i2c_bam brx;
+ struct qup_i2c_bam btx;
+
+ struct completion xfer;
+ /* function to write data in tx fifo */
+ void (*write_tx_fifo)(struct qup_i2c_dev *qup);
+ /* function to read data from rx fifo */
+ void (*read_rx_fifo)(struct qup_i2c_dev *qup);
+ /* function to write tags in tx fifo for i2c read transfer */
+ void (*write_rx_tags)(struct qup_i2c_dev *qup);
+};
+
+static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
+{
+ struct qup_i2c_dev *qup = dev;
+ struct qup_i2c_block *blk = &qup->blk;
+ u32 bus_err;
+ u32 qup_err;
+ u32 opflags;
+
+ bus_err = readl(qup->base + QUP_I2C_STATUS);
+ qup_err = readl(qup->base + QUP_ERROR_FLAGS);
+ opflags = readl(qup->base + QUP_OPERATIONAL);
+
+ if (!qup->msg) {
+ /* Clear Error interrupt */
+ writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+ return IRQ_HANDLED;
+ }
+
+ bus_err &= I2C_STATUS_ERROR_MASK;
+ qup_err &= QUP_STATUS_ERROR_FLAGS;
+
+ /* Clear the error bits in QUP_ERROR_FLAGS */
+ if (qup_err)
+ writel(qup_err, qup->base + QUP_ERROR_FLAGS);
+
+ /* Clear the error bits in QUP_I2C_STATUS */
+ if (bus_err)
+ writel(bus_err, qup->base + QUP_I2C_STATUS);
+
+ /*
+ * Check for BAM mode and returns if already error has come for current
+ * transfer. In Error case, sometimes, QUP generates more than one
+ * interrupt.
+ */
+ if (qup->use_dma && (qup->qup_err || qup->bus_err))
+ return IRQ_HANDLED;
+
+ /* Reset the QUP State in case of error */
+ if (qup_err || bus_err) {
+ /*
+ * Don’t reset the QUP state in case of BAM mode. The BAM
+ * flush operation needs to be scheduled in transfer function
+ * which will clear the remaining schedule descriptors in BAM
+ * HW FIFO and generates the BAM interrupt.
+ */
+ if (!qup->use_dma)
+ writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+ goto done;
+ }
+
+ if (opflags & QUP_OUT_SVC_FLAG) {
+ writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+ if (opflags & OUT_BLOCK_WRITE_REQ) {
+ blk->tx_fifo_free += qup->out_blk_sz;
+ if (qup->msg->flags & I2C_M_RD)
+ qup->write_rx_tags(qup);
+ else
+ qup->write_tx_fifo(qup);
+ }
+ }
+
+ if (opflags & QUP_IN_SVC_FLAG) {
+ writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+ if (!blk->is_rx_blk_mode) {
+ blk->fifo_available += qup->in_fifo_sz;
+ qup->read_rx_fifo(qup);
+ } else if (opflags & IN_BLOCK_READ_REQ) {
+ blk->fifo_available += qup->in_blk_sz;
+ qup->read_rx_fifo(qup);
+ }
+ }
+
+ if (qup->msg->flags & I2C_M_RD) {
+ if (!blk->rx_bytes_read)
+ return IRQ_HANDLED;
+ } else {
+ /*
+ * Ideally, QUP_MAX_OUTPUT_DONE_FLAG should be checked
+ * for FIFO mode also. But, QUP_MAX_OUTPUT_DONE_FLAG lags
+ * behind QUP_OUTPUT_SERVICE_FLAG sometimes. The only reason
+ * of interrupt for write message in FIFO mode is
+ * QUP_MAX_OUTPUT_DONE_FLAG condition.
+ */
+ if (blk->is_tx_blk_mode && !(opflags & QUP_MX_OUTPUT_DONE))
+ return IRQ_HANDLED;
+ }
+
+done:
+ qup->qup_err = qup_err;
+ qup->bus_err = bus_err;
+ complete(&qup->xfer);
+ return IRQ_HANDLED;
+}
+
+static int qup_i2c_poll_state_mask(struct qup_i2c_dev *qup,
+ u32 req_state, u32 req_mask)
+{
+ int retries = 1;
+ u32 state;
+
+ /*
+ * State transition takes 3 AHB clocks cycles + 3 I2C master clock
+ * cycles. So retry once after a 1uS delay.
+ */
+ do {
+ state = readl(qup->base + QUP_STATE);
+
+ if (state & QUP_STATE_VALID &&
+ (state & req_mask) == req_state)
+ return 0;
+
+ udelay(1);
+ } while (retries--);
+
+ return -ETIMEDOUT;
+}
+
+static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
+{
+ return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
+}
+
+static void qup_i2c_flush(struct qup_i2c_dev *qup)
+{
+ u32 val = readl(qup->base + QUP_STATE);
+
+ val |= QUP_I2C_FLUSH;
+ writel(val, qup->base + QUP_STATE);
+}
+
+static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
+{
+ return qup_i2c_poll_state_mask(qup, 0, 0);
+}
+
+static int qup_i2c_poll_state_i2c_master(struct qup_i2c_dev *qup)
+{
+ return qup_i2c_poll_state_mask(qup, QUP_I2C_MAST_GEN, QUP_I2C_MAST_GEN);
+}
+
+static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
+{
+ if (qup_i2c_poll_state_valid(qup) != 0)
+ return -EIO;
+
+ writel(state, qup->base + QUP_STATE);
+
+ if (qup_i2c_poll_state(qup, state) != 0)
+ return -EIO;
+ return 0;
+}
+
+/* Check if I2C bus returns to IDLE state */
+static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
+{
+ unsigned long timeout;
+ u32 status;
+ int ret = 0;
+
+ timeout = jiffies + len * 4;
+ for (;;) {
+ status = readl(qup->base + QUP_I2C_STATUS);
+ if (!(status & I2C_STATUS_BUS_ACTIVE))
+ break;
+
+ if (time_after(jiffies, timeout))
+ ret = -ETIMEDOUT;
+
+ usleep_range(len, len * 2);
+ }
+
+ return ret;
+}
+
+static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ struct i2c_msg *msg = qup->msg;
+ u32 addr = i2c_8bit_addr_from_msg(msg);
+ u32 qup_tag;
+ int idx;
+ u32 val;
+
+ if (qup->pos == 0) {
+ val = QUP_TAG_START | addr;
+ idx = 1;
+ blk->tx_fifo_free--;
+ } else {
+ val = 0;
+ idx = 0;
+ }
+
+ while (blk->tx_fifo_free && qup->pos < msg->len) {
+ if (qup->pos == msg->len - 1)
+ qup_tag = QUP_TAG_STOP;
+ else
+ qup_tag = QUP_TAG_DATA;
+
+ if (idx & 1)
+ val |= (qup_tag | msg->buf[qup->pos]) << QUP_MSW_SHIFT;
+ else
+ val = qup_tag | msg->buf[qup->pos];
+
+ /* Write out the pair and the last odd value */
+ if (idx & 1 || qup->pos == msg->len - 1)
+ writel(val, qup->base + QUP_OUT_FIFO_BASE);
+
+ qup->pos++;
+ idx++;
+ blk->tx_fifo_free--;
+ }
+}
+
+static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
+ struct i2c_msg *msg)
+{
+ qup->blk.pos = 0;
+ qup->blk.data_len = msg->len;
+ qup->blk.count = DIV_ROUND_UP(msg->len, qup->blk_xfer_limit);
+}
+
+static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
+{
+ int data_len;
+
+ if (qup->blk.data_len > qup->blk_xfer_limit)
+ data_len = qup->blk_xfer_limit;
+ else
+ data_len = qup->blk.data_len;
+
+ return data_len;
+}
+
+static bool qup_i2c_check_msg_len(struct i2c_msg *msg)
+{
+ return ((msg->flags & I2C_M_RD) && (msg->flags & I2C_M_RECV_LEN));
+}
+
+static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
+ struct i2c_msg *msg)
+{
+ int len = 0;
+
+ if (qup->is_smbus_read) {
+ tags[len++] = QUP_TAG_V2_DATARD_STOP;
+ tags[len++] = qup_i2c_get_data_len(qup);
+ } else {
+ tags[len++] = QUP_TAG_V2_START;
+ tags[len++] = addr & 0xff;
+
+ if (msg->flags & I2C_M_TEN)
+ tags[len++] = addr >> 8;
+
+ tags[len++] = QUP_TAG_V2_DATARD;
+ /* Read 1 byte indicating the length of the SMBus message */
+ tags[len++] = 1;
+ }
+ return len;
+}
+
+static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
+ struct i2c_msg *msg)
+{
+ u16 addr = i2c_8bit_addr_from_msg(msg);
+ int len = 0;
+ int data_len;
+
+ int last = (qup->blk.pos == (qup->blk.count - 1)) && (qup->is_last);
+
+ /* Handle tags for SMBus block read */
+ if (qup_i2c_check_msg_len(msg))
+ return qup_i2c_set_tags_smb(addr, tags, qup, msg);
+
+ if (qup->blk.pos == 0) {
+ tags[len++] = QUP_TAG_V2_START;
+ tags[len++] = addr & 0xff;
+
+ if (msg->flags & I2C_M_TEN)
+ tags[len++] = addr >> 8;
+ }
+
+ /* Send _STOP commands for the last block */
+ if (last) {
+ if (msg->flags & I2C_M_RD)
+ tags[len++] = QUP_TAG_V2_DATARD_STOP;
+ else
+ tags[len++] = QUP_TAG_V2_DATAWR_STOP;
+ } else {
+ if (msg->flags & I2C_M_RD)
+ tags[len++] = qup->blk.pos == (qup->blk.count - 1) ?
+ QUP_TAG_V2_DATARD_NACK :
+ QUP_TAG_V2_DATARD;
+ else
+ tags[len++] = QUP_TAG_V2_DATAWR;
+ }
+
+ data_len = qup_i2c_get_data_len(qup);
+
+ /* 0 implies 256 bytes */
+ if (data_len == QUP_READ_LIMIT)
+ tags[len++] = 0;
+ else
+ tags[len++] = data_len;
+
+ return len;
+}
+
+
+static void qup_i2c_bam_cb(void *data)
+{
+ struct qup_i2c_dev *qup = data;
+
+ complete(&qup->xfer);
+}
+
+static int qup_sg_set_buf(struct scatterlist *sg, void *buf,
+ unsigned int buflen, struct qup_i2c_dev *qup,
+ int dir)
+{
+ int ret;
+
+ sg_set_buf(sg, buf, buflen);
+ ret = dma_map_sg(qup->dev, sg, 1, dir);
+ if (!ret)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
+{
+ if (qup->btx.dma)
+ dma_release_channel(qup->btx.dma);
+ if (qup->brx.dma)
+ dma_release_channel(qup->brx.dma);
+ qup->btx.dma = NULL;
+ qup->brx.dma = NULL;
+}
+
+static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
+{
+ int err;
+
+ if (!qup->btx.dma) {
+ qup->btx.dma = dma_request_slave_channel_reason(qup->dev, "tx");
+ if (IS_ERR(qup->btx.dma)) {
+ err = PTR_ERR(qup->btx.dma);
+ qup->btx.dma = NULL;
+ dev_err(qup->dev, "\n tx channel not available");
+ return err;
+ }
+ }
+
+ if (!qup->brx.dma) {
+ qup->brx.dma = dma_request_slave_channel_reason(qup->dev, "rx");
+ if (IS_ERR(qup->brx.dma)) {
+ dev_err(qup->dev, "\n rx channel not available");
+ err = PTR_ERR(qup->brx.dma);
+ qup->brx.dma = NULL;
+ qup_i2c_rel_dma(qup);
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+ int ret = 0, limit = QUP_READ_LIMIT;
+ u32 len = 0, blocks, rem;
+ u32 i = 0, tlen, tx_len = 0;
+ u8 *tags;
+
+ qup->blk_xfer_limit = QUP_READ_LIMIT;
+ qup_i2c_set_blk_data(qup, msg);
+
+ blocks = qup->blk.count;
+ rem = msg->len - (blocks - 1) * limit;
+
+ if (msg->flags & I2C_M_RD) {
+ while (qup->blk.pos < blocks) {
+ tlen = (i == (blocks - 1)) ? rem : limit;
+ tags = &qup->start_tag.start[qup->tag_buf_pos + len];
+ len += qup_i2c_set_tags(tags, qup, msg);
+ qup->blk.data_len -= tlen;
+
+ /* scratch buf to read the start and len tags */
+ ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
+ &qup->brx.tag.start[0],
+ 2, qup, DMA_FROM_DEVICE);
+
+ if (ret)
+ return ret;
+
+ ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
+ &msg->buf[limit * i],
+ tlen, qup,
+ DMA_FROM_DEVICE);
+ if (ret)
+ return ret;
+
+ i++;
+ qup->blk.pos = i;
+ }
+ ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
+ &qup->start_tag.start[qup->tag_buf_pos],
+ len, qup, DMA_TO_DEVICE);
+ if (ret)
+ return ret;
+
+ qup->tag_buf_pos += len;
+ } else {
+ while (qup->blk.pos < blocks) {
+ tlen = (i == (blocks - 1)) ? rem : limit;
+ tags = &qup->start_tag.start[qup->tag_buf_pos + tx_len];
+ len = qup_i2c_set_tags(tags, qup, msg);
+ qup->blk.data_len -= tlen;
+
+ ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
+ tags, len,
+ qup, DMA_TO_DEVICE);
+ if (ret)
+ return ret;
+
+ tx_len += len;
+ ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
+ &msg->buf[limit * i],
+ tlen, qup, DMA_TO_DEVICE);
+ if (ret)
+ return ret;
+ i++;
+ qup->blk.pos = i;
+ }
+
+ qup->tag_buf_pos += tx_len;
+ }
+
+ return 0;
+}
+
+static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
+{
+ struct dma_async_tx_descriptor *txd, *rxd = NULL;
+ int ret = 0;
+ dma_cookie_t cookie_rx, cookie_tx;
+ u32 len = 0;
+ u32 tx_cnt = qup->btx.sg_cnt, rx_cnt = qup->brx.sg_cnt;
+
+ /* schedule the EOT and FLUSH I2C tags */
+ len = 1;
+ if (rx_cnt) {
+ qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
+ len++;
+
+ /* scratch buf to read the BAM EOT FLUSH tags */
+ ret = qup_sg_set_buf(&qup->brx.sg[rx_cnt++],
+ &qup->brx.tag.start[0],
+ 1, qup, DMA_FROM_DEVICE);
+ if (ret)
+ return ret;
+ }
+
+ qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP;
+ ret = qup_sg_set_buf(&qup->btx.sg[tx_cnt++], &qup->btx.tag.start[0],
+ len, qup, DMA_TO_DEVICE);
+ if (ret)
+ return ret;
+
+ txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_cnt,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
+ if (!txd) {
+ dev_err(qup->dev, "failed to get tx desc\n");
+ ret = -EINVAL;
+ goto desc_err;
+ }
+
+ if (!rx_cnt) {
+ txd->callback = qup_i2c_bam_cb;
+ txd->callback_param = qup;
+ }
+
+ cookie_tx = dmaengine_submit(txd);
+ if (dma_submit_error(cookie_tx)) {
+ ret = -EINVAL;
+ goto desc_err;
+ }
+
+ dma_async_issue_pending(qup->btx.dma);
+
+ if (rx_cnt) {
+ rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg,
+ rx_cnt, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!rxd) {
+ dev_err(qup->dev, "failed to get rx desc\n");
+ ret = -EINVAL;
+
+ /* abort TX descriptors */
+ dmaengine_terminate_all(qup->btx.dma);
+ goto desc_err;
+ }
+
+ rxd->callback = qup_i2c_bam_cb;
+ rxd->callback_param = qup;
+ cookie_rx = dmaengine_submit(rxd);
+ if (dma_submit_error(cookie_rx)) {
+ ret = -EINVAL;
+ goto desc_err;
+ }
+
+ dma_async_issue_pending(qup->brx.dma);
+ }
+
+ if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) {
+ dev_err(qup->dev, "normal trans timed out\n");
+ ret = -ETIMEDOUT;
+ }
+
+ if (ret || qup->bus_err || qup->qup_err) {
+ reinit_completion(&qup->xfer);
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret) {
+ dev_err(qup->dev, "change to run state timed out");
+ goto desc_err;
+ }
+
+ qup_i2c_flush(qup);
+
+ /* wait for remaining interrupts to occur */
+ if (!wait_for_completion_timeout(&qup->xfer, HZ))
+ dev_err(qup->dev, "flush timed out\n");
+
+ ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
+ }
+
+desc_err:
+ dma_unmap_sg(qup->dev, qup->btx.sg, tx_cnt, DMA_TO_DEVICE);
+
+ if (rx_cnt)
+ dma_unmap_sg(qup->dev, qup->brx.sg, rx_cnt,
+ DMA_FROM_DEVICE);
+
+ return ret;
+}
+
+static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup)
+{
+ qup->btx.sg_cnt = 0;
+ qup->brx.sg_cnt = 0;
+ qup->tag_buf_pos = 0;
+}
+
+static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int num)
+{
+ struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+ int ret = 0;
+ int idx = 0;
+
+ enable_irq(qup->irq);
+ ret = qup_i2c_req_dma(qup);
+
+ if (ret)
+ goto out;
+
+ writel(0, qup->base + QUP_MX_INPUT_CNT);
+ writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+
+ /* set BAM mode */
+ writel(QUP_REPACK_EN | QUP_BAM_MODE, qup->base + QUP_IO_MODE);
+
+ /* mask fifo irqs */
+ writel((0x3 << 8), qup->base + QUP_OPERATIONAL_MASK);
+
+ /* set RUN STATE */
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto out;
+
+ writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+ qup_i2c_bam_clear_tag_buffers(qup);
+
+ for (idx = 0; idx < num; idx++) {
+ qup->msg = msg + idx;
+ qup->is_last = idx == (num - 1);
+
+ ret = qup_i2c_bam_make_desc(qup, qup->msg);
+ if (ret)
+ break;
+
+ /*
+ * Make DMA descriptor and schedule the BAM transfer if its
+ * already crossed the maximum length. Since the memory for all
+ * tags buffers have been taken for 2 maximum possible
+ * transfers length so it will never cross the buffer actual
+ * length.
+ */
+ if (qup->btx.sg_cnt > qup->max_xfer_sg_len ||
+ qup->brx.sg_cnt > qup->max_xfer_sg_len ||
+ qup->is_last) {
+ ret = qup_i2c_bam_schedule_desc(qup);
+ if (ret)
+ break;
+
+ qup_i2c_bam_clear_tag_buffers(qup);
+ }
+ }
+
+out:
+ disable_irq(qup->irq);
+
+ qup->msg = NULL;
+ return ret;
+}
+
+static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
+ struct i2c_msg *msg)
+{
+ unsigned long left;
+ int ret = 0;
+
+ left = wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout);
+ if (!left) {
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = -ETIMEDOUT;
+ }
+
+ if (qup->bus_err || qup->qup_err)
+ ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
+
+ return ret;
+}
+
+static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ struct i2c_msg *msg = qup->msg;
+ u32 val = 0;
+ int idx = 0;
+
+ while (blk->fifo_available && qup->pos < msg->len) {
+ if ((idx & 1) == 0) {
+ /* Reading 2 words at time */
+ val = readl(qup->base + QUP_IN_FIFO_BASE);
+ msg->buf[qup->pos++] = val & 0xFF;
+ } else {
+ msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
+ }
+ idx++;
+ blk->fifo_available--;
+ }
+
+ if (qup->pos == msg->len)
+ blk->rx_bytes_read = true;
+}
+
+static void qup_i2c_write_rx_tags_v1(struct qup_i2c_dev *qup)
+{
+ struct i2c_msg *msg = qup->msg;
+ u32 addr, len, val;
+
+ addr = i2c_8bit_addr_from_msg(msg);
+
+ /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
+ len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
+
+ val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+ writel(val, qup->base + QUP_OUT_FIFO_BASE);
+}
+
+static void qup_i2c_conf_v1(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ u32 qup_config = I2C_MINI_CORE | I2C_N_VAL;
+ u32 io_mode = QUP_REPACK_EN;
+
+ blk->is_tx_blk_mode =
+ blk->total_tx_len > qup->out_fifo_sz ? true : false;
+ blk->is_rx_blk_mode =
+ blk->total_rx_len > qup->in_fifo_sz ? true : false;
+
+ if (blk->is_tx_blk_mode) {
+ io_mode |= QUP_OUTPUT_BLK_MODE;
+ writel(0, qup->base + QUP_MX_WRITE_CNT);
+ writel(blk->total_tx_len, qup->base + QUP_MX_OUTPUT_CNT);
+ } else {
+ writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+ writel(blk->total_tx_len, qup->base + QUP_MX_WRITE_CNT);
+ }
+
+ if (blk->total_rx_len) {
+ if (blk->is_rx_blk_mode) {
+ io_mode |= QUP_INPUT_BLK_MODE;
+ writel(0, qup->base + QUP_MX_READ_CNT);
+ writel(blk->total_rx_len, qup->base + QUP_MX_INPUT_CNT);
+ } else {
+ writel(0, qup->base + QUP_MX_INPUT_CNT);
+ writel(blk->total_rx_len, qup->base + QUP_MX_READ_CNT);
+ }
+ } else {
+ qup_config |= QUP_NO_INPUT;
+ }
+
+ writel(qup_config, qup->base + QUP_CONFIG);
+ writel(io_mode, qup->base + QUP_IO_MODE);
+}
+
+static void qup_i2c_clear_blk_v1(struct qup_i2c_block *blk)
+{
+ blk->tx_fifo_free = 0;
+ blk->fifo_available = 0;
+ blk->rx_bytes_read = false;
+}
+
+static int qup_i2c_conf_xfer_v1(struct qup_i2c_dev *qup, bool is_rx)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ int ret;
+
+ qup_i2c_clear_blk_v1(blk);
+ qup_i2c_conf_v1(qup);
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ return ret;
+
+ writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+ ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+ if (ret)
+ return ret;
+
+ reinit_completion(&qup->xfer);
+ enable_irq(qup->irq);
+ if (!blk->is_tx_blk_mode) {
+ blk->tx_fifo_free = qup->out_fifo_sz;
+
+ if (is_rx)
+ qup_i2c_write_rx_tags_v1(qup);
+ else
+ qup_i2c_write_tx_fifo_v1(qup);
+ }
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto err;
+
+ ret = qup_i2c_wait_for_complete(qup, qup->msg);
+ if (ret)
+ goto err;
+
+ ret = qup_i2c_bus_active(qup, ONE_BYTE);
+
+err:
+ disable_irq(qup->irq);
+ return ret;
+}
+
+static int qup_i2c_write_one(struct qup_i2c_dev *qup)
+{
+ struct i2c_msg *msg = qup->msg;
+ struct qup_i2c_block *blk = &qup->blk;
+
+ qup->pos = 0;
+ blk->total_tx_len = msg->len + 1;
+ blk->total_rx_len = 0;
+
+ return qup_i2c_conf_xfer_v1(qup, false);
+}
+
+static int qup_i2c_read_one(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+
+ qup->pos = 0;
+ blk->total_tx_len = 2;
+ blk->total_rx_len = qup->msg->len;
+
+ return qup_i2c_conf_xfer_v1(qup, true);
+}
+
+static int qup_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+ int ret, idx;
+
+ ret = pm_runtime_get_sync(qup->dev);
+ if (ret < 0)
+ goto out;
+
+ qup->bus_err = 0;
+ qup->qup_err = 0;
+
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
+ if (ret)
+ goto out;
+
+ /* Configure QUP as I2C mini core */
+ writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+
+ for (idx = 0; idx < num; idx++) {
+ if (qup_i2c_poll_state_i2c_master(qup)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (qup_i2c_check_msg_len(&msgs[idx])) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ qup->msg = &msgs[idx];
+ if (msgs[idx].flags & I2C_M_RD)
+ ret = qup_i2c_read_one(qup);
+ else
+ ret = qup_i2c_write_one(qup);
+
+ if (ret)
+ break;
+
+ ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+ if (ret)
+ break;
+ }
+
+ if (ret == 0)
+ ret = num;
+out:
+
+ pm_runtime_mark_last_busy(qup->dev);
+ pm_runtime_put_autosuspend(qup->dev);
+
+ return ret;
+}
+
+/*
+ * Configure registers related with reconfiguration during run and call it
+ * before each i2c sub transfer.
+ */
+static void qup_i2c_conf_count_v2(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ u32 qup_config = I2C_MINI_CORE | I2C_N_VAL_V2;
+
+ if (blk->is_tx_blk_mode)
+ writel(qup->config_run | blk->total_tx_len,
+ qup->base + QUP_MX_OUTPUT_CNT);
+ else
+ writel(qup->config_run | blk->total_tx_len,
+ qup->base + QUP_MX_WRITE_CNT);
+
+ if (blk->total_rx_len) {
+ if (blk->is_rx_blk_mode)
+ writel(qup->config_run | blk->total_rx_len,
+ qup->base + QUP_MX_INPUT_CNT);
+ else
+ writel(qup->config_run | blk->total_rx_len,
+ qup->base + QUP_MX_READ_CNT);
+ } else {
+ qup_config |= QUP_NO_INPUT;
+ }
+
+ writel(qup_config, qup->base + QUP_CONFIG);
+}
+
+/*
+ * Configure registers related with transfer mode (FIFO/Block)
+ * before starting of i2c transfer. It will be called only once in
+ * QUP RESET state.
+ */
+static void qup_i2c_conf_mode_v2(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ u32 io_mode = QUP_REPACK_EN;
+
+ if (blk->is_tx_blk_mode) {
+ io_mode |= QUP_OUTPUT_BLK_MODE;
+ writel(0, qup->base + QUP_MX_WRITE_CNT);
+ } else {
+ writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+ }
+
+ if (blk->is_rx_blk_mode) {
+ io_mode |= QUP_INPUT_BLK_MODE;
+ writel(0, qup->base + QUP_MX_READ_CNT);
+ } else {
+ writel(0, qup->base + QUP_MX_INPUT_CNT);
+ }
+
+ writel(io_mode, qup->base + QUP_IO_MODE);
+}
+
+/* Clear required variables before starting of any QUP v2 sub transfer. */
+static void qup_i2c_clear_blk_v2(struct qup_i2c_block *blk)
+{
+ blk->send_last_word = false;
+ blk->tx_tags_sent = false;
+ blk->tx_fifo_data = 0;
+ blk->tx_fifo_data_pos = 0;
+ blk->tx_fifo_free = 0;
+
+ blk->rx_tags_fetched = false;
+ blk->rx_bytes_read = false;
+ blk->rx_fifo_data = 0;
+ blk->rx_fifo_data_pos = 0;
+ blk->fifo_available = 0;
+}
+
+/* Receive data from RX FIFO for read message in QUP v2 i2c transfer. */
+static void qup_i2c_recv_data(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ int j;
+
+ for (j = blk->rx_fifo_data_pos;
+ blk->cur_blk_len && blk->fifo_available;
+ blk->cur_blk_len--, blk->fifo_available--) {
+ if (j == 0)
+ blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
+
+ *(blk->cur_data++) = blk->rx_fifo_data;
+ blk->rx_fifo_data >>= 8;
+
+ if (j == 3)
+ j = 0;
+ else
+ j++;
+ }
+
+ blk->rx_fifo_data_pos = j;
+}
+
+/* Receive tags for read message in QUP v2 i2c transfer. */
+static void qup_i2c_recv_tags(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+
+ blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
+ blk->rx_fifo_data >>= blk->rx_tag_len * 8;
+ blk->rx_fifo_data_pos = blk->rx_tag_len;
+ blk->fifo_available -= blk->rx_tag_len;
+}
+
+/*
+ * Read the data and tags from RX FIFO. Since in read case, the tags will be
+ * preceded by received data bytes so
+ * 1. Check if rx_tags_fetched is false i.e. the start of QUP block so receive
+ * all tag bytes and discard that.
+ * 2. Read the data from RX FIFO. When all the data bytes have been read then
+ * set rx_bytes_read to true.
+ */
+static void qup_i2c_read_rx_fifo_v2(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+
+ if (!blk->rx_tags_fetched) {
+ qup_i2c_recv_tags(qup);
+ blk->rx_tags_fetched = true;
+ }
+
+ qup_i2c_recv_data(qup);
+ if (!blk->cur_blk_len)
+ blk->rx_bytes_read = true;
+}
+
+/*
+ * Write bytes in TX FIFO for write message in QUP v2 i2c transfer. QUP TX FIFO
+ * write works on word basis (4 bytes). Append new data byte write for TX FIFO
+ * in tx_fifo_data and write to TX FIFO when all the 4 bytes are present.
+ */
+static void
+qup_i2c_write_blk_data(struct qup_i2c_dev *qup, u8 **data, unsigned int *len)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ unsigned int j;
+
+ for (j = blk->tx_fifo_data_pos; *len && blk->tx_fifo_free;
+ (*len)--, blk->tx_fifo_free--) {
+ blk->tx_fifo_data |= *(*data)++ << (j * 8);
+ if (j == 3) {
+ writel(blk->tx_fifo_data,
+ qup->base + QUP_OUT_FIFO_BASE);
+ blk->tx_fifo_data = 0x0;
+ j = 0;
+ } else {
+ j++;
+ }
+ }
+
+ blk->tx_fifo_data_pos = j;
+}
+
+/* Transfer tags for read message in QUP v2 i2c transfer. */
+static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+
+ qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, &blk->tx_tag_len);
+ if (blk->tx_fifo_data_pos)
+ writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
+}
+
+/*
+ * Write the data and tags in TX FIFO. Since in write case, both tags and data
+ * need to be written and QUP write tags can have maximum 256 data length, so
+ *
+ * 1. Check if tx_tags_sent is false i.e. the start of QUP block so write the
+ * tags to TX FIFO and set tx_tags_sent to true.
+ * 2. Check if send_last_word is true. It will be set when last few data bytes
+ * (less than 4 bytes) are reamining to be written in FIFO because of no FIFO
+ * space. All this data bytes are available in tx_fifo_data so write this
+ * in FIFO.
+ * 3. Write the data to TX FIFO and check for cur_blk_len. If it is non zero
+ * then more data is pending otherwise following 3 cases can be possible
+ * a. if tx_fifo_data_pos is zero i.e. all the data bytes in this block
+ * have been written in TX FIFO so nothing else is required.
+ * b. tx_fifo_free is non zero i.e tx FIFO is free so copy the remaining data
+ * from tx_fifo_data to tx FIFO. Since, qup_i2c_write_blk_data do write
+ * in 4 bytes and FIFO space is in multiple of 4 bytes so tx_fifo_free
+ * will be always greater than or equal to 4 bytes.
+ * c. tx_fifo_free is zero. In this case, last few bytes (less than 4
+ * bytes) are copied to tx_fifo_data but couldn't be sent because of
+ * FIFO full so make send_last_word true.
+ */
+static void qup_i2c_write_tx_fifo_v2(struct qup_i2c_dev *qup)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+
+ if (!blk->tx_tags_sent) {
+ qup_i2c_write_blk_data(qup, &blk->cur_tx_tags,
+ &blk->tx_tag_len);
+ blk->tx_tags_sent = true;
+ }
+
+ if (blk->send_last_word)
+ goto send_last_word;
+
+ qup_i2c_write_blk_data(qup, &blk->cur_data, &blk->cur_blk_len);
+ if (!blk->cur_blk_len) {
+ if (!blk->tx_fifo_data_pos)
+ return;
+
+ if (blk->tx_fifo_free)
+ goto send_last_word;
+
+ blk->send_last_word = true;
+ }
+
+ return;
+
+send_last_word:
+ writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
+}
+
+/*
+ * Main transfer function which read or write i2c data.
+ * The QUP v2 supports reconfiguration during run in which multiple i2c sub
+ * transfers can be scheduled.
+ */
+static int
+qup_i2c_conf_xfer_v2(struct qup_i2c_dev *qup, bool is_rx, bool is_first,
+ bool change_pause_state)
+{
+ struct qup_i2c_block *blk = &qup->blk;
+ struct i2c_msg *msg = qup->msg;
+ int ret;
+
+ /*
+ * Check if its SMBus Block read for which the top level read will be
+ * done into 2 QUP reads. One with message length 1 while other one is
+ * with actual length.
+ */
+ if (qup_i2c_check_msg_len(msg)) {
+ if (qup->is_smbus_read) {
+ /*
+ * If the message length is already read in
+ * the first byte of the buffer, account for
+ * that by setting the offset
+ */
+ blk->cur_data += 1;
+ is_first = false;
+ } else {
+ change_pause_state = false;
+ }
+ }
+
+ qup->config_run = is_first ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN;
+
+ qup_i2c_clear_blk_v2(blk);
+ qup_i2c_conf_count_v2(qup);
+
+ /* If it is first sub transfer, then configure i2c bus clocks */
+ if (is_first) {
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ return ret;
+
+ writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+ ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+ if (ret)
+ return ret;
+ }
+
+ reinit_completion(&qup->xfer);
+ enable_irq(qup->irq);
+ /*
+ * In FIFO mode, tx FIFO can be written directly while in block mode the
+ * it will be written after getting OUT_BLOCK_WRITE_REQ interrupt
+ */
+ if (!blk->is_tx_blk_mode) {
+ blk->tx_fifo_free = qup->out_fifo_sz;
+
+ if (is_rx)
+ qup_i2c_write_rx_tags_v2(qup);
+ else
+ qup_i2c_write_tx_fifo_v2(qup);
+ }
+
+ ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+ if (ret)
+ goto err;
+
+ ret = qup_i2c_wait_for_complete(qup, msg);
+ if (ret)
+ goto err;
+
+ /* Move to pause state for all the transfers, except last one */
+ if (change_pause_state) {
+ ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+ if (ret)
+ goto err;
+ }
+
+err:
+ disable_irq(qup->irq);
+ return ret;
+}
+
+/*
+ * Transfer one read/write message in i2c transfer. It splits the message into
+ * multiple of blk_xfer_limit data length blocks and schedule each
+ * QUP block individually.
+ */
+static int qup_i2c_xfer_v2_msg(struct qup_i2c_dev *qup, int msg_id, bool is_rx)
+{
+ int ret = 0;
+ unsigned int data_len, i;
+ struct i2c_msg *msg = qup->msg;
+ struct qup_i2c_block *blk = &qup->blk;
+ u8 *msg_buf = msg->buf;
+
+ qup->blk_xfer_limit = is_rx ? RECV_MAX_DATA_LEN : QUP_READ_LIMIT;
+ qup_i2c_set_blk_data(qup, msg);
+
+ for (i = 0; i < blk->count; i++) {
+ data_len = qup_i2c_get_data_len(qup);
+ blk->pos = i;
+ blk->cur_tx_tags = blk->tags;
+ blk->cur_blk_len = data_len;
+ blk->tx_tag_len =
+ qup_i2c_set_tags(blk->cur_tx_tags, qup, qup->msg);
+
+ blk->cur_data = msg_buf;
+
+ if (is_rx) {
+ blk->total_tx_len = blk->tx_tag_len;
+ blk->rx_tag_len = 2;
+ blk->total_rx_len = blk->rx_tag_len + data_len;
+ } else {
+ blk->total_tx_len = blk->tx_tag_len + data_len;
+ blk->total_rx_len = 0;
+ }
+
+ ret = qup_i2c_conf_xfer_v2(qup, is_rx, !msg_id && !i,
+ !qup->is_last || i < blk->count - 1);
+ if (ret)
+ return ret;
+
+ /* Handle SMBus block read length */
+ if (qup_i2c_check_msg_len(msg) && msg->len == 1 &&
+ !qup->is_smbus_read) {
+ if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+
+ msg->len = msg->buf[0];
+ qup->is_smbus_read = true;
+ ret = qup_i2c_xfer_v2_msg(qup, msg_id, true);
+ qup->is_smbus_read = false;
+ if (ret)
+ return ret;
+
+ msg->len += 1;
+ }
+
+ msg_buf += data_len;
+ blk->data_len -= qup->blk_xfer_limit;
+ }
+
+ return ret;
+}
+
+/*
+ * QUP v2 supports 3 modes
+ * Programmed IO using FIFO mode : Less than FIFO size
+ * Programmed IO using Block mode : Greater than FIFO size
+ * DMA using BAM : Appropriate for any transaction size but the address should
+ * be DMA applicable
+ *
+ * This function determines the mode which will be used for this transfer. An
+ * i2c transfer contains multiple message. Following are the rules to determine
+ * the mode used.
+ * 1. Determine complete length, maximum tx and rx length for complete transfer.
+ * 2. If complete transfer length is greater than fifo size then use the DMA
+ * mode.
+ * 3. In FIFO or block mode, tx and rx can operate in different mode so check
+ * for maximum tx and rx length to determine mode.
+ */
+static int
+qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup,
+ struct i2c_msg msgs[], int num)
+{
+ int idx;
+ bool no_dma = false;
+ unsigned int max_tx_len = 0, max_rx_len = 0, total_len = 0;
+
+ /* All i2c_msgs should be transferred using either dma or cpu */
+ for (idx = 0; idx < num; idx++) {
+ if (msgs[idx].flags & I2C_M_RD)
+ max_rx_len = max_t(unsigned int, max_rx_len,
+ msgs[idx].len);
+ else
+ max_tx_len = max_t(unsigned int, max_tx_len,
+ msgs[idx].len);
+
+ if (is_vmalloc_addr(msgs[idx].buf))
+ no_dma = true;
+
+ total_len += msgs[idx].len;
+ }
+
+ if (!no_dma && qup->is_dma &&
+ (total_len > qup->out_fifo_sz || total_len > qup->in_fifo_sz)) {
+ qup->use_dma = true;
+ } else {
+ qup->blk.is_tx_blk_mode = max_tx_len > qup->out_fifo_sz -
+ QUP_MAX_TAGS_LEN ? true : false;
+ qup->blk.is_rx_blk_mode = max_rx_len > qup->in_fifo_sz -
+ READ_RX_TAGS_LEN ? true : false;
+ }
+
+ return 0;
+}
+
+static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+ int ret, idx = 0;
+
+ qup->bus_err = 0;
+ qup->qup_err = 0;
+
+ ret = pm_runtime_get_sync(qup->dev);
+ if (ret < 0)
+ goto out;
+
+ ret = qup_i2c_determine_mode_v2(qup, msgs, num);
+ if (ret)
+ goto out;
+
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
+ if (ret)
+ goto out;
+
+ /* Configure QUP as I2C mini core */
+ writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
+ writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
+
+ if (qup_i2c_poll_state_i2c_master(qup)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (qup->use_dma) {
+ reinit_completion(&qup->xfer);
+ ret = qup_i2c_bam_xfer(adap, &msgs[0], num);
+ qup->use_dma = false;
+ } else {
+ qup_i2c_conf_mode_v2(qup);
+
+ for (idx = 0; idx < num; idx++) {
+ qup->msg = &msgs[idx];
+ qup->is_last = idx == (num - 1);
+
+ ret = qup_i2c_xfer_v2_msg(qup, idx,
+ !!(msgs[idx].flags & I2C_M_RD));
+ if (ret)
+ break;
+ }
+ qup->msg = NULL;
+ }
+
+ if (!ret)
+ ret = qup_i2c_bus_active(qup, ONE_BYTE);
+
+ if (!ret)
+ qup_i2c_change_state(qup, QUP_RESET_STATE);
+
+ if (ret == 0)
+ ret = num;
+out:
+ pm_runtime_mark_last_busy(qup->dev);
+ pm_runtime_put_autosuspend(qup->dev);
+
+ return ret;
+}
+
+static u32 qup_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm qup_i2c_algo = {
+ .master_xfer = qup_i2c_xfer,
+ .functionality = qup_i2c_func,
+};
+
+static const struct i2c_algorithm qup_i2c_algo_v2 = {
+ .master_xfer = qup_i2c_xfer_v2,
+ .functionality = qup_i2c_func,
+};
+
+/*
+ * The QUP block will issue a NACK and STOP on the bus when reaching
+ * the end of the read, the length of the read is specified as one byte
+ * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+ */
+static const struct i2c_adapter_quirks qup_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = QUP_READ_LIMIT,
+};
+
+static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
+{
+ clk_prepare_enable(qup->clk);
+ clk_prepare_enable(qup->pclk);
+}
+
+static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
+{
+ u32 config;
+
+ qup_i2c_change_state(qup, QUP_RESET_STATE);
+ clk_disable_unprepare(qup->clk);
+ config = readl(qup->base + QUP_CONFIG);
+ config |= QUP_CLOCK_AUTO_GATE;
+ writel(config, qup->base + QUP_CONFIG);
+ clk_disable_unprepare(qup->pclk);
+}
+
+static const struct acpi_device_id qup_i2c_acpi_match[] = {
+ { "QCOM8010"},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match);
+
+static int qup_i2c_probe(struct platform_device *pdev)
+{
+ static const int blk_sizes[] = {4, 16, 32};
+ struct qup_i2c_dev *qup;
+ unsigned long one_bit_t;
+ struct resource *res;
+ u32 io_mode, hw_ver, size;
+ int ret, fs_div, hs_div;
+ u32 src_clk_freq = DEFAULT_SRC_CLK;
+ u32 clk_freq = DEFAULT_CLK_FREQ;
+ int blocks;
+ bool is_qup_v1;
+
+ qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
+ if (!qup)
+ return -ENOMEM;
+
+ qup->dev = &pdev->dev;
+ init_completion(&qup->xfer);
+ platform_set_drvdata(pdev, qup);
+
+ if (scl_freq) {
+ dev_notice(qup->dev, "Using override frequency of %u\n", scl_freq);
+ clk_freq = scl_freq;
+ } else {
+ ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq);
+ if (ret) {
+ dev_notice(qup->dev, "using default clock-frequency %d",
+ DEFAULT_CLK_FREQ);
+ }
+ }
+
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
+ qup->adap.algo = &qup_i2c_algo;
+ qup->adap.quirks = &qup_i2c_quirks;
+ is_qup_v1 = true;
+ } else {
+ qup->adap.algo = &qup_i2c_algo_v2;
+ qup->adap.quirks = &qup_i2c_quirks_v2;
+ is_qup_v1 = false;
+ if (acpi_match_device(qup_i2c_acpi_match, qup->dev))
+ goto nodma;
+ else
+ ret = qup_i2c_req_dma(qup);
+
+ if (ret == -EPROBE_DEFER)
+ goto fail_dma;
+ else if (ret != 0)
+ goto nodma;
+
+ qup->max_xfer_sg_len = (MX_BLOCKS << 1);
+ blocks = (MX_DMA_BLOCKS << 1) + 1;
+ qup->btx.sg = devm_kcalloc(&pdev->dev,
+ blocks, sizeof(*qup->btx.sg),
+ GFP_KERNEL);
+ if (!qup->btx.sg) {
+ ret = -ENOMEM;
+ goto fail_dma;
+ }
+ sg_init_table(qup->btx.sg, blocks);
+
+ qup->brx.sg = devm_kcalloc(&pdev->dev,
+ blocks, sizeof(*qup->brx.sg),
+ GFP_KERNEL);
+ if (!qup->brx.sg) {
+ ret = -ENOMEM;
+ goto fail_dma;
+ }
+ sg_init_table(qup->brx.sg, blocks);
+
+ /* 2 tag bytes for each block + 5 for start, stop tags */
+ size = blocks * 2 + 5;
+
+ qup->start_tag.start = devm_kzalloc(&pdev->dev,
+ size, GFP_KERNEL);
+ if (!qup->start_tag.start) {
+ ret = -ENOMEM;
+ goto fail_dma;
+ }
+
+ qup->brx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL);
+ if (!qup->brx.tag.start) {
+ ret = -ENOMEM;
+ goto fail_dma;
+ }
+
+ qup->btx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL);
+ if (!qup->btx.tag.start) {
+ ret = -ENOMEM;
+ goto fail_dma;
+ }
+ qup->is_dma = true;
+ }
+
+nodma:
+ /* We support frequencies up to FAST Mode Plus (1MHz) */
+ if (!clk_freq || clk_freq > I2C_FAST_MODE_PLUS_FREQ) {
+ dev_err(qup->dev, "clock frequency not supported %d\n",
+ clk_freq);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qup->base = devm_ioremap_resource(qup->dev, res);
+ if (IS_ERR(qup->base))
+ return PTR_ERR(qup->base);
+
+ qup->irq = platform_get_irq(pdev, 0);
+ if (qup->irq < 0) {
+ dev_err(qup->dev, "No IRQ defined\n");
+ return qup->irq;
+ }
+
+ if (has_acpi_companion(qup->dev)) {
+ ret = device_property_read_u32(qup->dev,
+ "src-clock-hz", &src_clk_freq);
+ if (ret) {
+ dev_notice(qup->dev, "using default src-clock-hz %d",
+ DEFAULT_SRC_CLK);
+ }
+ ACPI_COMPANION_SET(&qup->adap.dev, ACPI_COMPANION(qup->dev));
+ } else {
+ qup->clk = devm_clk_get(qup->dev, "core");
+ if (IS_ERR(qup->clk)) {
+ dev_err(qup->dev, "Could not get core clock\n");
+ return PTR_ERR(qup->clk);
+ }
+
+ qup->pclk = devm_clk_get(qup->dev, "iface");
+ if (IS_ERR(qup->pclk)) {
+ dev_err(qup->dev, "Could not get iface clock\n");
+ return PTR_ERR(qup->pclk);
+ }
+ qup_i2c_enable_clocks(qup);
+ src_clk_freq = clk_get_rate(qup->clk);
+ }
+
+ /*
+ * Bootloaders might leave a pending interrupt on certain QUP's,
+ * so we reset the core before registering for interrupts.
+ */
+ writel(1, qup->base + QUP_SW_RESET);
+ ret = qup_i2c_poll_state_valid(qup);
+ if (ret)
+ goto fail;
+
+ ret = devm_request_irq(qup->dev, qup->irq, qup_i2c_interrupt,
+ IRQF_TRIGGER_HIGH, "i2c_qup", qup);
+ if (ret) {
+ dev_err(qup->dev, "Request %d IRQ failed\n", qup->irq);
+ goto fail;
+ }
+ disable_irq(qup->irq);
+
+ hw_ver = readl(qup->base + QUP_HW_VERSION);
+ dev_dbg(qup->dev, "Revision %x\n", hw_ver);
+
+ io_mode = readl(qup->base + QUP_IO_MODE);
+
+ /*
+ * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
+ * associated with each byte written/received
+ */
+ size = QUP_OUTPUT_BLOCK_SIZE(io_mode);
+ if (size >= ARRAY_SIZE(blk_sizes)) {
+ ret = -EIO;
+ goto fail;
+ }
+ qup->out_blk_sz = blk_sizes[size];
+
+ size = QUP_INPUT_BLOCK_SIZE(io_mode);
+ if (size >= ARRAY_SIZE(blk_sizes)) {
+ ret = -EIO;
+ goto fail;
+ }
+ qup->in_blk_sz = blk_sizes[size];
+
+ if (is_qup_v1) {
+ /*
+ * in QUP v1, QUP_CONFIG uses N as 15 i.e 16 bits constitutes a
+ * single transfer but the block size is in bytes so divide the
+ * in_blk_sz and out_blk_sz by 2
+ */
+ qup->in_blk_sz /= 2;
+ qup->out_blk_sz /= 2;
+ qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
+ qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
+ qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
+ } else {
+ qup->write_tx_fifo = qup_i2c_write_tx_fifo_v2;
+ qup->read_rx_fifo = qup_i2c_read_rx_fifo_v2;
+ qup->write_rx_tags = qup_i2c_write_rx_tags_v2;
+ }
+
+ size = QUP_OUTPUT_FIFO_SIZE(io_mode);
+ qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
+
+ size = QUP_INPUT_FIFO_SIZE(io_mode);
+ qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
+
+ hs_div = 3;
+ if (clk_freq <= I2C_STANDARD_FREQ) {
+ fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+ qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
+ } else {
+ /* 33%/66% duty cycle */
+ fs_div = ((src_clk_freq / clk_freq) - 6) * 2 / 3;
+ qup->clk_ctl = ((fs_div / 2) << 16) | (hs_div << 8) | (fs_div & 0xff);
+ }
+
+ /*
+ * Time it takes for a byte to be clocked out on the bus.
+ * Each byte takes 9 clock cycles (8 bits + 1 ack).
+ */
+ one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
+ qup->one_byte_t = one_bit_t * 9;
+ qup->xfer_timeout = TOUT_MIN * HZ +
+ usecs_to_jiffies(MX_DMA_TX_RX_LEN * qup->one_byte_t);
+
+ dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+ qup->in_blk_sz, qup->in_fifo_sz,
+ qup->out_blk_sz, qup->out_fifo_sz);
+
+ i2c_set_adapdata(&qup->adap, qup);
+ qup->adap.dev.parent = qup->dev;
+ qup->adap.dev.of_node = pdev->dev.of_node;
+ qup->is_last = true;
+
+ strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
+
+ pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(qup->dev);
+ pm_runtime_set_active(qup->dev);
+ pm_runtime_enable(qup->dev);
+
+ ret = i2c_add_adapter(&qup->adap);
+ if (ret)
+ goto fail_runtime;
+
+ return 0;
+
+fail_runtime:
+ pm_runtime_disable(qup->dev);
+ pm_runtime_set_suspended(qup->dev);
+fail:
+ qup_i2c_disable_clocks(qup);
+fail_dma:
+ if (qup->btx.dma)
+ dma_release_channel(qup->btx.dma);
+ if (qup->brx.dma)
+ dma_release_channel(qup->brx.dma);
+ return ret;
+}
+
+static int qup_i2c_remove(struct platform_device *pdev)
+{
+ struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
+
+ if (qup->is_dma) {
+ dma_release_channel(qup->btx.dma);
+ dma_release_channel(qup->brx.dma);
+ }
+
+ disable_irq(qup->irq);
+ qup_i2c_disable_clocks(qup);
+ i2c_del_adapter(&qup->adap);
+ pm_runtime_disable(qup->dev);
+ pm_runtime_set_suspended(qup->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int qup_i2c_pm_suspend_runtime(struct device *device)
+{
+ struct qup_i2c_dev *qup = dev_get_drvdata(device);
+
+ dev_dbg(device, "pm_runtime: suspending...\n");
+ qup_i2c_disable_clocks(qup);
+ return 0;
+}
+
+static int qup_i2c_pm_resume_runtime(struct device *device)
+{
+ struct qup_i2c_dev *qup = dev_get_drvdata(device);
+
+ dev_dbg(device, "pm_runtime: resuming...\n");
+ qup_i2c_enable_clocks(qup);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int qup_i2c_suspend(struct device *device)
+{
+ if (!pm_runtime_suspended(device))
+ return qup_i2c_pm_suspend_runtime(device);
+ return 0;
+}
+
+static int qup_i2c_resume(struct device *device)
+{
+ qup_i2c_pm_resume_runtime(device);
+ pm_runtime_mark_last_busy(device);
+ pm_request_autosuspend(device);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(
+ qup_i2c_suspend,
+ qup_i2c_resume)
+ SET_RUNTIME_PM_OPS(
+ qup_i2c_pm_suspend_runtime,
+ qup_i2c_pm_resume_runtime,
+ NULL)
+};
+
+static const struct of_device_id qup_i2c_dt_match[] = {
+ { .compatible = "qcom,i2c-qup-v1.1.1" },
+ { .compatible = "qcom,i2c-qup-v2.1.1" },
+ { .compatible = "qcom,i2c-qup-v2.2.1" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
+
+static struct platform_driver qup_i2c_driver = {
+ .probe = qup_i2c_probe,
+ .remove = qup_i2c_remove,
+ .driver = {
+ .name = "i2c_qup",
+ .pm = &qup_i2c_qup_pm_ops,
+ .of_match_table = qup_i2c_dt_match,
+ .acpi_match_table = ACPI_PTR(qup_i2c_acpi_match),
+ },
+};
+
+module_platform_driver(qup_i2c_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c_qup");
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
new file mode 100644
index 000000000..3ea2ceec6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -0,0 +1,1043 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the Renesas R-Car I2C unit
+ *
+ * Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright (C) 2011-2015 Renesas Electronics Corporation
+ *
+ * Copyright (C) 2012-14 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is based on the drivers/i2c/busses/i2c-sh7760.c
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.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/reset.h>
+#include <linux/slab.h>
+
+/* register offsets */
+#define ICSCR 0x00 /* slave ctrl */
+#define ICMCR 0x04 /* master ctrl */
+#define ICSSR 0x08 /* slave status */
+#define ICMSR 0x0C /* master status */
+#define ICSIER 0x10 /* slave irq enable */
+#define ICMIER 0x14 /* master irq enable */
+#define ICCCR 0x18 /* clock dividers */
+#define ICSAR 0x1C /* slave address */
+#define ICMAR 0x20 /* master address */
+#define ICRXTX 0x24 /* data port */
+#define ICDMAER 0x3c /* DMA enable */
+#define ICFBSCR 0x38 /* first bit setup cycle */
+
+/* ICSCR */
+#define SDBS (1 << 3) /* slave data buffer select */
+#define SIE (1 << 2) /* slave interface enable */
+#define GCAE (1 << 1) /* general call address enable */
+#define FNA (1 << 0) /* forced non acknowledgment */
+
+/* ICMCR */
+#define MDBS (1 << 7) /* non-fifo mode switch */
+#define FSCL (1 << 6) /* override SCL pin */
+#define FSDA (1 << 5) /* override SDA pin */
+#define OBPC (1 << 4) /* override pins */
+#define MIE (1 << 3) /* master if enable */
+#define TSBE (1 << 2)
+#define FSB (1 << 1) /* force stop bit */
+#define ESG (1 << 0) /* enable start bit gen */
+
+/* ICSSR (also for ICSIER) */
+#define GCAR (1 << 6) /* general call received */
+#define STM (1 << 5) /* slave transmit mode */
+#define SSR (1 << 4) /* stop received */
+#define SDE (1 << 3) /* slave data empty */
+#define SDT (1 << 2) /* slave data transmitted */
+#define SDR (1 << 1) /* slave data received */
+#define SAR (1 << 0) /* slave addr received */
+
+/* ICMSR (also for ICMIE) */
+#define MNR (1 << 6) /* nack received */
+#define MAL (1 << 5) /* arbitration lost */
+#define MST (1 << 4) /* sent a stop */
+#define MDE (1 << 3)
+#define MDT (1 << 2)
+#define MDR (1 << 1)
+#define MAT (1 << 0) /* slave addr xfer done */
+
+/* ICDMAER */
+#define RSDMAE (1 << 3) /* DMA Slave Received Enable */
+#define TSDMAE (1 << 2) /* DMA Slave Transmitted Enable */
+#define RMDMAE (1 << 1) /* DMA Master Received Enable */
+#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */
+
+/* ICFBSCR */
+#define TCYC06 0x04 /* 6*Tcyc delay 1st bit between SDA and SCL */
+#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
+
+
+#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
+#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
+#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF)
+#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB)
+
+#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE)
+#define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR)
+#define RCAR_IRQ_STOP (MST)
+
+#define RCAR_IRQ_ACK_SEND (~(MAT | MDE) & 0x7F)
+#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0x7F)
+
+#define ID_LAST_MSG (1 << 0)
+#define ID_FIRST_MSG (1 << 1)
+#define ID_DONE (1 << 2)
+#define ID_ARBLOST (1 << 3)
+#define ID_NACK (1 << 4)
+/* persistent flags */
+#define ID_P_REP_AFTER_RD BIT(29)
+#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
+#define ID_P_PM_BLOCKED BIT(31)
+#define ID_P_MASK GENMASK(31, 29)
+
+enum rcar_i2c_type {
+ I2C_RCAR_GEN1,
+ I2C_RCAR_GEN2,
+ I2C_RCAR_GEN3,
+};
+
+struct rcar_i2c_priv {
+ u32 flags;
+ void __iomem *io;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int msgs_left;
+ struct clk *clk;
+
+ wait_queue_head_t wait;
+
+ int pos;
+ u32 icccr;
+ u8 recovery_icmcr; /* protected by adapter lock */
+ enum rcar_i2c_type devtype;
+ struct i2c_client *slave;
+
+ struct resource *res;
+ struct dma_chan *dma_tx;
+ struct dma_chan *dma_rx;
+ struct scatterlist sg;
+ enum dma_data_direction dma_direction;
+
+ struct reset_control *rstc;
+ int irq;
+};
+
+#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
+#define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD)
+
+#define LOOP_TIMEOUT 1024
+
+
+static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
+{
+ writel(val, priv->io + reg);
+}
+
+static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
+{
+ return readl(priv->io + reg);
+}
+
+static int rcar_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(rcar_i2c_read(priv, ICMCR) & FSCL);
+
+};
+
+static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (val)
+ priv->recovery_icmcr |= FSCL;
+ else
+ priv->recovery_icmcr &= ~FSCL;
+
+ rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
+};
+
+static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (val)
+ priv->recovery_icmcr |= FSDA;
+ else
+ priv->recovery_icmcr &= ~FSDA;
+
+ rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
+};
+
+static int rcar_i2c_get_bus_free(struct i2c_adapter *adap)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !(rcar_i2c_read(priv, ICMCR) & FSDA);
+
+};
+
+static struct i2c_bus_recovery_info rcar_i2c_bri = {
+ .get_scl = rcar_i2c_get_scl,
+ .set_scl = rcar_i2c_set_scl,
+ .set_sda = rcar_i2c_set_sda,
+ .get_bus_free = rcar_i2c_get_bus_free,
+ .recover_bus = i2c_generic_scl_recovery,
+};
+static void rcar_i2c_init(struct rcar_i2c_priv *priv)
+{
+ /* reset master mode */
+ rcar_i2c_write(priv, ICMIER, 0);
+ rcar_i2c_write(priv, ICMCR, MDBS);
+ rcar_i2c_write(priv, ICMSR, 0);
+ /* start clock */
+ rcar_i2c_write(priv, ICCCR, priv->icccr);
+}
+
+static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < LOOP_TIMEOUT; i++) {
+ /* make sure that bus is not busy */
+ if (!(rcar_i2c_read(priv, ICMCR) & FSDA))
+ return 0;
+ udelay(1);
+ }
+
+ /* Waiting did not help, try to recover */
+ priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
+ return i2c_recover_bus(&priv->adap);
+}
+
+static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
+{
+ u32 scgd, cdf, round, ick, sum, scl, cdf_width;
+ unsigned long rate;
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+
+ /* Fall back to previously used values if not supplied */
+ t->bus_freq_hz = t->bus_freq_hz ?: 100000;
+ t->scl_fall_ns = t->scl_fall_ns ?: 35;
+ t->scl_rise_ns = t->scl_rise_ns ?: 200;
+ t->scl_int_delay_ns = t->scl_int_delay_ns ?: 50;
+
+ switch (priv->devtype) {
+ case I2C_RCAR_GEN1:
+ cdf_width = 2;
+ break;
+ case I2C_RCAR_GEN2:
+ case I2C_RCAR_GEN3:
+ cdf_width = 3;
+ break;
+ default:
+ dev_err(dev, "device type error\n");
+ return -EIO;
+ }
+
+ /*
+ * calculate SCL clock
+ * see
+ * ICCCR
+ *
+ * ick = clkp / (1 + CDF)
+ * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+ *
+ * ick : I2C internal clock < 20 MHz
+ * ticf : I2C SCL falling time
+ * tr : I2C SCL rising time
+ * intd : LSI internal delay
+ * clkp : peripheral_clk
+ * F[] : integer up-valuation
+ */
+ rate = clk_get_rate(priv->clk);
+ cdf = rate / 20000000;
+ if (cdf >= 1U << cdf_width) {
+ dev_err(dev, "Input clock %lu too high\n", rate);
+ return -EIO;
+ }
+ ick = rate / (cdf + 1);
+
+ /*
+ * it is impossible to calculate large scale
+ * number on u32. separate it
+ *
+ * F[(ticf + tr + intd) * ick] with sum = (ticf + tr + intd)
+ * = F[sum * ick / 1000000000]
+ * = F[(ick / 1000000) * sum / 1000]
+ */
+ sum = t->scl_fall_ns + t->scl_rise_ns + t->scl_int_delay_ns;
+ round = (ick + 500000) / 1000000 * sum;
+ round = (round + 500) / 1000;
+
+ /*
+ * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
+ *
+ * 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);
+ if (scl <= t->bus_freq_hz)
+ goto scgd_find;
+ }
+ dev_err(dev, "it is impossible to calculate best SCL\n");
+ return -EIO;
+
+scgd_find:
+ dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
+ scl, t->bus_freq_hz, clk_get_rate(priv->clk), round, cdf, scgd);
+
+ /* keep icccr value */
+ priv->icccr = scgd << cdf_width | cdf;
+
+ return 0;
+}
+
+static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
+{
+ int read = !!rcar_i2c_is_recv(priv);
+
+ priv->pos = 0;
+ if (priv->msgs_left == 1)
+ priv->flags |= ID_LAST_MSG;
+
+ rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg));
+ /*
+ * We don't have a test case but the HW engineers say that the write order
+ * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
+ * it didn't cause a drawback for me, let's rather be safe than sorry.
+ */
+ if (priv->flags & ID_FIRST_MSG) {
+ rcar_i2c_write(priv, ICMSR, 0);
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ } else {
+ if (priv->flags & ID_P_REP_AFTER_RD)
+ priv->flags &= ~ID_P_REP_AFTER_RD;
+ else
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ rcar_i2c_write(priv, ICMSR, 0);
+ }
+ rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
+}
+
+static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
+{
+ priv->msg++;
+ priv->msgs_left--;
+ priv->flags &= ID_P_MASK;
+ rcar_i2c_prepare_msg(priv);
+}
+
+/*
+ * interrupt functions
+ */
+static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
+{
+ struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
+ ? priv->dma_rx : priv->dma_tx;
+
+ /* Disable DMA Master Received/Transmitted */
+ rcar_i2c_write(priv, ICDMAER, 0);
+
+ /* Reset default delay */
+ rcar_i2c_write(priv, ICFBSCR, TCYC06);
+
+ dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
+ sg_dma_len(&priv->sg), priv->dma_direction);
+
+ /* Gen3 can only do one RXDMA per transfer and we just completed it */
+ if (priv->devtype == I2C_RCAR_GEN3 &&
+ priv->dma_direction == DMA_FROM_DEVICE)
+ priv->flags |= ID_P_NO_RXDMA;
+
+ priv->dma_direction = DMA_NONE;
+}
+
+static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv)
+{
+ if (priv->dma_direction == DMA_NONE)
+ return;
+ else if (priv->dma_direction == DMA_FROM_DEVICE)
+ dmaengine_terminate_all(priv->dma_rx);
+ else if (priv->dma_direction == DMA_TO_DEVICE)
+ dmaengine_terminate_all(priv->dma_tx);
+
+ rcar_i2c_dma_unmap(priv);
+}
+
+static void rcar_i2c_dma_callback(void *data)
+{
+ struct rcar_i2c_priv *priv = data;
+
+ priv->pos += sg_dma_len(&priv->sg);
+
+ rcar_i2c_dma_unmap(priv);
+}
+
+static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
+{
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+ struct i2c_msg *msg = priv->msg;
+ bool read = msg->flags & I2C_M_RD;
+ enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ struct dma_chan *chan = read ? priv->dma_rx : priv->dma_tx;
+ struct dma_async_tx_descriptor *txdesc;
+ dma_addr_t dma_addr;
+ dma_cookie_t cookie;
+ unsigned char *buf;
+ int len;
+
+ /* Do various checks to see if DMA is feasible at all */
+ if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE) ||
+ (read && priv->flags & ID_P_NO_RXDMA))
+ return;
+
+ if (read) {
+ /*
+ * The last two bytes needs to be fetched using PIO in
+ * order for the STOP phase to work.
+ */
+ buf = priv->msg->buf;
+ len = priv->msg->len - 2;
+ } else {
+ /*
+ * First byte in message was sent using PIO.
+ */
+ buf = priv->msg->buf + 1;
+ len = priv->msg->len - 1;
+ }
+
+ dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+ if (dma_mapping_error(chan->device->dev, dma_addr)) {
+ dev_dbg(dev, "dma map failed, using PIO\n");
+ return;
+ }
+
+ sg_dma_len(&priv->sg) = len;
+ sg_dma_address(&priv->sg) = dma_addr;
+
+ priv->dma_direction = dir;
+
+ txdesc = dmaengine_prep_slave_sg(chan, &priv->sg, 1,
+ read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc) {
+ dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
+ rcar_i2c_cleanup_dma(priv);
+ return;
+ }
+
+ txdesc->callback = rcar_i2c_dma_callback;
+ txdesc->callback_param = priv;
+
+ cookie = dmaengine_submit(txdesc);
+ if (dma_submit_error(cookie)) {
+ dev_dbg(dev, "submitting dma failed, using PIO\n");
+ rcar_i2c_cleanup_dma(priv);
+ return;
+ }
+
+ /* Set delay for DMA operations */
+ rcar_i2c_write(priv, ICFBSCR, TCYC17);
+
+ /* Enable DMA Master Received/Transmitted */
+ if (read)
+ rcar_i2c_write(priv, ICDMAER, RMDMAE);
+ else
+ rcar_i2c_write(priv, ICDMAER, TMDMAE);
+
+ dma_async_issue_pending(chan);
+}
+
+static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ /* FIXME: sometimes, unknown interrupt happened. Do nothing */
+ if (!(msr & MDE))
+ return;
+
+ if (priv->pos < msg->len) {
+ /*
+ * Prepare next data to ICRXTX register.
+ * This data will go to _SHIFT_ register.
+ *
+ * *
+ * [ICRXTX] -> [SHIFT] -> [I2C bus]
+ */
+ rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
+ priv->pos++;
+
+ /*
+ * Try to use DMA to transmit the rest of the data if
+ * address transfer phase just finished.
+ */
+ if (msr & MAT)
+ rcar_i2c_dma(priv);
+ } else {
+ /*
+ * The last data was pushed to ICRXTX on _PREV_ empty irq.
+ * It is on _SHIFT_ register, and will sent to I2C bus.
+ *
+ * *
+ * [ICRXTX] -> [SHIFT] -> [I2C bus]
+ */
+
+ if (priv->flags & ID_LAST_MSG) {
+ /*
+ * If current msg is the _LAST_ msg,
+ * prepare stop condition here.
+ * ID_DONE will be set on STOP irq.
+ */
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
+ } else {
+ rcar_i2c_next_msg(priv);
+ return;
+ }
+ }
+
+ rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
+}
+
+static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ /* FIXME: sometimes, unknown interrupt happened. Do nothing */
+ if (!(msr & MDR))
+ return;
+
+ if (msr & MAT) {
+ /*
+ * Address transfer phase finished, but no data at this point.
+ * Try to use DMA to receive data.
+ */
+ rcar_i2c_dma(priv);
+ } else if (priv->pos < msg->len) {
+ /* get received data */
+ msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
+ priv->pos++;
+ }
+
+ /* If next received data is the _LAST_, go to new phase. */
+ if (priv->pos + 1 == msg->len) {
+ if (priv->flags & ID_LAST_MSG) {
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
+ } else {
+ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
+ priv->flags |= ID_P_REP_AFTER_RD;
+ }
+ }
+
+ if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
+ rcar_i2c_next_msg(priv);
+ else
+ rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
+}
+
+static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
+{
+ u32 ssr_raw, ssr_filtered;
+ u8 value;
+
+ ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff;
+ ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER);
+
+ if (!ssr_filtered)
+ return false;
+
+ /* address detected */
+ if (ssr_filtered & SAR) {
+ /* read or write request */
+ if (ssr_raw & STM) {
+ i2c_slave_event(priv->slave, I2C_SLAVE_READ_REQUESTED, &value);
+ rcar_i2c_write(priv, ICRXTX, value);
+ rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
+ } else {
+ i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+ rcar_i2c_read(priv, ICRXTX); /* dummy read */
+ rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
+ }
+
+ /* Clear SSR, too, because of old STOPs to other clients than us */
+ rcar_i2c_write(priv, ICSSR, ~(SAR | SSR) & 0xff);
+ }
+
+ /* master sent stop */
+ if (ssr_filtered & SSR) {
+ i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
+ rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */
+ rcar_i2c_write(priv, ICSIER, SAR);
+ rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
+ }
+
+ /* master wants to write to us */
+ if (ssr_filtered & SDR) {
+ int ret;
+
+ value = rcar_i2c_read(priv, ICRXTX);
+ ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
+ /* Send NACK in case of error */
+ rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
+ rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
+ }
+
+ /* master wants to read from us */
+ if (ssr_filtered & SDE) {
+ i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value);
+ rcar_i2c_write(priv, ICRXTX, value);
+ rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
+ }
+
+ return true;
+}
+
+static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
+{
+ struct rcar_i2c_priv *priv = ptr;
+ u32 msr, val;
+
+ /* Clear START or STOP immediately, except for REPSTART after read */
+ if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) {
+ val = rcar_i2c_read(priv, ICMCR);
+ rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
+ }
+
+ msr = rcar_i2c_read(priv, ICMSR);
+
+ /* Only handle interrupts that are currently enabled */
+ msr &= rcar_i2c_read(priv, ICMIER);
+ if (!msr) {
+ if (rcar_i2c_slave_irq(priv))
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+ }
+
+ /* Arbitration lost */
+ if (msr & MAL) {
+ priv->flags |= ID_DONE | ID_ARBLOST;
+ goto out;
+ }
+
+ /* Nack */
+ if (msr & MNR) {
+ /* HW automatically sends STOP after received NACK */
+ rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
+ priv->flags |= ID_NACK;
+ goto out;
+ }
+
+ /* Stop */
+ if (msr & MST) {
+ priv->msgs_left--; /* The last message also made it */
+ priv->flags |= ID_DONE;
+ goto out;
+ }
+
+ if (rcar_i2c_is_recv(priv))
+ rcar_i2c_irq_recv(priv, msr);
+ else
+ rcar_i2c_irq_send(priv, msr);
+
+out:
+ if (priv->flags & ID_DONE) {
+ rcar_i2c_write(priv, ICMIER, 0);
+ rcar_i2c_write(priv, ICMSR, 0);
+ wake_up(&priv->wait);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
+ enum dma_transfer_direction dir,
+ dma_addr_t port_addr)
+{
+ struct dma_chan *chan;
+ struct dma_slave_config cfg;
+ char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
+ int ret;
+
+ chan = dma_request_chan(dev, chan_name);
+ if (IS_ERR(chan)) {
+ dev_dbg(dev, "request_channel failed for %s (%ld)\n",
+ chan_name, PTR_ERR(chan));
+ return chan;
+ }
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.direction = dir;
+ if (dir == DMA_MEM_TO_DEV) {
+ cfg.dst_addr = port_addr;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ } else {
+ cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
+
+ ret = dmaengine_slave_config(chan, &cfg);
+ if (ret) {
+ dev_dbg(dev, "slave_config failed for %s (%d)\n",
+ chan_name, ret);
+ dma_release_channel(chan);
+ return ERR_PTR(ret);
+ }
+
+ dev_dbg(dev, "got DMA channel for %s\n", chan_name);
+ return chan;
+}
+
+static void rcar_i2c_request_dma(struct rcar_i2c_priv *priv,
+ struct i2c_msg *msg)
+{
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+ bool read;
+ struct dma_chan *chan;
+ enum dma_transfer_direction dir;
+
+ read = msg->flags & I2C_M_RD;
+
+ chan = read ? priv->dma_rx : priv->dma_tx;
+ if (PTR_ERR(chan) != -EPROBE_DEFER)
+ return;
+
+ dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+ chan = rcar_i2c_request_dma_chan(dev, dir, priv->res->start + ICRXTX);
+
+ if (read)
+ priv->dma_rx = chan;
+ else
+ priv->dma_tx = chan;
+}
+
+static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
+{
+ if (!IS_ERR(priv->dma_tx)) {
+ dma_release_channel(priv->dma_tx);
+ priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
+ }
+
+ if (!IS_ERR(priv->dma_rx)) {
+ dma_release_channel(priv->dma_rx);
+ priv->dma_rx = ERR_PTR(-EPROBE_DEFER);
+ }
+}
+
+/* I2C is a special case, we need to poll the status of a reset */
+static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv)
+{
+ int i, ret;
+
+ ret = reset_control_reset(priv->rstc);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < LOOP_TIMEOUT; i++) {
+ ret = reset_control_status(priv->rstc);
+ if (ret == 0)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
+ struct device *dev = rcar_i2c_priv_to_dev(priv);
+ int i, ret;
+ long time_left;
+
+ pm_runtime_get_sync(dev);
+
+ /* Check bus state before init otherwise bus busy info will be lost */
+ ret = rcar_i2c_bus_barrier(priv);
+ if (ret < 0)
+ goto out;
+
+ /* Gen3 needs a reset before allowing RXDMA once */
+ if (priv->devtype == I2C_RCAR_GEN3) {
+ priv->flags |= ID_P_NO_RXDMA;
+ if (!IS_ERR(priv->rstc)) {
+ ret = rcar_i2c_do_reset(priv);
+ if (ret == 0)
+ priv->flags &= ~ID_P_NO_RXDMA;
+ }
+ }
+
+ rcar_i2c_init(priv);
+
+ for (i = 0; i < num; i++)
+ rcar_i2c_request_dma(priv, msgs + i);
+
+ /* init first message */
+ priv->msg = msgs;
+ priv->msgs_left = num;
+ priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
+ rcar_i2c_prepare_msg(priv);
+
+ time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
+ num * adap->timeout);
+
+ /* cleanup DMA if it couldn't complete properly due to an error */
+ if (priv->dma_direction != DMA_NONE)
+ rcar_i2c_cleanup_dma(priv);
+
+ if (!time_left) {
+ rcar_i2c_init(priv);
+ ret = -ETIMEDOUT;
+ } else if (priv->flags & ID_NACK) {
+ ret = -ENXIO;
+ } else if (priv->flags & ID_ARBLOST) {
+ ret = -EAGAIN;
+ } else {
+ ret = num - priv->msgs_left; /* The number of transfer */
+ }
+out:
+ pm_runtime_put(dev);
+
+ if (ret < 0 && ret != -ENXIO)
+ dev_err(dev, "error %d : %x\n", ret, priv->flags);
+
+ return ret;
+}
+
+static int rcar_reg_slave(struct i2c_client *slave)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
+
+ if (priv->slave)
+ return -EBUSY;
+
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ /* Keep device active for slave address detection logic */
+ pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
+
+ priv->slave = slave;
+ rcar_i2c_write(priv, ICSAR, slave->addr);
+ rcar_i2c_write(priv, ICSSR, 0);
+ rcar_i2c_write(priv, ICSIER, SAR);
+ rcar_i2c_write(priv, ICSCR, SIE | SDBS);
+
+ return 0;
+}
+
+static int rcar_unreg_slave(struct i2c_client *slave)
+{
+ struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
+
+ WARN_ON(!priv->slave);
+
+ /* ensure no irq is running before clearing ptr */
+ disable_irq(priv->irq);
+ rcar_i2c_write(priv, ICSIER, 0);
+ rcar_i2c_write(priv, ICSSR, 0);
+ enable_irq(priv->irq);
+ rcar_i2c_write(priv, ICSCR, SDBS);
+ rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
+
+ priv->slave = NULL;
+
+ pm_runtime_put(rcar_i2c_priv_to_dev(priv));
+
+ return 0;
+}
+
+static u32 rcar_i2c_func(struct i2c_adapter *adap)
+{
+ /*
+ * This HW can't do:
+ * I2C_SMBUS_QUICK (setting FSB during START didn't work)
+ * I2C_M_NOSTART (automatically sends address after START)
+ * I2C_M_IGNORE_NAK (automatically sends STOP after NAK)
+ */
+ return I2C_FUNC_I2C | I2C_FUNC_SLAVE |
+ (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm rcar_i2c_algo = {
+ .master_xfer = rcar_i2c_master_xfer,
+ .functionality = rcar_i2c_func,
+ .reg_slave = rcar_reg_slave,
+ .unreg_slave = rcar_unreg_slave,
+};
+
+static const struct i2c_adapter_quirks rcar_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static const struct of_device_id rcar_i2c_dt_ids[] = {
+ { .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 },
+ { .compatible = "renesas,i2c-r8a7791", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
+ { .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 },
+ { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 }, /* Deprecated */
+ { .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 },
+ { .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
+
+static int rcar_i2c_probe(struct platform_device *pdev)
+{
+ struct rcar_i2c_priv *priv;
+ struct i2c_adapter *adap;
+ struct device *dev = &pdev->dev;
+ struct i2c_timings i2c_t;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "cannot get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ priv->io = devm_ioremap_resource(dev, priv->res);
+ if (IS_ERR(priv->io))
+ return PTR_ERR(priv->io);
+
+ priv->devtype = (enum rcar_i2c_type)of_device_get_match_data(dev);
+ init_waitqueue_head(&priv->wait);
+
+ adap = &priv->adap;
+ adap->nr = pdev->id;
+ adap->algo = &rcar_i2c_algo;
+ adap->class = I2C_CLASS_DEPRECATED;
+ adap->retries = 3;
+ adap->dev.parent = dev;
+ adap->dev.of_node = dev->of_node;
+ adap->bus_recovery_info = &rcar_i2c_bri;
+ adap->quirks = &rcar_i2c_quirks;
+ i2c_set_adapdata(adap, priv);
+ strlcpy(adap->name, pdev->name, sizeof(adap->name));
+
+ i2c_parse_fw_timings(dev, &i2c_t, false);
+
+ /* Init DMA */
+ sg_init_table(&priv->sg, 1);
+ priv->dma_direction = DMA_NONE;
+ priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
+
+ /* Activate device for clock calculation */
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ ret = rcar_i2c_clock_calculate(priv, &i2c_t);
+ if (ret < 0)
+ goto out_pm_put;
+
+ rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
+
+ if (priv->devtype == I2C_RCAR_GEN3) {
+ priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (!IS_ERR(priv->rstc)) {
+ ret = reset_control_status(priv->rstc);
+ if (ret < 0)
+ priv->rstc = ERR_PTR(-ENOTSUPP);
+ }
+ }
+
+ /* Stay always active when multi-master to keep arbitration working */
+ if (of_property_read_bool(dev->of_node, "multi-master"))
+ priv->flags |= ID_P_PM_BLOCKED;
+ else
+ pm_runtime_put(dev);
+
+
+ priv->irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv);
+ if (ret < 0) {
+ dev_err(dev, "cannot get irq %d\n", priv->irq);
+ goto out_pm_disable;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret < 0)
+ goto out_pm_disable;
+
+ dev_info(dev, "probed\n");
+
+ return 0;
+
+ out_pm_put:
+ pm_runtime_put(dev);
+ out_pm_disable:
+ pm_runtime_disable(dev);
+ return ret;
+}
+
+static int rcar_i2c_remove(struct platform_device *pdev)
+{
+ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ i2c_del_adapter(&priv->adap);
+ rcar_i2c_release_dma(priv);
+ if (priv->flags & ID_P_PM_BLOCKED)
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+static struct platform_driver rcar_i2c_driver = {
+ .driver = {
+ .name = "i2c-rcar",
+ .of_match_table = rcar_i2c_dt_ids,
+ },
+ .probe = rcar_i2c_probe,
+ .remove = rcar_i2c_remove,
+};
+
+module_platform_driver(rcar_i2c_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
new file mode 100644
index 000000000..e6f351c92
--- /dev/null
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RIIC driver
+ *
+ * Copyright (C) 2013 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ */
+
+/*
+ * This i2c core has a lot of interrupts, namely 8. We use their chaining as
+ * some kind of state machine.
+ *
+ * 1) The main xfer routine kicks off a transmission by putting the start bit
+ * (or repeated start) on the bus and enabling the transmit interrupt (TIE)
+ * since we need to send the slave address + RW bit in every case.
+ *
+ * 2) TIE sends slave address + RW bit and selects how to continue.
+ *
+ * 3a) Write case: We keep utilizing TIE as long as we have data to send. If we
+ * are done, we switch over to the transmission done interrupt (TEIE) and mark
+ * the message as completed (includes sending STOP) there.
+ *
+ * 3b) Read case: We switch over to receive interrupt (RIE). One dummy read is
+ * needed to start clocking, then we keep receiving until we are done. Note
+ * that we use the RDRFS mode all the time, i.e. we ACK/NACK every byte by
+ * writing to the ACKBT bit. I tried using the RDRFS mode only at the end of a
+ * message to create the final NACK as sketched in the datasheet. This caused
+ * some subtle races (when byte n was processed and byte n+1 was already
+ * waiting), though, and I started with the safe approach.
+ *
+ * 4) If we got a NACK somewhere, we flag the error and stop the transmission
+ * via NAKIE.
+ *
+ * Also check the comments in the interrupt routines for some gory details.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define RIIC_ICCR1 0x00
+#define RIIC_ICCR2 0x04
+#define RIIC_ICMR1 0x08
+#define RIIC_ICMR3 0x10
+#define RIIC_ICSER 0x18
+#define RIIC_ICIER 0x1c
+#define RIIC_ICSR2 0x24
+#define RIIC_ICBRL 0x34
+#define RIIC_ICBRH 0x38
+#define RIIC_ICDRT 0x3c
+#define RIIC_ICDRR 0x40
+
+#define ICCR1_ICE 0x80
+#define ICCR1_IICRST 0x40
+#define ICCR1_SOWP 0x10
+
+#define ICCR2_BBSY 0x80
+#define ICCR2_SP 0x08
+#define ICCR2_RS 0x04
+#define ICCR2_ST 0x02
+
+#define ICMR1_CKS_MASK 0x70
+#define ICMR1_BCWP 0x08
+#define ICMR1_CKS(_x) ((((_x) << 4) & ICMR1_CKS_MASK) | ICMR1_BCWP)
+
+#define ICMR3_RDRFS 0x20
+#define ICMR3_ACKWP 0x10
+#define ICMR3_ACKBT 0x08
+
+#define ICIER_TIE 0x80
+#define ICIER_TEIE 0x40
+#define ICIER_RIE 0x20
+#define ICIER_NAKIE 0x10
+#define ICIER_SPIE 0x08
+
+#define ICSR2_NACKF 0x10
+
+#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */
+
+#define RIIC_INIT_MSG -1
+
+struct riic_dev {
+ void __iomem *base;
+ u8 *buf;
+ struct i2c_msg *msg;
+ int bytes_left;
+ int err;
+ int is_last;
+ struct completion msg_done;
+ struct i2c_adapter adapter;
+ struct clk *clk;
+};
+
+struct riic_irq_desc {
+ int res_num;
+ irq_handler_t isr;
+ char *name;
+};
+
+static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg)
+{
+ writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg);
+}
+
+static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct riic_dev *riic = i2c_get_adapdata(adap);
+ unsigned long time_left;
+ int i, ret;
+ u8 start_bit;
+
+ ret = clk_prepare_enable(riic->clk);
+ if (ret)
+ return ret;
+
+ if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) {
+ riic->err = -EBUSY;
+ goto out;
+ }
+
+ reinit_completion(&riic->msg_done);
+ riic->err = 0;
+
+ writeb(0, riic->base + RIIC_ICSR2);
+
+ for (i = 0, start_bit = ICCR2_ST; i < num; i++) {
+ riic->bytes_left = RIIC_INIT_MSG;
+ riic->buf = msgs[i].buf;
+ riic->msg = &msgs[i];
+ riic->is_last = (i == num - 1);
+
+ writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER);
+
+ writeb(start_bit, riic->base + RIIC_ICCR2);
+
+ time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout);
+ if (time_left == 0)
+ riic->err = -ETIMEDOUT;
+
+ if (riic->err)
+ break;
+
+ start_bit = ICCR2_RS;
+ }
+
+ out:
+ clk_disable_unprepare(riic->clk);
+
+ return riic->err ?: num;
+}
+
+static irqreturn_t riic_tdre_isr(int irq, void *data)
+{
+ struct riic_dev *riic = data;
+ u8 val;
+
+ if (!riic->bytes_left)
+ return IRQ_NONE;
+
+ if (riic->bytes_left == RIIC_INIT_MSG) {
+ if (riic->msg->flags & I2C_M_RD)
+ /* On read, switch over to receive interrupt */
+ riic_clear_set_bit(riic, ICIER_TIE, ICIER_RIE, RIIC_ICIER);
+ else
+ /* On write, initialize length */
+ riic->bytes_left = riic->msg->len;
+
+ val = i2c_8bit_addr_from_msg(riic->msg);
+ } else {
+ val = *riic->buf;
+ riic->buf++;
+ riic->bytes_left--;
+ }
+
+ /*
+ * Switch to transmission ended interrupt when done. Do check here
+ * after bytes_left was initialized to support SMBUS_QUICK (new msg has
+ * 0 length then)
+ */
+ if (riic->bytes_left == 0)
+ riic_clear_set_bit(riic, ICIER_TIE, ICIER_TEIE, RIIC_ICIER);
+
+ /*
+ * This acks the TIE interrupt. We get another TIE immediately if our
+ * value could be moved to the shadow shift register right away. So
+ * this must be after updates to ICIER (where we want to disable TIE)!
+ */
+ writeb(val, riic->base + RIIC_ICDRT);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t riic_tend_isr(int irq, void *data)
+{
+ struct riic_dev *riic = data;
+
+ if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
+ /* We got a NACKIE */
+ readb(riic->base + RIIC_ICDRR); /* dummy read */
+ riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
+ riic->err = -ENXIO;
+ } else if (riic->bytes_left) {
+ return IRQ_NONE;
+ }
+
+ if (riic->is_last || riic->err) {
+ riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER);
+ writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
+ } else {
+ /* Transfer is complete, but do not send STOP */
+ riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER);
+ complete(&riic->msg_done);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t riic_rdrf_isr(int irq, void *data)
+{
+ struct riic_dev *riic = data;
+
+ if (!riic->bytes_left)
+ return IRQ_NONE;
+
+ if (riic->bytes_left == RIIC_INIT_MSG) {
+ riic->bytes_left = riic->msg->len;
+ readb(riic->base + RIIC_ICDRR); /* dummy read */
+ return IRQ_HANDLED;
+ }
+
+ if (riic->bytes_left == 1) {
+ /* STOP must come before we set ACKBT! */
+ if (riic->is_last) {
+ riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
+ writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
+ }
+
+ riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
+
+ } else {
+ riic_clear_set_bit(riic, ICMR3_ACKBT, 0, RIIC_ICMR3);
+ }
+
+ /* Reading acks the RIE interrupt */
+ *riic->buf = readb(riic->base + RIIC_ICDRR);
+ riic->buf++;
+ riic->bytes_left--;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t riic_stop_isr(int irq, void *data)
+{
+ struct riic_dev *riic = data;
+
+ /* read back registers to confirm writes have fully propagated */
+ writeb(0, riic->base + RIIC_ICSR2);
+ readb(riic->base + RIIC_ICSR2);
+ writeb(0, riic->base + RIIC_ICIER);
+ readb(riic->base + RIIC_ICIER);
+
+ complete(&riic->msg_done);
+
+ return IRQ_HANDLED;
+}
+
+static u32 riic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm riic_algo = {
+ .master_xfer = riic_xfer,
+ .functionality = riic_func,
+};
+
+static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
+{
+ int ret;
+ unsigned long rate;
+ int total_ticks, cks, brl, brh;
+
+ ret = clk_prepare_enable(riic->clk);
+ if (ret)
+ return ret;
+
+ if (t->bus_freq_hz > 400000) {
+ dev_err(&riic->adapter.dev,
+ "unsupported bus speed (%dHz). 400000 max\n",
+ t->bus_freq_hz);
+ clk_disable_unprepare(riic->clk);
+ return -EINVAL;
+ }
+
+ rate = clk_get_rate(riic->clk);
+
+ /*
+ * Assume the default register settings:
+ * FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles)
+ * FER.NFE = 1 (noise circuit enabled)
+ * MR3.NF = 0 (1 cycle of noise filtered out)
+ *
+ * Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1)
+ * Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1)
+ */
+
+ /*
+ * Determine reference clock rate. We must be able to get the desired
+ * frequency with only 62 clock ticks max (31 high, 31 low).
+ * Aim for a duty of 60% LOW, 40% HIGH.
+ */
+ total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz);
+
+ for (cks = 0; cks < 7; cks++) {
+ /*
+ * 60% low time must be less than BRL + 2 + 1
+ * BRL max register value is 0x1F.
+ */
+ brl = ((total_ticks * 6) / 10);
+ if (brl <= (0x1F + 3))
+ break;
+
+ total_ticks /= 2;
+ rate /= 2;
+ }
+
+ if (brl > (0x1F + 3)) {
+ dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n",
+ (unsigned long)t->bus_freq_hz);
+ clk_disable_unprepare(riic->clk);
+ return -EINVAL;
+ }
+
+ brh = total_ticks - brl;
+
+ /* Remove automatic clock ticks for sync circuit and NF */
+ if (cks == 0) {
+ brl -= 4;
+ brh -= 4;
+ } else {
+ brl -= 3;
+ brh -= 3;
+ }
+
+ /*
+ * Remove clock ticks for rise and fall times. Convert ns to clock
+ * ticks.
+ */
+ brl -= t->scl_fall_ns / (1000000000 / rate);
+ brh -= t->scl_rise_ns / (1000000000 / rate);
+
+ /* Adjust for min register values for when SCLE=1 and NFE=1 */
+ if (brl < 1)
+ brl = 1;
+ if (brh < 1)
+ brh = 1;
+
+ pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n",
+ rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6),
+ t->scl_fall_ns / (1000000000 / rate),
+ t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
+
+ /* Changing the order of accessing IICRST and ICE may break things! */
+ writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
+ riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
+
+ writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
+ writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
+ writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
+
+ writeb(0, riic->base + RIIC_ICSER);
+ writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
+
+ riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1);
+
+ clk_disable_unprepare(riic->clk);
+
+ return 0;
+}
+
+static struct riic_irq_desc riic_irqs[] = {
+ { .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" },
+ { .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" },
+ { .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" },
+ { .res_num = 3, .isr = riic_stop_isr, .name = "riic-stop" },
+ { .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" },
+};
+
+static int riic_i2c_probe(struct platform_device *pdev)
+{
+ struct riic_dev *riic;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ struct i2c_timings i2c_t;
+ int i, ret;
+
+ riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
+ if (!riic)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ riic->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(riic->base))
+ return PTR_ERR(riic->base);
+
+ riic->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(riic->clk)) {
+ dev_err(&pdev->dev, "missing controller clock");
+ return PTR_ERR(riic->clk);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) {
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, riic_irqs[i].res_num);
+ if (!res)
+ return -ENODEV;
+
+ ret = devm_request_irq(&pdev->dev, res->start, riic_irqs[i].isr,
+ 0, riic_irqs[i].name, riic);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq %s\n", riic_irqs[i].name);
+ return ret;
+ }
+ }
+
+ adap = &riic->adapter;
+ i2c_set_adapdata(adap, riic);
+ strlcpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name));
+ adap->owner = THIS_MODULE;
+ adap->algo = &riic_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ init_completion(&riic->msg_done);
+
+ i2c_parse_fw_timings(&pdev->dev, &i2c_t, true);
+
+ ret = riic_init_hw(riic, &i2c_t);
+ if (ret)
+ return ret;
+
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, riic);
+
+ dev_info(&pdev->dev, "registered with %dHz bus speed\n",
+ i2c_t.bus_freq_hz);
+ return 0;
+}
+
+static int riic_i2c_remove(struct platform_device *pdev)
+{
+ struct riic_dev *riic = platform_get_drvdata(pdev);
+
+ writeb(0, riic->base + RIIC_ICIER);
+ i2c_del_adapter(&riic->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id riic_i2c_dt_ids[] = {
+ { .compatible = "renesas,riic-rz" },
+ { /* Sentinel */ },
+};
+
+static struct platform_driver riic_i2c_driver = {
+ .probe = riic_i2c_probe,
+ .remove = riic_i2c_remove,
+ .driver = {
+ .name = "i2c-riic",
+ .of_match_table = riic_i2c_dt_ids,
+ },
+};
+
+module_platform_driver(riic_i2c_driver);
+
+MODULE_DESCRIPTION("Renesas RIIC adapter");
+MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, riic_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
new file mode 100644
index 000000000..e76ad020a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -0,0 +1,1369 @@
+/*
+ * Driver for I2C adapter in Rockchip RK3xxx SoC
+ *
+ * Max Schwarz <max.schwarz@online.de>
+ * based on the patches by Rockchip Inc.
+ *
+ * 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/interrupt.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/math64.h>
+
+
+/* Register Map */
+#define REG_CON 0x00 /* control register */
+#define REG_CLKDIV 0x04 /* clock divisor register */
+#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */
+#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */
+#define REG_MTXCNT 0x10 /* number of bytes to be transmitted */
+#define REG_MRXCNT 0x14 /* number of bytes to be received */
+#define REG_IEN 0x18 /* interrupt enable */
+#define REG_IPD 0x1c /* interrupt pending */
+#define REG_FCNT 0x20 /* finished count */
+
+/* Data buffer offsets */
+#define TXBUFFER_BASE 0x100
+#define RXBUFFER_BASE 0x200
+
+/* REG_CON bits */
+#define REG_CON_EN BIT(0)
+enum {
+ REG_CON_MOD_TX = 0, /* transmit data */
+ REG_CON_MOD_REGISTER_TX, /* select register and restart */
+ REG_CON_MOD_RX, /* receive data */
+ REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes
+ * register addr */
+};
+#define REG_CON_MOD(mod) ((mod) << 1)
+#define REG_CON_MOD_MASK (BIT(1) | BIT(2))
+#define REG_CON_START BIT(3)
+#define REG_CON_STOP BIT(4)
+#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */
+#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */
+
+#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8)
+
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
+
+/* REG_MRXADDR bits */
+#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
+
+/* REG_IEN/REG_IPD bits */
+#define REG_INT_BTF BIT(0) /* a byte was transmitted */
+#define REG_INT_BRF BIT(1) /* a byte was received */
+#define REG_INT_MBTF BIT(2) /* master data transmit finished */
+#define REG_INT_MBRF BIT(3) /* master data receive finished */
+#define REG_INT_START BIT(4) /* START condition generated */
+#define REG_INT_STOP BIT(5) /* STOP condition generated */
+#define REG_INT_NAKRCV BIT(6) /* NACK received */
+#define REG_INT_ALL 0x7f
+
+/* Constants */
+#define WAIT_TIMEOUT 1000 /* ms */
+#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */
+
+/**
+ * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
+ */
+struct i2c_spec_values {
+ unsigned long min_hold_start_ns;
+ unsigned long min_low_ns;
+ unsigned long min_high_ns;
+ unsigned long min_setup_start_ns;
+ unsigned long max_data_hold_ns;
+ unsigned long min_data_setup_ns;
+ unsigned long min_setup_stop_ns;
+ unsigned long min_hold_buffer_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+ .min_hold_start_ns = 4000,
+ .min_low_ns = 4700,
+ .min_high_ns = 4000,
+ .min_setup_start_ns = 4700,
+ .max_data_hold_ns = 3450,
+ .min_data_setup_ns = 250,
+ .min_setup_stop_ns = 4000,
+ .min_hold_buffer_ns = 4700,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+ .min_hold_start_ns = 600,
+ .min_low_ns = 1300,
+ .min_high_ns = 600,
+ .min_setup_start_ns = 600,
+ .max_data_hold_ns = 900,
+ .min_data_setup_ns = 100,
+ .min_setup_stop_ns = 600,
+ .min_hold_buffer_ns = 1300,
+};
+
+static const struct i2c_spec_values fast_mode_plus_spec = {
+ .min_hold_start_ns = 260,
+ .min_low_ns = 500,
+ .min_high_ns = 260,
+ .min_setup_start_ns = 260,
+ .max_data_hold_ns = 400,
+ .min_data_setup_ns = 50,
+ .min_setup_stop_ns = 260,
+ .min_hold_buffer_ns = 500,
+};
+
+/**
+ * struct rk3x_i2c_calced_timings:
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
+ */
+struct rk3x_i2c_calced_timings {
+ unsigned long div_low;
+ unsigned long div_high;
+ unsigned int tuning;
+};
+
+enum rk3x_i2c_state {
+ STATE_IDLE,
+ STATE_START,
+ STATE_READ,
+ STATE_WRITE,
+ STATE_STOP
+};
+
+/**
+ * struct rk3x_i2c_soc_data:
+ * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
+ */
+struct rk3x_i2c_soc_data {
+ int grf_offset;
+ int (*calc_timings)(unsigned long, struct i2c_timings *,
+ struct rk3x_i2c_calced_timings *);
+};
+
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
+struct rk3x_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ const struct rk3x_i2c_soc_data *soc_data;
+
+ /* Hardware resources */
+ void __iomem *regs;
+ struct clk *clk;
+ struct clk *pclk;
+ struct notifier_block clk_rate_nb;
+
+ /* Settings */
+ struct i2c_timings t;
+
+ /* Synchronization & notification */
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ bool busy;
+
+ /* Current message */
+ struct i2c_msg *msg;
+ u8 addr;
+ unsigned int mode;
+ bool is_last_msg;
+
+ /* I2C state machine */
+ enum rk3x_i2c_state state;
+ unsigned int processed;
+ int error;
+};
+
+static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value,
+ unsigned int offset)
+{
+ writel(value, i2c->regs + offset);
+}
+
+static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset)
+{
+ return readl(i2c->regs + offset);
+}
+
+/* Reset all interrupt pending bits */
+static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
+{
+ i2c_writel(i2c, REG_INT_ALL, REG_IPD);
+}
+
+/**
+ * Generate a START condition, which triggers a REG_INT_START interrupt.
+ */
+static void rk3x_i2c_start(struct rk3x_i2c *i2c)
+{
+ u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+
+ i2c_writel(i2c, REG_INT_START, REG_IEN);
+
+ /* enable adapter with correct mode, send START condition */
+ val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+
+ /* if we want to react to NACK, set ACTACK bit */
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
+ val |= REG_CON_ACTACK;
+
+ i2c_writel(i2c, val, REG_CON);
+}
+
+/**
+ * Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
+ *
+ * @error: Error code to return in rk3x_i2c_xfer
+ */
+static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
+{
+ unsigned int ctrl;
+
+ i2c->processed = 0;
+ i2c->msg = NULL;
+ i2c->error = error;
+
+ if (i2c->is_last_msg) {
+ /* Enable stop interrupt */
+ i2c_writel(i2c, REG_INT_STOP, REG_IEN);
+
+ i2c->state = STATE_STOP;
+
+ ctrl = i2c_readl(i2c, REG_CON);
+ ctrl |= REG_CON_STOP;
+ i2c_writel(i2c, ctrl, REG_CON);
+ } else {
+ /* Signal rk3x_i2c_xfer to start the next message. */
+ i2c->busy = false;
+ i2c->state = STATE_IDLE;
+
+ /*
+ * The HW is actually not capable of REPEATED START. But we can
+ * get the intended effect by resetting its internal state
+ * and issuing an ordinary START.
+ */
+ ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+ i2c_writel(i2c, ctrl, REG_CON);
+
+ /* signal that we are finished with the current msg */
+ wake_up(&i2c->wait);
+ }
+}
+
+/**
+ * Setup a read according to i2c->msg
+ */
+static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
+{
+ unsigned int len = i2c->msg->len - i2c->processed;
+ u32 con;
+
+ con = i2c_readl(i2c, REG_CON);
+
+ /*
+ * The hw can read up to 32 bytes at a time. If we need more than one
+ * chunk, send an ACK after the last byte of the current chunk.
+ */
+ if (len > 32) {
+ len = 32;
+ con &= ~REG_CON_LASTACK;
+ } else {
+ con |= REG_CON_LASTACK;
+ }
+
+ /* make sure we are in plain RX mode if we read a second chunk */
+ if (i2c->processed != 0) {
+ con &= ~REG_CON_MOD_MASK;
+ con |= REG_CON_MOD(REG_CON_MOD_RX);
+ }
+
+ i2c_writel(i2c, con, REG_CON);
+ i2c_writel(i2c, len, REG_MRXCNT);
+}
+
+/**
+ * Fill the transmit buffer with data from i2c->msg
+ */
+static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
+{
+ unsigned int i, j;
+ u32 cnt = 0;
+ u32 val;
+ u8 byte;
+
+ for (i = 0; i < 8; ++i) {
+ val = 0;
+ for (j = 0; j < 4; ++j) {
+ if ((i2c->processed == i2c->msg->len) && (cnt != 0))
+ break;
+
+ if (i2c->processed == 0 && cnt == 0)
+ byte = (i2c->addr & 0x7f) << 1;
+ else
+ byte = i2c->msg->buf[i2c->processed++];
+
+ val |= byte << (j * 8);
+ cnt++;
+ }
+
+ i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i);
+
+ if (i2c->processed == i2c->msg->len)
+ break;
+ }
+
+ i2c_writel(i2c, cnt, REG_MTXCNT);
+}
+
+
+/* IRQ handlers for individual states */
+
+static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ if (!(ipd & REG_INT_START)) {
+ rk3x_i2c_stop(i2c, -EIO);
+ dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ return;
+ }
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_START, REG_IPD);
+
+ /* disable start bit */
+ i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON);
+
+ /* enable appropriate interrupts and transition */
+ if (i2c->mode == REG_CON_MOD_TX) {
+ i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN);
+ i2c->state = STATE_WRITE;
+ rk3x_i2c_fill_transmit_buf(i2c);
+ } else {
+ /* in any other case, we are going to be reading. */
+ i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN);
+ i2c->state = STATE_READ;
+ rk3x_i2c_prepare_read(i2c);
+ }
+}
+
+static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ if (!(ipd & REG_INT_MBTF)) {
+ rk3x_i2c_stop(i2c, -EIO);
+ dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ return;
+ }
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_MBTF, REG_IPD);
+
+ /* are we finished? */
+ if (i2c->processed == i2c->msg->len)
+ rk3x_i2c_stop(i2c, i2c->error);
+ else
+ rk3x_i2c_fill_transmit_buf(i2c);
+}
+
+static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ unsigned int i;
+ unsigned int len = i2c->msg->len - i2c->processed;
+ u32 uninitialized_var(val);
+ u8 byte;
+
+ /* we only care for MBRF here. */
+ if (!(ipd & REG_INT_MBRF))
+ return;
+
+ /* ack interrupt (read also produces a spurious START flag, clear it too) */
+ i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD);
+
+ /* Can only handle a maximum of 32 bytes at a time */
+ if (len > 32)
+ len = 32;
+
+ /* read the data from receive buffer */
+ for (i = 0; i < len; ++i) {
+ if (i % 4 == 0)
+ val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4);
+
+ byte = (val >> ((i % 4) * 8)) & 0xff;
+ i2c->msg->buf[i2c->processed++] = byte;
+ }
+
+ /* are we finished? */
+ if (i2c->processed == i2c->msg->len)
+ rk3x_i2c_stop(i2c, i2c->error);
+ else
+ rk3x_i2c_prepare_read(i2c);
+}
+
+static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+ unsigned int con;
+
+ if (!(ipd & REG_INT_STOP)) {
+ rk3x_i2c_stop(i2c, -EIO);
+ dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ return;
+ }
+
+ /* ack interrupt */
+ i2c_writel(i2c, REG_INT_STOP, REG_IPD);
+
+ /* disable STOP bit */
+ con = i2c_readl(i2c, REG_CON);
+ con &= ~REG_CON_STOP;
+ i2c_writel(i2c, con, REG_CON);
+
+ i2c->busy = false;
+ i2c->state = STATE_IDLE;
+
+ /* signal rk3x_i2c_xfer that we are finished */
+ wake_up(&i2c->wait);
+}
+
+static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
+{
+ struct rk3x_i2c *i2c = dev_id;
+ unsigned int ipd;
+
+ spin_lock(&i2c->lock);
+
+ ipd = i2c_readl(i2c, REG_IPD);
+ if (i2c->state == STATE_IDLE) {
+ dev_warn(i2c->dev, "irq in STATE_IDLE, ipd = 0x%x\n", ipd);
+ rk3x_i2c_clean_ipd(i2c);
+ goto out;
+ }
+
+ dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd);
+
+ /* Clean interrupt bits we don't care about */
+ ipd &= ~(REG_INT_BRF | REG_INT_BTF);
+
+ if (ipd & REG_INT_NAKRCV) {
+ /*
+ * We got a NACK in the last operation. Depending on whether
+ * IGNORE_NAK is set, we have to stop the operation and report
+ * an error.
+ */
+ i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD);
+
+ ipd &= ~REG_INT_NAKRCV;
+
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
+ rk3x_i2c_stop(i2c, -ENXIO);
+ }
+
+ /* is there anything left to handle? */
+ if ((ipd & REG_INT_ALL) == 0)
+ goto out;
+
+ switch (i2c->state) {
+ case STATE_START:
+ rk3x_i2c_handle_start(i2c, ipd);
+ break;
+ case STATE_WRITE:
+ rk3x_i2c_handle_write(i2c, ipd);
+ break;
+ case STATE_READ:
+ rk3x_i2c_handle_read(i2c, ipd);
+ break;
+ case STATE_STOP:
+ rk3x_i2c_handle_stop(i2c, ipd);
+ break;
+ case STATE_IDLE:
+ break;
+ }
+
+out:
+ spin_unlock(&i2c->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+ if (speed <= 100000)
+ return &standard_mode_spec;
+ else if (speed <= 400000)
+ return &fast_mode_spec;
+ else
+ return &fast_mode_plus_spec;
+}
+
+/**
+ * Calculate divider values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ */
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+ struct i2c_timings *t,
+ struct rk3x_i2c_calced_timings *t_calc)
+{
+ unsigned long min_low_ns, min_high_ns;
+ unsigned long max_low_ns, min_total_ns;
+
+ unsigned long clk_rate_khz, scl_rate_khz;
+
+ unsigned long min_low_div, min_high_div;
+ unsigned long max_low_div;
+
+ unsigned long min_div_for_hold, min_total_div;
+ unsigned long extra_div, extra_low_div, ideal_low_div;
+
+ unsigned long data_hold_buffer_ns = 50;
+ const struct i2c_spec_values *spec;
+ int ret = 0;
+
+ /* Only support standard-mode and fast-mode */
+ if (WARN_ON(t->bus_freq_hz > 400000))
+ t->bus_freq_hz = 400000;
+
+ /* prevent scl_rate_khz from becoming 0 */
+ if (WARN_ON(t->bus_freq_hz < 1000))
+ t->bus_freq_hz = 1000;
+
+ /*
+ * min_low_ns: The minimum number of ns we need to hold low to
+ * meet I2C specification, should include fall time.
+ * min_high_ns: The minimum number of ns we need to hold high to
+ * meet I2C specification, should include rise time.
+ * max_low_ns: The maximum number of ns we can hold low to meet
+ * I2C specification.
+ *
+ * Note: max_low_ns should be (maximum data hold time * 2 - buffer)
+ * This is because the i2c host on Rockchip holds the data line
+ * for half the low time.
+ */
+ spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+ min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+
+ /*
+ * Timings for repeated start:
+ * - controller appears to drop SDA at .875x (7/8) programmed clk high.
+ * - controller appears to keep SCL high for 2x programmed clk high.
+ *
+ * We need to account for those rules in picking our "high" time so
+ * we meet tSU;STA and tHD;STA times.
+ */
+ min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+ (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+ min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+ (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+ spec->min_high_ns), 2));
+
+ min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+ max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
+ min_total_ns = min_low_ns + min_high_ns;
+
+ /* Adjust to avoid overflow */
+ clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+ scl_rate_khz = t->bus_freq_hz / 1000;
+
+ /*
+ * We need the total div to be >= this number
+ * so we don't clock too fast.
+ */
+ min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+ /* These are the min dividers needed for min hold times. */
+ min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+ min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+ min_div_for_hold = (min_low_div + min_high_div);
+
+ /*
+ * This is the maximum divider so we don't go over the maximum.
+ * We don't round up here (we round down) since this is a maximum.
+ */
+ max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
+
+ if (min_low_div > max_low_div) {
+ WARN_ONCE(true,
+ "Conflicting, min_low_div %lu, max_low_div %lu\n",
+ min_low_div, max_low_div);
+ max_low_div = min_low_div;
+ }
+
+ if (min_div_for_hold > min_total_div) {
+ /*
+ * Time needed to meet hold requirements is important.
+ * Just use that.
+ */
+ t_calc->div_low = min_low_div;
+ t_calc->div_high = min_high_div;
+ } else {
+ /*
+ * We've got to distribute some time among the low and high
+ * so we don't run too fast.
+ */
+ extra_div = min_total_div - min_div_for_hold;
+
+ /*
+ * We'll try to split things up perfectly evenly,
+ * biasing slightly towards having a higher div
+ * for low (spend more time low).
+ */
+ ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
+ scl_rate_khz * 8 * min_total_ns);
+
+ /* Don't allow it to go over the maximum */
+ if (ideal_low_div > max_low_div)
+ ideal_low_div = max_low_div;
+
+ /*
+ * Handle when the ideal low div is going to take up
+ * more than we have.
+ */
+ if (ideal_low_div > min_low_div + extra_div)
+ ideal_low_div = min_low_div + extra_div;
+
+ /* Give low the "ideal" and give high whatever extra is left */
+ extra_low_div = ideal_low_div - min_low_div;
+ t_calc->div_low = ideal_low_div;
+ t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+ }
+
+ /*
+ * Adjust to the fact that the hardware has an implicit "+1".
+ * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
+ */
+ t_calc->div_low--;
+ t_calc->div_high--;
+
+ /* Give the tuning value 0, that would not update con register */
+ t_calc->tuning = 0;
+ /* Maximum divider supported by hw is 0xffff */
+ if (t_calc->div_low > 0xffff) {
+ t_calc->div_low = 0xffff;
+ ret = -EINVAL;
+ }
+
+ if (t_calc->div_high > 0xffff) {
+ t_calc->div_high = 0xffff;
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * Calculate timing values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+ *
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+ *
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+ *
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+ struct i2c_timings *t,
+ struct rk3x_i2c_calced_timings *t_calc)
+{
+ unsigned long min_low_ns, min_high_ns;
+ unsigned long min_setup_start_ns, min_setup_data_ns;
+ unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+ unsigned long clk_rate_khz, scl_rate_khz;
+
+ unsigned long min_low_div, min_high_div;
+
+ unsigned long min_div_for_hold, min_total_div;
+ unsigned long extra_div, extra_low_div;
+ unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+ const struct i2c_spec_values *spec;
+ int ret = 0;
+
+ /* Support standard-mode, fast-mode and fast-mode plus */
+ if (WARN_ON(t->bus_freq_hz > 1000000))
+ t->bus_freq_hz = 1000000;
+
+ /* prevent scl_rate_khz from becoming 0 */
+ if (WARN_ON(t->bus_freq_hz < 1000))
+ t->bus_freq_hz = 1000;
+
+ /*
+ * min_low_ns: The minimum number of ns we need to hold low to
+ * meet I2C specification, should include fall time.
+ * min_high_ns: The minimum number of ns we need to hold high to
+ * meet I2C specification, should include rise time.
+ */
+ spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+ /* calculate min-divh and min-divl */
+ clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+ scl_rate_khz = t->bus_freq_hz / 1000;
+ min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+ min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+ min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+ min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+ min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+ /*
+ * Final divh and divl must be greater than 0, otherwise the
+ * hardware would not output the i2c clk.
+ */
+ min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+ min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+ /* These are the min dividers needed for min hold times. */
+ min_div_for_hold = (min_low_div + min_high_div);
+
+ /*
+ * This is the maximum divider so we don't go over the maximum.
+ * We don't round up here (we round down) since this is a maximum.
+ */
+ if (min_div_for_hold >= min_total_div) {
+ /*
+ * Time needed to meet hold requirements is important.
+ * Just use that.
+ */
+ t_calc->div_low = min_low_div;
+ t_calc->div_high = min_high_div;
+ } else {
+ /*
+ * We've got to distribute some time among the low and high
+ * so we don't run too fast.
+ * We'll try to split things up by the scale of min_low_div and
+ * min_high_div, biasing slightly towards having a higher div
+ * for low (spend more time low).
+ */
+ extra_div = min_total_div - min_div_for_hold;
+ extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+ min_div_for_hold);
+
+ t_calc->div_low = min_low_div + extra_low_div;
+ t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+ }
+
+ /*
+ * calculate sda data hold count by the rules, data_upd_st:3
+ * is a appropriate value to reduce calculated times.
+ */
+ for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+ max_hold_data_ns = DIV_ROUND_UP((sda_update_cfg
+ * (t_calc->div_low) + 1)
+ * 1000000, clk_rate_khz);
+ min_setup_data_ns = DIV_ROUND_UP(((8 - sda_update_cfg)
+ * (t_calc->div_low) + 1)
+ * 1000000, clk_rate_khz);
+ if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+ (min_setup_data_ns > spec->min_data_setup_ns))
+ break;
+ }
+
+ /* calculate setup start config */
+ min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+ stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+ - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+ /* calculate setup stop config */
+ min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+ stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+ - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+ t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+ REG_CON_STA_CFG(--stp_sta_cfg) |
+ REG_CON_STO_CFG(--stp_sto_cfg);
+
+ t_calc->div_low--;
+ t_calc->div_high--;
+
+ /* Maximum divider supported by hw is 0xffff */
+ if (t_calc->div_low > 0xffff) {
+ t_calc->div_low = 0xffff;
+ ret = -EINVAL;
+ }
+
+ if (t_calc->div_high > 0xffff) {
+ t_calc->div_high = 0xffff;
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
+{
+ struct i2c_timings *t = &i2c->t;
+ struct rk3x_i2c_calced_timings calc;
+ u64 t_low_ns, t_high_ns;
+ unsigned long flags;
+ u32 val;
+ int ret;
+
+ ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
+ WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
+
+ clk_enable(i2c->pclk);
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ val = i2c_readl(i2c, REG_CON);
+ val &= ~REG_CON_TUNING_MASK;
+ val |= calc.tuning;
+ i2c_writel(i2c, val, REG_CON);
+ i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+ REG_CLKDIV);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ clk_disable(i2c->pclk);
+
+ t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+ t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+ clk_rate);
+ dev_dbg(i2c->dev,
+ "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
+ clk_rate / 1000,
+ 1000000000 / t->bus_freq_hz,
+ t_low_ns, t_high_ns);
+}
+
+/**
+ * rk3x_i2c_clk_notifier_cb - Clock rate change callback
+ * @nb: Pointer to notifier block
+ * @event: Notification reason
+ * @data: Pointer to notification data object
+ *
+ * The callback checks whether a valid bus frequency can be generated after the
+ * change. If so, the change is acknowledged, otherwise the change is aborted.
+ * New dividers are written to the HW in the pre- or post change notification
+ * depending on the scaling direction.
+ *
+ * Code adapted from i2c-cadence.c.
+ *
+ * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
+ * to acknowledge the change, NOTIFY_DONE if the notification is
+ * considered irrelevant.
+ */
+static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
+ event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
+ struct rk3x_i2c_calced_timings calc;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ /*
+ * Try the calculation (but don't store the result) ahead of
+ * time to see if we need to block the clock change. Timings
+ * shouldn't actually take effect until rk3x_i2c_adapt_div().
+ */
+ if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+ &calc) != 0)
+ return NOTIFY_STOP;
+
+ /* scale up */
+ if (ndata->new_rate > ndata->old_rate)
+ rk3x_i2c_adapt_div(i2c, ndata->new_rate);
+
+ return NOTIFY_OK;
+ case POST_RATE_CHANGE:
+ /* scale down */
+ if (ndata->new_rate < ndata->old_rate)
+ rk3x_i2c_adapt_div(i2c, ndata->new_rate);
+ return NOTIFY_OK;
+ case ABORT_RATE_CHANGE:
+ /* scale up */
+ if (ndata->new_rate > ndata->old_rate)
+ rk3x_i2c_adapt_div(i2c, ndata->old_rate);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+/**
+ * Setup I2C registers for an I2C operation specified by msgs, num.
+ *
+ * Must be called with i2c->lock held.
+ *
+ * @msgs: I2C msgs to process
+ * @num: Number of msgs
+ *
+ * returns: Number of I2C msgs processed or negative in case of error
+ */
+static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
+{
+ u32 addr = (msgs[0].addr & 0x7f) << 1;
+ int ret = 0;
+
+ /*
+ * The I2C adapter can issue a small (len < 4) write packet before
+ * reading. This speeds up SMBus-style register reads.
+ * The MRXADDR/MRXRADDR hold the slave address and the slave register
+ * address in this case.
+ */
+
+ if (num >= 2 && msgs[0].len < 4 &&
+ !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+ u32 reg_addr = 0;
+ int i;
+
+ dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n",
+ addr >> 1);
+
+ /* Fill MRXRADDR with the register address(es) */
+ for (i = 0; i < msgs[0].len; ++i) {
+ reg_addr |= msgs[0].buf[i] << (i * 8);
+ reg_addr |= REG_MRXADDR_VALID(i);
+ }
+
+ /* msgs[0] is handled by hw. */
+ i2c->msg = &msgs[1];
+
+ i2c->mode = REG_CON_MOD_REGISTER_TX;
+
+ i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR);
+ i2c_writel(i2c, reg_addr, REG_MRXRADDR);
+
+ ret = 2;
+ } else {
+ /*
+ * We'll have to do it the boring way and process the msgs
+ * one-by-one.
+ */
+
+ if (msgs[0].flags & I2C_M_RD) {
+ addr |= 1; /* set read bit */
+
+ /*
+ * We have to transmit the slave addr first. Use
+ * MOD_REGISTER_TX for that purpose.
+ */
+ i2c->mode = REG_CON_MOD_REGISTER_TX;
+ i2c_writel(i2c, addr | REG_MRXADDR_VALID(0),
+ REG_MRXADDR);
+ i2c_writel(i2c, 0, REG_MRXRADDR);
+ } else {
+ i2c->mode = REG_CON_MOD_TX;
+ }
+
+ i2c->msg = &msgs[0];
+
+ ret = 1;
+ }
+
+ i2c->addr = msgs[0].addr;
+ i2c->busy = true;
+ i2c->state = STATE_START;
+ i2c->processed = 0;
+ i2c->error = 0;
+
+ rk3x_i2c_clean_ipd(i2c);
+
+ return ret;
+}
+
+static int rk3x_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
+ unsigned long timeout, flags;
+ u32 val;
+ int ret = 0;
+ int i;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ clk_enable(i2c->clk);
+ clk_enable(i2c->pclk);
+
+ i2c->is_last_msg = false;
+
+ /*
+ * Process msgs. We can handle more than one message at once (see
+ * rk3x_i2c_setup()).
+ */
+ for (i = 0; i < num; i += ret) {
+ ret = rk3x_i2c_setup(i2c, msgs + i, num - i);
+
+ if (ret < 0) {
+ dev_err(i2c->dev, "rk3x_i2c_setup() failed\n");
+ break;
+ }
+
+ if (i + ret >= num)
+ i2c->is_last_msg = true;
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ rk3x_i2c_start(i2c);
+
+ timeout = wait_event_timeout(i2c->wait, !i2c->busy,
+ msecs_to_jiffies(WAIT_TIMEOUT));
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ if (timeout == 0) {
+ dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n",
+ i2c_readl(i2c, REG_IPD), i2c->state);
+
+ /* Force a STOP condition without interrupt */
+ i2c_writel(i2c, 0, REG_IEN);
+ val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+ val |= REG_CON_EN | REG_CON_STOP;
+ i2c_writel(i2c, val, REG_CON);
+
+ i2c->state = STATE_IDLE;
+
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ if (i2c->error) {
+ ret = i2c->error;
+ break;
+ }
+ }
+
+ clk_disable(i2c->pclk);
+ clk_disable(i2c->clk);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ return ret < 0 ? ret : num;
+}
+
+static __maybe_unused int rk3x_i2c_resume(struct device *dev)
+{
+ struct rk3x_i2c *i2c = dev_get_drvdata(dev);
+
+ rk3x_i2c_adapt_div(i2c, clk_get_rate(i2c->clk));
+
+ return 0;
+}
+
+static u32 rk3x_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm rk3x_i2c_algorithm = {
+ .master_xfer = rk3x_i2c_xfer,
+ .functionality = rk3x_i2c_func,
+};
+
+static const struct rk3x_i2c_soc_data rv1108_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v1_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+ .grf_offset = 0x154,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+ .grf_offset = 0x0a4,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v1_calc_timings,
+};
+
+static const struct of_device_id rk3x_i2c_match[] = {
+ {
+ .compatible = "rockchip,rv1108-i2c",
+ .data = &rv1108_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3066-i2c",
+ .data = &rk3066_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3188-i2c",
+ .data = &rk3188_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3228-i2c",
+ .data = &rk3228_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3288-i2c",
+ .data = &rk3288_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3399-i2c",
+ .data = &rk3399_soc_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
+
+static int rk3x_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ struct rk3x_i2c *i2c;
+ struct resource *mem;
+ int ret = 0;
+ int bus_nr;
+ u32 value;
+ int irq;
+ unsigned long clk_rate;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ match = of_match_node(rk3x_i2c_match, np);
+ i2c->soc_data = match->data;
+
+ /* use common interface to get I2C timing properties */
+ i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
+
+ strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &rk3x_i2c_algorithm;
+ i2c->adap.retries = 3;
+ i2c->adap.dev.of_node = np;
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &pdev->dev;
+
+ i2c->dev = &pdev->dev;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ /* Try to set the I2C adapter number from dt */
+ bus_nr = of_alias_get_id(np, "i2c");
+
+ /*
+ * Switch to new interface if the SoC also offers the old one.
+ * The control bit is located in the GRF register space.
+ */
+ if (i2c->soc_data->grf_offset >= 0) {
+ struct regmap *grf;
+
+ grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(grf)) {
+ dev_err(&pdev->dev,
+ "rk3x-i2c needs 'rockchip,grf' property\n");
+ return PTR_ERR(grf);
+ }
+
+ if (bus_nr < 0) {
+ dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias");
+ return -EINVAL;
+ }
+
+ /* 27+i: write mask, 11+i: value */
+ value = BIT(27 + bus_nr) | BIT(11 + bus_nr);
+
+ ret = regmap_write(grf, i2c->soc_data->grf_offset, value);
+ if (ret != 0) {
+ dev_err(i2c->dev, "Could not write to GRF: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* IRQ setup */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "cannot find rk3x IRQ\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq,
+ 0, dev_name(&pdev->dev), i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot request IRQ\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+ /* Only one clock to use for bus clock and peripheral clock */
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ i2c->pclk = i2c->clk;
+ } else {
+ i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+ i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+ }
+
+ if (IS_ERR(i2c->clk)) {
+ ret = PTR_ERR(i2c->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
+ return ret;
+ }
+ if (IS_ERR(i2c->pclk)) {
+ ret = PTR_ERR(i2c->pclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare(i2c->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare(i2c->pclk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
+ goto err_clk;
+ }
+
+ i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
+ ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Unable to register clock notifier\n");
+ goto err_pclk;
+ }
+
+ clk_rate = clk_get_rate(i2c->clk);
+ rk3x_i2c_adapt_div(i2c, clk_rate);
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0)
+ goto err_clk_notifier;
+
+ return 0;
+
+err_clk_notifier:
+ clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+ clk_unprepare(i2c->pclk);
+err_clk:
+ clk_unprepare(i2c->clk);
+ return ret;
+}
+
+static int rk3x_i2c_remove(struct platform_device *pdev)
+{
+ struct rk3x_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+
+ clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+ clk_unprepare(i2c->pclk);
+ clk_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume);
+
+static struct platform_driver rk3x_i2c_driver = {
+ .probe = rk3x_i2c_probe,
+ .remove = rk3x_i2c_remove,
+ .driver = {
+ .name = "rk3x-i2c",
+ .of_match_table = rk3x_i2c_match,
+ .pm = &rk3x_i2c_pm_ops,
+ },
+};
+
+module_platform_driver(rk3x_i2c_driver);
+
+MODULE_DESCRIPTION("Rockchip RK3xxx I2C Bus driver");
+MODULE_AUTHOR("Max Schwarz <max.schwarz@online.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c
new file mode 100644
index 000000000..3fe21397a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c
@@ -0,0 +1,199 @@
+/*
+ * Driver for RobotFuzz OSIF
+ *
+ * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch>
+ * Copyright (c) 2007 Barry Carter <Barry.Carter@robotfuzz.com>
+ *
+ * Based on the i2c-tiny-usb by
+ *
+ * Copyright (C) 2006 Til Harbaum (Till@Harbaum.org)
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#define OSIFI2C_READ 20
+#define OSIFI2C_WRITE 21
+#define OSIFI2C_STOP 22
+#define OSIFI2C_STATUS 23
+#define OSIFI2C_SET_BIT_RATE 24
+
+#define STATUS_ADDRESS_ACK 0
+#define STATUS_ADDRESS_NAK 2
+
+struct osif_priv {
+ struct usb_device *usb_dev;
+ struct usb_interface *interface;
+ struct i2c_adapter adapter;
+ unsigned char status;
+};
+
+static int osif_usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct osif_priv *priv = adapter->algo_data;
+
+ return usb_control_msg(priv->usb_dev, usb_rcvctrlpipe(priv->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+ USB_DIR_IN, value, index, data, len, 2000);
+}
+
+static int osif_usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+
+ struct osif_priv *priv = adapter->algo_data;
+
+ return usb_control_msg(priv->usb_dev, usb_sndctrlpipe(priv->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, data, len, 2000);
+}
+
+static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+ int num)
+{
+ struct osif_priv *priv = adapter->algo_data;
+ struct i2c_msg *pmsg;
+ int ret;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+
+ if (pmsg->flags & I2C_M_RD) {
+ ret = osif_usb_read(adapter, OSIFI2C_READ,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len);
+ if (ret != pmsg->len) {
+ dev_err(&adapter->dev, "failure reading data\n");
+ return -EREMOTEIO;
+ }
+ } else {
+ ret = osif_usb_write(adapter, OSIFI2C_WRITE,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len);
+ if (ret != pmsg->len) {
+ dev_err(&adapter->dev, "failure writing data\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ ret = osif_usb_write(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
+ if (ret) {
+ dev_err(&adapter->dev, "failure sending STOP\n");
+ return -EREMOTEIO;
+ }
+
+ /* read status */
+ ret = osif_usb_read(adapter, OSIFI2C_STATUS, 0, 0,
+ &priv->status, 1);
+ if (ret != 1) {
+ dev_err(&adapter->dev, "failure reading status\n");
+ return -EREMOTEIO;
+ }
+
+ if (priv->status != STATUS_ADDRESS_ACK) {
+ dev_dbg(&adapter->dev, "status = %d\n", priv->status);
+ return -EREMOTEIO;
+ }
+ }
+
+ return i;
+}
+
+static u32 osif_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm osif_algorithm = {
+ .master_xfer = osif_xfer,
+ .functionality = osif_func,
+};
+
+#define USB_OSIF_VENDOR_ID 0x1964
+#define USB_OSIF_PRODUCT_ID 0x0001
+
+static const struct usb_device_id osif_table[] = {
+ { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, osif_table);
+
+static int osif_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ret;
+ struct osif_priv *priv;
+ u16 version;
+
+ priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ priv->interface = interface;
+
+ usb_set_intfdata(interface, priv);
+
+ priv->adapter.owner = THIS_MODULE;
+ priv->adapter.class = I2C_CLASS_HWMON;
+ priv->adapter.algo = &osif_algorithm;
+ priv->adapter.algo_data = priv;
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+ "OSIF at bus %03d device %03d",
+ priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
+
+ /*
+ * Set bus frequency. The frequency is:
+ * 120,000,000 / ( 16 + 2 * div * 4^prescale).
+ * Using dev = 52, prescale = 0 give 100KHz */
+ ret = osif_usb_write(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
+ NULL, 0);
+ if (ret) {
+ dev_err(&interface->dev, "failure sending bit rate");
+ usb_put_dev(priv->usb_dev);
+ return ret;
+ }
+
+ i2c_add_adapter(&(priv->adapter));
+
+ version = le16_to_cpu(priv->usb_dev->descriptor.bcdDevice);
+ dev_info(&interface->dev,
+ "version %x.%02x found at bus %03d address %03d",
+ version >> 8, version & 0xff,
+ priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
+
+ return 0;
+}
+
+static void osif_disconnect(struct usb_interface *interface)
+{
+ struct osif_priv *priv = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&(priv->adapter));
+ usb_set_intfdata(interface, NULL);
+ usb_put_dev(priv->usb_dev);
+}
+
+static struct usb_driver osif_driver = {
+ .name = "RobotFuzz Open Source InterFace, OSIF",
+ .probe = osif_probe,
+ .disconnect = osif_disconnect,
+ .id_table = osif_table,
+};
+
+module_usb_driver(osif_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
+MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>");
+MODULE_DESCRIPTION("RobotFuzz OSIF driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
new file mode 100644
index 000000000..4c6036920
--- /dev/null
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -0,0 +1,1315 @@
+/* linux/drivers/i2c/busses/i2c-s3c2410.c
+ *
+ * Copyright (C) 2004,2005,2009 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 I2C Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/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/pm_runtime.h>
+#include <linux/clk.h>
+#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>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include <asm/irq.h>
+
+#include <linux/platform_data/i2c-s3c2410.h>
+
+/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */
+
+#define S3C2410_IICCON 0x00
+#define S3C2410_IICSTAT 0x04
+#define S3C2410_IICADD 0x08
+#define S3C2410_IICDS 0x0C
+#define S3C2440_IICLC 0x10
+
+#define S3C2410_IICCON_ACKEN (1 << 7)
+#define S3C2410_IICCON_TXDIV_16 (0 << 6)
+#define S3C2410_IICCON_TXDIV_512 (1 << 6)
+#define S3C2410_IICCON_IRQEN (1 << 5)
+#define S3C2410_IICCON_IRQPEND (1 << 4)
+#define S3C2410_IICCON_SCALE(x) ((x) & 0xf)
+#define S3C2410_IICCON_SCALEMASK (0xf)
+
+#define S3C2410_IICSTAT_MASTER_RX (2 << 6)
+#define S3C2410_IICSTAT_MASTER_TX (3 << 6)
+#define S3C2410_IICSTAT_SLAVE_RX (0 << 6)
+#define S3C2410_IICSTAT_SLAVE_TX (1 << 6)
+#define S3C2410_IICSTAT_MODEMASK (3 << 6)
+
+#define S3C2410_IICSTAT_START (1 << 5)
+#define S3C2410_IICSTAT_BUSBUSY (1 << 5)
+#define S3C2410_IICSTAT_TXRXEN (1 << 4)
+#define S3C2410_IICSTAT_ARBITR (1 << 3)
+#define S3C2410_IICSTAT_ASSLAVE (1 << 2)
+#define S3C2410_IICSTAT_ADDR0 (1 << 1)
+#define S3C2410_IICSTAT_LASTBIT (1 << 0)
+
+#define S3C2410_IICLC_SDA_DELAY0 (0 << 0)
+#define S3C2410_IICLC_SDA_DELAY5 (1 << 0)
+#define S3C2410_IICLC_SDA_DELAY10 (2 << 0)
+#define S3C2410_IICLC_SDA_DELAY15 (3 << 0)
+#define S3C2410_IICLC_SDA_DELAY_MASK (3 << 0)
+
+#define S3C2410_IICLC_FILTER_ON (1 << 2)
+
+/* Treat S3C2410 as baseline hardware, anything else is supported via quirks */
+#define QUIRK_S3C2440 (1 << 0)
+#define QUIRK_HDMIPHY (1 << 1)
+#define QUIRK_NO_GPIO (1 << 2)
+#define QUIRK_POLL (1 << 3)
+
+/* Max time to wait for bus to become idle after a xfer (in us) */
+#define S3C2410_IDLE_TIMEOUT 5000
+
+/* Exynos5 Sysreg offset */
+#define EXYNOS5_SYS_I2C_CFG 0x0234
+
+/* i2c controller state */
+enum s3c24xx_i2c_state {
+ STATE_IDLE,
+ STATE_START,
+ STATE_READ,
+ STATE_WRITE,
+ STATE_STOP
+};
+
+struct s3c24xx_i2c {
+ wait_queue_head_t wait;
+ kernel_ulong_t quirks;
+ unsigned int suspended:1;
+
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int msg_idx;
+ unsigned int msg_ptr;
+
+ unsigned int tx_setup;
+ unsigned int irq;
+
+ enum s3c24xx_i2c_state state;
+ unsigned long clkrate;
+
+ void __iomem *regs;
+ struct clk *clk;
+ struct device *dev;
+ struct i2c_adapter adap;
+
+ struct s3c2410_platform_i2c *pdata;
+ int gpios[2];
+ struct pinctrl *pctrl;
+#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
+ struct notifier_block freq_transition;
+#endif
+ struct regmap *sysreg;
+ unsigned int sys_i2c_cfg;
+};
+
+static const struct platform_device_id s3c24xx_driver_ids[] = {
+ {
+ .name = "s3c2410-i2c",
+ .driver_data = 0,
+ }, {
+ .name = "s3c2440-i2c",
+ .driver_data = QUIRK_S3C2440,
+ }, {
+ .name = "s3c2440-hdmiphy-i2c",
+ .driver_data = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
+ }, { },
+};
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat);
+
+#ifdef CONFIG_OF
+static const struct of_device_id s3c24xx_i2c_match[] = {
+ { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
+ { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 },
+ { .compatible = "samsung,s3c2440-hdmiphy-i2c",
+ .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
+ { .compatible = "samsung,exynos5-sata-phy-i2c",
+ .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) },
+ {},
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
+#endif
+
+/*
+ * Get controller type either from device tree or platform device variant.
+ */
+static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+
+ match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
+ return (kernel_ulong_t)match->data;
+ }
+
+ return platform_get_device_id(pdev)->driver_data;
+}
+
+/*
+ * Complete the message and wake up the caller, using the given return code,
+ * or zero to mean ok.
+ */
+static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
+{
+ dev_dbg(i2c->dev, "master_complete %d\n", ret);
+
+ i2c->msg_ptr = 0;
+ i2c->msg = NULL;
+ i2c->msg_idx++;
+ i2c->msg_num = 0;
+ if (ret)
+ i2c->msg_idx = ret;
+
+ if (!(i2c->quirks & QUIRK_POLL))
+ wake_up(&i2c->wait);
+}
+
+static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+}
+
+/* irq enable/disable functions */
+static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+static bool is_ack(struct s3c24xx_i2c *i2c)
+{
+ int tries;
+
+ for (tries = 50; tries; --tries) {
+ if (readl(i2c->regs + S3C2410_IICCON)
+ & S3C2410_IICCON_IRQPEND) {
+ if (!(readl(i2c->regs + S3C2410_IICSTAT)
+ & S3C2410_IICSTAT_LASTBIT))
+ return true;
+ }
+ usleep_range(1000, 2000);
+ }
+ dev_err(i2c->dev, "ack was not received\n");
+ return false;
+}
+
+/*
+ * put the start of a message onto the bus
+ */
+static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
+ struct i2c_msg *msg)
+{
+ unsigned int addr = (msg->addr & 0x7f) << 1;
+ unsigned long stat;
+ unsigned long iiccon;
+
+ stat = 0;
+ stat |= S3C2410_IICSTAT_TXRXEN;
+
+ if (msg->flags & I2C_M_RD) {
+ stat |= S3C2410_IICSTAT_MASTER_RX;
+ addr |= 1;
+ } else
+ stat |= S3C2410_IICSTAT_MASTER_TX;
+
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
+ /* todo - check for whether ack wanted or not */
+ s3c24xx_i2c_enable_ack(i2c);
+
+ iiccon = readl(i2c->regs + S3C2410_IICCON);
+ writel(stat, i2c->regs + S3C2410_IICSTAT);
+
+ dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
+ writeb(addr, i2c->regs + S3C2410_IICDS);
+
+ /*
+ * delay here to ensure the data byte has gotten onto the bus
+ * before the transaction is started
+ */
+ ndelay(i2c->tx_setup);
+
+ dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
+ writel(iiccon, i2c->regs + S3C2410_IICCON);
+
+ stat |= S3C2410_IICSTAT_START;
+ writel(stat, i2c->regs + S3C2410_IICSTAT);
+
+ if (i2c->quirks & QUIRK_POLL) {
+ while ((i2c->msg_num != 0) && is_ack(i2c)) {
+ i2c_s3c_irq_nextbyte(i2c, stat);
+ stat = readl(i2c->regs + S3C2410_IICSTAT);
+
+ if (stat & S3C2410_IICSTAT_ARBITR)
+ dev_err(i2c->dev, "deal with arbitration loss\n");
+ }
+ }
+}
+
+static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
+{
+ unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+ dev_dbg(i2c->dev, "STOP\n");
+
+ /*
+ * The datasheet says that the STOP sequence should be:
+ * 1) I2CSTAT.5 = 0 - Clear BUSY (or 'generate STOP')
+ * 2) I2CCON.4 = 0 - Clear IRQPEND
+ * 3) Wait until the stop condition takes effect.
+ * 4*) I2CSTAT.4 = 0 - Clear TXRXEN
+ *
+ * Where, step "4*" is only for buses with the "HDMIPHY" quirk.
+ *
+ * However, after much experimentation, it appears that:
+ * a) normal buses automatically clear BUSY and transition from
+ * Master->Slave when they complete generating a STOP condition.
+ * Therefore, step (3) can be done in doxfer() by polling I2CCON.4
+ * after starting the STOP generation here.
+ * b) HDMIPHY bus does neither, so there is no way to do step 3.
+ * There is no indication when this bus has finished generating
+ * STOP.
+ *
+ * In fact, we have found that as soon as the IRQPEND bit is cleared in
+ * step 2, the HDMIPHY bus generates the STOP condition, and then
+ * immediately starts transferring another data byte, even though the
+ * bus is supposedly stopped. This is presumably because the bus is
+ * still in "Master" mode, and its BUSY bit is still set.
+ *
+ * To avoid these extra post-STOP transactions on HDMI phy devices, we
+ * just disable Serial Output on the bus (I2CSTAT.4 = 0) directly,
+ * instead of first generating a proper STOP condition. This should
+ * float SDA & SCK terminating the transfer. Subsequent transfers
+ * start with a proper START condition, and proceed normally.
+ *
+ * The HDMIPHY bus is an internal bus that always has exactly two
+ * devices, the host as Master and the HDMIPHY device as the slave.
+ * Skipping the STOP condition has been tested on this bus and works.
+ */
+ if (i2c->quirks & QUIRK_HDMIPHY) {
+ /* Stop driving the I2C pins */
+ iicstat &= ~S3C2410_IICSTAT_TXRXEN;
+ } else {
+ /* stop the transfer */
+ iicstat &= ~S3C2410_IICSTAT_START;
+ }
+ writel(iicstat, i2c->regs + S3C2410_IICSTAT);
+
+ i2c->state = STATE_STOP;
+
+ s3c24xx_i2c_master_complete(i2c, ret);
+ s3c24xx_i2c_disable_irq(i2c);
+}
+
+/*
+ * helper functions to determine the current state in the set of
+ * messages we are sending
+ */
+
+/*
+ * returns TRUE if the current message is the last in the set
+ */
+static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
+{
+ return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+/*
+ * returns TRUE if we this is the last byte in the current message
+ */
+static inline int is_msglast(struct s3c24xx_i2c *i2c)
+{
+ /*
+ * msg->len is always 1 for the first byte of smbus block read.
+ * Actual length will be read from slave. More bytes will be
+ * read according to the length then.
+ */
+ if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1)
+ return 0;
+
+ return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/*
+ * returns TRUE if we reached the end of the current message
+ */
+static inline int is_msgend(struct s3c24xx_i2c *i2c)
+{
+ return i2c->msg_ptr >= i2c->msg->len;
+}
+
+/*
+ * process an interrupt and work out what to do
+ */
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
+{
+ unsigned long tmp;
+ unsigned char byte;
+ int ret = 0;
+
+ switch (i2c->state) {
+
+ case STATE_IDLE:
+ dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
+ goto out;
+
+ case STATE_STOP:
+ dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
+ s3c24xx_i2c_disable_irq(i2c);
+ goto out_ack;
+
+ case STATE_START:
+ /*
+ * last thing we did was send a start condition on the
+ * bus, or started a new i2c message
+ */
+ if (iicstat & S3C2410_IICSTAT_LASTBIT &&
+ !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ /* ack was not received... */
+ dev_dbg(i2c->dev, "ack was not received\n");
+ s3c24xx_i2c_stop(i2c, -ENXIO);
+ goto out_ack;
+ }
+
+ if (i2c->msg->flags & I2C_M_RD)
+ i2c->state = STATE_READ;
+ else
+ i2c->state = STATE_WRITE;
+
+ /*
+ * Terminate the transfer if there is nothing to do
+ * as this is used by the i2c probe to find devices.
+ */
+ if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+ s3c24xx_i2c_stop(i2c, 0);
+ goto out_ack;
+ }
+
+ if (i2c->state == STATE_READ)
+ goto prepare_read;
+
+ /*
+ * fall through to the write state, as we will need to
+ * send a byte as well
+ */
+
+ case STATE_WRITE:
+ /*
+ * we are writing data to the device... check for the
+ * end of the message, and if so, work out what to do
+ */
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+ dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+ s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+ goto out_ack;
+ }
+ }
+
+ retry_write:
+
+ if (!is_msgend(i2c)) {
+ byte = i2c->msg->buf[i2c->msg_ptr++];
+ writeb(byte, i2c->regs + S3C2410_IICDS);
+
+ /*
+ * delay after writing the byte to allow the
+ * data setup time on the bus, as writing the
+ * data to the register causes the first bit
+ * to appear on SDA, and SCL will change as
+ * soon as the interrupt is acknowledged
+ */
+ ndelay(i2c->tx_setup);
+
+ } else if (!is_lastmsg(i2c)) {
+ /* we need to go to the next i2c message */
+
+ dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+
+ /* check to see if we need to do another message */
+ if (i2c->msg->flags & I2C_M_NOSTART) {
+
+ if (i2c->msg->flags & I2C_M_RD) {
+ /*
+ * cannot do this, the controller
+ * forces us to send a new START
+ * when we change direction
+ */
+ dev_dbg(i2c->dev,
+ "missing START before write->read\n");
+ s3c24xx_i2c_stop(i2c, -EINVAL);
+ break;
+ }
+
+ goto retry_write;
+ } else {
+ /* send the new start */
+ s3c24xx_i2c_message_start(i2c, i2c->msg);
+ i2c->state = STATE_START;
+ }
+
+ } else {
+ /* send stop */
+ s3c24xx_i2c_stop(i2c, 0);
+ }
+ break;
+
+ case STATE_READ:
+ /*
+ * we have a byte of data in the data register, do
+ * something with it, and then work out whether we are
+ * going to do any more read/write
+ */
+ byte = readb(i2c->regs + S3C2410_IICDS);
+ i2c->msg->buf[i2c->msg_ptr++] = byte;
+
+ /* Add actual length to read for smbus block read */
+ if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1)
+ i2c->msg->len += byte;
+ prepare_read:
+ if (is_msglast(i2c)) {
+ /* last byte of buffer */
+
+ if (is_lastmsg(i2c))
+ s3c24xx_i2c_disable_ack(i2c);
+
+ } else if (is_msgend(i2c)) {
+ /*
+ * ok, we've read the entire buffer, see if there
+ * is anything else we need to do
+ */
+ if (is_lastmsg(i2c)) {
+ /* last message, send stop and complete */
+ dev_dbg(i2c->dev, "READ: Send Stop\n");
+
+ s3c24xx_i2c_stop(i2c, 0);
+ } else {
+ /* go to the next transfer */
+ dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+ }
+ }
+
+ break;
+ }
+
+ /* acknowlegde the IRQ and get back on with the work */
+
+ out_ack:
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~S3C2410_IICCON_IRQPEND;
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+ out:
+ return ret;
+}
+
+/*
+ * top level IRQ servicing routine
+ */
+static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
+{
+ struct s3c24xx_i2c *i2c = dev_id;
+ unsigned long status;
+ unsigned long tmp;
+
+ status = readl(i2c->regs + S3C2410_IICSTAT);
+
+ if (status & S3C2410_IICSTAT_ARBITR) {
+ /* deal with arbitration loss */
+ dev_err(i2c->dev, "deal with arbitration loss\n");
+ }
+
+ if (i2c->state == STATE_IDLE) {
+ dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
+
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~S3C2410_IICCON_IRQPEND;
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+ goto out;
+ }
+
+ /*
+ * pretty much this leaves us with the fact that we've
+ * transmitted or received whatever byte we last sent
+ */
+ i2c_s3c_irq_nextbyte(i2c, status);
+
+ out:
+ return IRQ_HANDLED;
+}
+
+/*
+ * Disable the bus so that we won't get any interrupts from now on, or try
+ * to drive any lines. This is the default state when we don't have
+ * anything to send/receive.
+ *
+ * If there is an event on the bus, or we have a pre-existing event at
+ * kernel boot time, we may not notice the event and the I2C controller
+ * will lock the bus with the I2C clock line low indefinitely.
+ */
+static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ /* Stop driving the I2C pins */
+ tmp = readl(i2c->regs + S3C2410_IICSTAT);
+ tmp &= ~S3C2410_IICSTAT_TXRXEN;
+ writel(tmp, i2c->regs + S3C2410_IICSTAT);
+
+ /* We don't expect any interrupts now, and don't want send acks */
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND |
+ S3C2410_IICCON_ACKEN);
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+}
+
+
+/*
+ * get the i2c bus for a master transaction
+ */
+static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
+{
+ unsigned long iicstat;
+ int timeout = 400;
+
+ while (timeout-- > 0) {
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+ if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
+ return 0;
+
+ msleep(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/*
+ * wait for the i2c bus to become idle.
+ */
+static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
+{
+ unsigned long iicstat;
+ ktime_t start, now;
+ unsigned long delay;
+ int spins;
+
+ /* ensure the stop has been through the bus */
+
+ dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+ start = now = ktime_get();
+
+ /*
+ * Most of the time, the bus is already idle within a few usec of the
+ * end of a transaction. However, really slow i2c devices can stretch
+ * the clock, delaying STOP generation.
+ *
+ * On slower SoCs this typically happens within a very small number of
+ * instructions so busy wait briefly to avoid scheduling overhead.
+ */
+ spins = 3;
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ while ((iicstat & S3C2410_IICSTAT_START) && --spins) {
+ cpu_relax();
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ }
+
+ /*
+ * If we do get an appreciable delay as a compromise between idle
+ * detection latency for the normal, fast case, and system load in the
+ * slow device case, use an exponential back off in the polling loop,
+ * up to 1/10th of the total timeout, then continue to poll at a
+ * constant rate up to the timeout.
+ */
+ delay = 1;
+ while ((iicstat & S3C2410_IICSTAT_START) &&
+ ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) {
+ usleep_range(delay, 2 * delay);
+ if (delay < S3C2410_IDLE_TIMEOUT / 10)
+ delay <<= 1;
+ now = ktime_get();
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ }
+
+ if (iicstat & S3C2410_IICSTAT_START)
+ dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+}
+
+/*
+ * this starts an i2c transfer
+ */
+static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ unsigned long timeout;
+ int ret;
+
+ if (i2c->suspended)
+ return -EIO;
+
+ ret = s3c24xx_i2c_set_master(i2c);
+ if (ret != 0) {
+ dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ i2c->msg = msgs;
+ i2c->msg_num = num;
+ i2c->msg_ptr = 0;
+ i2c->msg_idx = 0;
+ i2c->state = STATE_START;
+
+ s3c24xx_i2c_enable_irq(i2c);
+ s3c24xx_i2c_message_start(i2c, msgs);
+
+ if (i2c->quirks & QUIRK_POLL) {
+ ret = i2c->msg_idx;
+
+ if (ret != num)
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+ goto out;
+ }
+
+ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+ ret = i2c->msg_idx;
+
+ /*
+ * Having these next two as dev_err() makes life very
+ * noisy when doing an i2cdetect
+ */
+ if (timeout == 0)
+ dev_dbg(i2c->dev, "timeout\n");
+ else if (ret != num)
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+ /* For QUIRK_HDMIPHY, bus is already disabled */
+ if (i2c->quirks & QUIRK_HDMIPHY)
+ goto out;
+
+ s3c24xx_i2c_wait_idle(i2c);
+
+ s3c24xx_i2c_disable_bus(i2c);
+
+ out:
+ i2c->state = STATE_IDLE;
+
+ return ret;
+}
+
+/*
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+ */
+static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
+ int retry;
+ int ret;
+
+ ret = clk_enable(i2c->clk);
+ if (ret)
+ return ret;
+
+ for (retry = 0; retry < adap->retries; retry++) {
+
+ ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
+
+ if (ret != -EAGAIN) {
+ clk_disable(i2c->clk);
+ return ret;
+ }
+
+ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+ udelay(100);
+ }
+
+ clk_disable(i2c->clk);
+ return -EREMOTEIO;
+}
+
+/* declare our i2c functionality */
+static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART |
+ I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* i2c bus registration info */
+static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
+ .master_xfer = s3c24xx_i2c_xfer,
+ .functionality = s3c24xx_i2c_func,
+};
+
+/*
+ * return the divisor settings for a given frequency
+ */
+static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
+ unsigned int *div1, unsigned int *divs)
+{
+ unsigned int calc_divs = clkin / wanted;
+ unsigned int calc_div1;
+
+ if (calc_divs > (16*16))
+ calc_div1 = 512;
+ else
+ calc_div1 = 16;
+
+ calc_divs += calc_div1-1;
+ calc_divs /= calc_div1;
+
+ if (calc_divs == 0)
+ calc_divs = 1;
+ if (calc_divs > 17)
+ calc_divs = 17;
+
+ *divs = calc_divs;
+ *div1 = calc_div1;
+
+ return clkin / (calc_divs * calc_div1);
+}
+
+/*
+ * work out a divisor for the user requested frequency setting,
+ * either by the requested frequency, or scanning the acceptable
+ * range of frequencies until something is found
+ */
+static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
+{
+ struct s3c2410_platform_i2c *pdata = i2c->pdata;
+ unsigned long clkin = clk_get_rate(i2c->clk);
+ unsigned int divs, div1;
+ unsigned long target_frequency;
+ u32 iiccon;
+ int freq;
+
+ i2c->clkrate = clkin;
+ clkin /= 1000; /* clkin now in KHz */
+
+ dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);
+
+ target_frequency = pdata->frequency ? pdata->frequency : 100000;
+
+ target_frequency /= 1000; /* Target frequency now in KHz */
+
+ freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);
+
+ if (freq > target_frequency) {
+ dev_err(i2c->dev,
+ "Unable to achieve desired frequency %luKHz." \
+ " Lowest achievable %dKHz\n", target_frequency, freq);
+ return -EINVAL;
+ }
+
+ *got = freq;
+
+ iiccon = readl(i2c->regs + S3C2410_IICCON);
+ iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512);
+ iiccon |= (divs-1);
+
+ if (div1 == 512)
+ iiccon |= S3C2410_IICCON_TXDIV_512;
+
+ if (i2c->quirks & QUIRK_POLL)
+ iiccon |= S3C2410_IICCON_SCALE(2);
+
+ writel(iiccon, i2c->regs + S3C2410_IICCON);
+
+ if (i2c->quirks & QUIRK_S3C2440) {
+ unsigned long sda_delay;
+
+ if (pdata->sda_delay) {
+ sda_delay = clkin * pdata->sda_delay;
+ sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
+ sda_delay = DIV_ROUND_UP(sda_delay, 5);
+ if (sda_delay > 3)
+ sda_delay = 3;
+ sda_delay |= S3C2410_IICLC_FILTER_ON;
+ } else
+ sda_delay = 0;
+
+ dev_dbg(i2c->dev, "IICLC=%08lx\n", sda_delay);
+ writel(sda_delay, i2c->regs + S3C2440_IICLC);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
+
+#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition)
+
+static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct s3c24xx_i2c *i2c = freq_to_i2c(nb);
+ unsigned int got;
+ int delta_f;
+ int ret;
+
+ delta_f = clk_get_rate(i2c->clk) - i2c->clkrate;
+
+ /* if we're post-change and the input clock has slowed down
+ * or at pre-change and the clock is about to speed up, then
+ * adjust our clock rate. <0 is slow, >0 speedup.
+ */
+
+ if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
+ (val == CPUFREQ_PRECHANGE && delta_f > 0)) {
+ i2c_lock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER);
+ ret = s3c24xx_i2c_clockrate(i2c, &got);
+ i2c_unlock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER);
+
+ if (ret < 0)
+ dev_err(i2c->dev, "cannot find frequency (%d)\n", ret);
+ else
+ dev_info(i2c->dev, "setting freq %d\n", got);
+ }
+
+ return 0;
+}
+
+static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)
+{
+ i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition;
+
+ return cpufreq_register_notifier(&i2c->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
+{
+ cpufreq_unregister_notifier(&i2c->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)
+{
+ return 0;
+}
+
+static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
+{
+}
+#endif
+
+#ifdef CONFIG_OF
+static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
+{
+ int idx, gpio, ret;
+
+ if (i2c->quirks & QUIRK_NO_GPIO)
+ return 0;
+
+ for (idx = 0; idx < 2; idx++) {
+ gpio = of_get_gpio(i2c->dev->of_node, idx);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
+ goto free_gpio;
+ }
+ i2c->gpios[idx] = gpio;
+
+ ret = gpio_request(gpio, "i2c-bus");
+ if (ret) {
+ dev_err(i2c->dev, "gpio [%d] request failed (%d)\n",
+ gpio, ret);
+ goto free_gpio;
+ }
+ }
+ return 0;
+
+free_gpio:
+ while (--idx >= 0)
+ gpio_free(i2c->gpios[idx]);
+ return -EINVAL;
+}
+
+static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
+{
+ unsigned int idx;
+
+ if (i2c->quirks & QUIRK_NO_GPIO)
+ return;
+
+ for (idx = 0; idx < 2; idx++)
+ gpio_free(i2c->gpios[idx]);
+}
+#else
+static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
+{
+ return 0;
+}
+
+static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
+{
+}
+#endif
+
+/*
+ * initialise the controller, set the IO lines and frequency
+ */
+static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
+{
+ struct s3c2410_platform_i2c *pdata;
+ unsigned int freq;
+
+ /* get the plafrom data */
+
+ pdata = i2c->pdata;
+
+ /* write slave address */
+
+ writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
+
+ dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
+
+ writel(0, i2c->regs + S3C2410_IICCON);
+ writel(0, i2c->regs + S3C2410_IICSTAT);
+
+ /* we need to work out the divisors for the clock... */
+
+ if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
+ dev_err(i2c->dev, "cannot meet bus frequency required\n");
+ return -EINVAL;
+ }
+
+ /* todo - check that the i2c lines aren't being dragged anywhere */
+
+ dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
+ dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
+ readl(i2c->regs + S3C2410_IICCON));
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+/*
+ * Parse the device tree node and retreive the platform data.
+ */
+static void
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
+{
+ struct s3c2410_platform_i2c *pdata = i2c->pdata;
+ int id;
+
+ if (!np)
+ return;
+
+ pdata->bus_num = -1; /* i2c bus number is dynamically assigned */
+ of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay);
+ of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr);
+ of_property_read_u32(np, "samsung,i2c-max-bus-freq",
+ (u32 *)&pdata->frequency);
+ /*
+ * Exynos5's legacy i2c controller and new high speed i2c
+ * controller have muxed interrupt sources. By default the
+ * interrupts for 4-channel HS-I2C controller are enabled.
+ * If nodes for first four channels of legacy i2c controller
+ * are available then re-configure the interrupts via the
+ * system register.
+ */
+ id = of_alias_get_id(np, "i2c");
+ i2c->sysreg = syscon_regmap_lookup_by_phandle(np,
+ "samsung,sysreg-phandle");
+ if (IS_ERR(i2c->sysreg))
+ return;
+
+ regmap_update_bits(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, BIT(id), 0);
+}
+#else
+static void
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) { }
+#endif
+
+static int s3c24xx_i2c_probe(struct platform_device *pdev)
+{
+ struct s3c24xx_i2c *i2c;
+ struct s3c2410_platform_i2c *pdata = NULL;
+ struct resource *res;
+ int ret;
+
+ if (!pdev->dev.of_node) {
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+ }
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!i2c->pdata)
+ return -ENOMEM;
+
+ i2c->quirks = s3c24xx_get_device_quirks(pdev);
+ i2c->sysreg = ERR_PTR(-ENOENT);
+ if (pdata)
+ memcpy(i2c->pdata, pdata, sizeof(*pdata));
+ else
+ s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
+
+ strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &s3c24xx_i2c_algorithm;
+ i2c->adap.retries = 2;
+ i2c->adap.class = I2C_CLASS_DEPRECATED;
+ i2c->tx_setup = 50;
+
+ init_waitqueue_head(&i2c->wait);
+
+ /* find the clock and enable it */
+ i2c->dev = &pdev->dev;
+ i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ return -ENOENT;
+ }
+
+ dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
+ /* map the registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, res);
+
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ dev_dbg(&pdev->dev, "registers %p (%p)\n",
+ i2c->regs, res);
+
+ /* setup info block for the i2c core */
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
+
+ /* inititalise the i2c gpio lines */
+ if (i2c->pdata->cfg_gpio)
+ i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
+ else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c))
+ return -EINVAL;
+
+ /* initialise the i2c controller */
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "I2C clock enable failed\n");
+ return ret;
+ }
+
+ ret = s3c24xx_i2c_init(i2c);
+ clk_disable(i2c->clk);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "I2C controller init failed\n");
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+
+ /*
+ * find the IRQ for this unit (note, this relies on the init call to
+ * ensure no current IRQs pending
+ */
+ if (!(i2c->quirks & QUIRK_POLL)) {
+ i2c->irq = ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq,
+ 0, dev_name(&pdev->dev), i2c);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+ }
+
+ ret = s3c24xx_i2c_register_cpufreq(i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+
+ /*
+ * Note, previous versions of the driver used i2c_add_adapter()
+ * to add the bus at any number. We now pass the bus number via
+ * the platform data, so if unset it will now default to always
+ * being bus 0.
+ */
+ i2c->adap.nr = i2c->pdata->bus_num;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+
+ platform_set_drvdata(pdev, i2c);
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0) {
+ pm_runtime_disable(&pdev->dev);
+ s3c24xx_i2c_deregister_cpufreq(i2c);
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
+ return 0;
+}
+
+static int s3c24xx_i2c_remove(struct platform_device *pdev)
+{
+ struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_unprepare(i2c->clk);
+
+ pm_runtime_disable(&pdev->dev);
+
+ s3c24xx_i2c_deregister_cpufreq(i2c);
+
+ i2c_del_adapter(&i2c->adap);
+
+ if (pdev->dev.of_node && IS_ERR(i2c->pctrl))
+ s3c24xx_i2c_dt_gpio_free(i2c);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s3c24xx_i2c_suspend_noirq(struct device *dev)
+{
+ struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
+
+ i2c->suspended = 1;
+
+ if (!IS_ERR(i2c->sysreg))
+ regmap_read(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, &i2c->sys_i2c_cfg);
+
+ return 0;
+}
+
+static int s3c24xx_i2c_resume_noirq(struct device *dev)
+{
+ struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ if (!IS_ERR(i2c->sysreg))
+ regmap_write(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, i2c->sys_i2c_cfg);
+
+ ret = clk_enable(i2c->clk);
+ if (ret)
+ return ret;
+ s3c24xx_i2c_init(i2c);
+ clk_disable(i2c->clk);
+ i2c->suspended = 0;
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq,
+ s3c24xx_i2c_resume_noirq)
+};
+
+#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
+#else
+#define S3C24XX_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver s3c24xx_i2c_driver = {
+ .probe = s3c24xx_i2c_probe,
+ .remove = s3c24xx_i2c_remove,
+ .id_table = s3c24xx_driver_ids,
+ .driver = {
+ .name = "s3c-i2c",
+ .pm = S3C24XX_DEV_PM_OPS,
+ .of_match_table = of_match_ptr(s3c24xx_i2c_match),
+ },
+};
+
+static int __init i2c_adap_s3c_init(void)
+{
+ return platform_driver_register(&s3c24xx_i2c_driver);
+}
+subsys_initcall(i2c_adap_s3c_init);
+
+static void __exit i2c_adap_s3c_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_i2c_driver);
+}
+module_exit(i2c_adap_s3c_exit);
+
+MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
new file mode 100644
index 000000000..ff3f45536
--- /dev/null
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -0,0 +1,444 @@
+/*
+ * SMBus driver for ACPI SMBus CMI
+ *
+ * Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#define ACPI_SMBUS_HC_CLASS "smbus"
+#define ACPI_SMBUS_HC_DEVICE_NAME "cmi"
+
+/* SMBUS HID definition as supported by Microsoft Windows */
+#define ACPI_SMBUS_MS_HID "SMB0001"
+
+ACPI_MODULE_NAME("smbus_cmi");
+
+struct smbus_methods_t {
+ char *mt_info;
+ char *mt_sbr;
+ char *mt_sbw;
+};
+
+struct acpi_smbus_cmi {
+ acpi_handle handle;
+ struct i2c_adapter adapter;
+ u8 cap_info:1;
+ u8 cap_read:1;
+ u8 cap_write:1;
+ struct smbus_methods_t *methods;
+};
+
+static const struct smbus_methods_t smbus_methods = {
+ .mt_info = "_SBI",
+ .mt_sbr = "_SBR",
+ .mt_sbw = "_SBW",
+};
+
+/* Some IBM BIOSes omit the leading underscore */
+static const struct smbus_methods_t ibm_smbus_methods = {
+ .mt_info = "SBI_",
+ .mt_sbr = "SBR_",
+ .mt_sbw = "SBW_",
+};
+
+static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
+ {"SMBUS01", (kernel_ulong_t)&smbus_methods},
+ {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
+ {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods},
+ {"", 0}
+};
+MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
+
+#define ACPI_SMBUS_STATUS_OK 0x00
+#define ACPI_SMBUS_STATUS_FAIL 0x07
+#define ACPI_SMBUS_STATUS_DNAK 0x10
+#define ACPI_SMBUS_STATUS_DERR 0x11
+#define ACPI_SMBUS_STATUS_CMD_DENY 0x12
+#define ACPI_SMBUS_STATUS_UNKNOWN 0x13
+#define ACPI_SMBUS_STATUS_ACC_DENY 0x17
+#define ACPI_SMBUS_STATUS_TIMEOUT 0x18
+#define ACPI_SMBUS_STATUS_NOTSUP 0x19
+#define ACPI_SMBUS_STATUS_BUSY 0x1a
+#define ACPI_SMBUS_STATUS_PEC 0x1f
+
+#define ACPI_SMBUS_PRTCL_WRITE 0x00
+#define ACPI_SMBUS_PRTCL_READ 0x01
+#define ACPI_SMBUS_PRTCL_QUICK 0x02
+#define ACPI_SMBUS_PRTCL_BYTE 0x04
+#define ACPI_SMBUS_PRTCL_BYTE_DATA 0x06
+#define ACPI_SMBUS_PRTCL_WORD_DATA 0x08
+#define ACPI_SMBUS_PRTCL_BLOCK_DATA 0x0a
+
+
+static int
+acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ int result = 0;
+ struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
+ unsigned char protocol;
+ acpi_status status = 0;
+ struct acpi_object_list input;
+ union acpi_object mt_params[5];
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ union acpi_object *pkg;
+ char *method;
+ int len = 0;
+
+ dev_dbg(&adap->dev, "access size: %d %s\n", size,
+ (read_write) ? "READ" : "WRITE");
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ protocol = ACPI_SMBUS_PRTCL_QUICK;
+ command = 0;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 0;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = 0;
+ }
+ break;
+
+ case I2C_SMBUS_BYTE:
+ protocol = ACPI_SMBUS_PRTCL_BYTE;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 0;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = 0;
+ } else {
+ command = 0;
+ }
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 1;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = data->byte;
+ }
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
+ if (read_write == I2C_SMBUS_WRITE) {
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = 2;
+ mt_params[4].type = ACPI_TYPE_INTEGER;
+ mt_params[4].integer.value = data->word;
+ }
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ mt_params[3].type = ACPI_TYPE_INTEGER;
+ mt_params[3].integer.value = len;
+ mt_params[4].type = ACPI_TYPE_BUFFER;
+ mt_params[4].buffer.length = len;
+ mt_params[4].buffer.pointer = data->block + 1;
+ }
+ break;
+
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ if (read_write == I2C_SMBUS_READ) {
+ protocol |= ACPI_SMBUS_PRTCL_READ;
+ method = smbus_cmi->methods->mt_sbr;
+ input.count = 3;
+ } else {
+ protocol |= ACPI_SMBUS_PRTCL_WRITE;
+ method = smbus_cmi->methods->mt_sbw;
+ input.count = 5;
+ }
+
+ input.pointer = mt_params;
+ mt_params[0].type = ACPI_TYPE_INTEGER;
+ mt_params[0].integer.value = protocol;
+ mt_params[1].type = ACPI_TYPE_INTEGER;
+ mt_params[1].integer.value = addr;
+ mt_params[2].type = ACPI_TYPE_INTEGER;
+ mt_params[2].integer.value = command;
+
+ status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
+ &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(smbus_cmi->handle,
+ "Failed to evaluate %s: %i\n", method, status);
+ return -EIO;
+ }
+
+ pkg = buffer.pointer;
+ if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
+ obj = pkg->package.elements;
+ else {
+ acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
+ result = -EIO;
+ goto out;
+ }
+ if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+ acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
+ result = -EIO;
+ goto out;
+ }
+
+ result = obj->integer.value;
+ acpi_handle_debug(smbus_cmi->handle, "%s return status: %i\n", method,
+ result);
+
+ switch (result) {
+ case ACPI_SMBUS_STATUS_OK:
+ result = 0;
+ break;
+ case ACPI_SMBUS_STATUS_BUSY:
+ result = -EBUSY;
+ goto out;
+ case ACPI_SMBUS_STATUS_TIMEOUT:
+ result = -ETIMEDOUT;
+ goto out;
+ case ACPI_SMBUS_STATUS_DNAK:
+ result = -ENXIO;
+ goto out;
+ default:
+ result = -EIO;
+ goto out;
+ }
+
+ if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
+ goto out;
+
+ obj = pkg->package.elements + 1;
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
+ result = -EIO;
+ goto out;
+ }
+
+ len = obj->integer.value;
+ obj = pkg->package.elements + 2;
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ case I2C_SMBUS_WORD_DATA:
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ acpi_handle_err(smbus_cmi->handle,
+ "Invalid argument type\n");
+ result = -EIO;
+ goto out;
+ }
+ if (len == 2)
+ data->word = obj->integer.value;
+ else
+ data->byte = obj->integer.value;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ acpi_handle_err(smbus_cmi->handle,
+ "Invalid argument type\n");
+ result = -EIO;
+ goto out;
+ }
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+ data->block[0] = len;
+ memcpy(data->block + 1, obj->buffer.pointer, len);
+ break;
+ }
+
+out:
+ kfree(buffer.pointer);
+ dev_dbg(&adap->dev, "Transaction status: %i\n", result);
+ return result;
+}
+
+static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
+{
+ struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
+ u32 ret;
+
+ ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
+ I2C_FUNC_SMBUS_QUICK : 0;
+
+ ret |= smbus_cmi->cap_read ?
+ (I2C_FUNC_SMBUS_READ_BYTE |
+ I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
+
+ ret |= smbus_cmi->cap_write ?
+ (I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
+
+ return ret;
+}
+
+static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
+ .smbus_xfer = acpi_smbus_cmi_access,
+ .functionality = acpi_smbus_cmi_func,
+};
+
+
+static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
+ const char *name)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_handle *handle = smbus_cmi->handle;
+ union acpi_object *obj;
+ acpi_status status;
+
+ if (!strcmp(name, smbus_cmi->methods->mt_info)) {
+ status = acpi_evaluate_object(smbus_cmi->handle,
+ smbus_cmi->methods->mt_info,
+ NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "Failed to evaluate %s: %i\n",
+ smbus_cmi->methods->mt_info, status);
+ return -EIO;
+ }
+
+ obj = buffer.pointer;
+ if (obj && obj->type == ACPI_TYPE_PACKAGE)
+ obj = obj->package.elements;
+ else {
+ acpi_handle_err(handle, "Invalid argument type\n");
+ kfree(buffer.pointer);
+ return -EIO;
+ }
+
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ acpi_handle_err(handle, "Invalid argument type\n");
+ kfree(buffer.pointer);
+ return -EIO;
+ } else
+ acpi_handle_debug(handle, "SMBus CMI Version %x\n",
+ (int)obj->integer.value);
+
+ kfree(buffer.pointer);
+ smbus_cmi->cap_info = 1;
+ } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
+ smbus_cmi->cap_read = 1;
+ else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
+ smbus_cmi->cap_write = 1;
+ else
+ acpi_handle_debug(handle, "Unsupported CMI method: %s\n", name);
+
+ return 0;
+}
+
+static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
+ void *context, void **return_value)
+{
+ char node_name[5];
+ struct acpi_buffer buffer = { sizeof(node_name), node_name };
+ struct acpi_smbus_cmi *smbus_cmi = context;
+ acpi_status status;
+
+ status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+
+ if (ACPI_SUCCESS(status))
+ acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
+
+ return AE_OK;
+}
+
+static int acpi_smbus_cmi_add(struct acpi_device *device)
+{
+ struct acpi_smbus_cmi *smbus_cmi;
+ const struct acpi_device_id *id;
+ int ret;
+
+ smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
+ if (!smbus_cmi)
+ return -ENOMEM;
+
+ smbus_cmi->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
+ device->driver_data = smbus_cmi;
+ smbus_cmi->cap_info = 0;
+ smbus_cmi->cap_read = 0;
+ smbus_cmi->cap_write = 0;
+
+ for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
+ if (!strcmp(id->id, acpi_device_hid(device)))
+ smbus_cmi->methods =
+ (struct smbus_methods_t *) id->driver_data;
+
+ acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
+ acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
+
+ if (smbus_cmi->cap_info == 0) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
+ "SMBus CMI adapter %s",
+ acpi_device_name(device));
+ smbus_cmi->adapter.owner = THIS_MODULE;
+ smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
+ smbus_cmi->adapter.algo_data = smbus_cmi;
+ smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ smbus_cmi->adapter.dev.parent = &device->dev;
+
+ ret = i2c_add_adapter(&smbus_cmi->adapter);
+ if (ret) {
+ dev_err(&device->dev, "Couldn't register adapter!\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ kfree(smbus_cmi);
+ device->driver_data = NULL;
+ return ret;
+}
+
+static int acpi_smbus_cmi_remove(struct acpi_device *device)
+{
+ struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
+
+ i2c_del_adapter(&smbus_cmi->adapter);
+ kfree(smbus_cmi);
+ device->driver_data = NULL;
+
+ return 0;
+}
+
+static struct acpi_driver acpi_smbus_cmi_driver = {
+ .name = ACPI_SMBUS_HC_DEVICE_NAME,
+ .class = ACPI_SMBUS_HC_CLASS,
+ .ids = acpi_smbus_cmi_ids,
+ .ops = {
+ .add = acpi_smbus_cmi_add,
+ .remove = acpi_smbus_cmi_remove,
+ },
+};
+module_acpi_driver(acpi_smbus_cmi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
+MODULE_DESCRIPTION("ACPI SMBus CMI driver");
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
new file mode 100644
index 000000000..319d1fa61
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -0,0 +1,565 @@
+/*
+ * I2C bus driver for the SH7760 I2C Interfaces.
+ *
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *
+ * licensed under the terms outlined in the file COPYING.
+ *
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <asm/clock.h>
+#include <asm/i2c-sh7760.h>
+
+/* register offsets */
+#define I2CSCR 0x0 /* slave ctrl */
+#define I2CMCR 0x4 /* master ctrl */
+#define I2CSSR 0x8 /* slave status */
+#define I2CMSR 0xC /* master status */
+#define I2CSIER 0x10 /* slave irq enable */
+#define I2CMIER 0x14 /* master irq enable */
+#define I2CCCR 0x18 /* clock dividers */
+#define I2CSAR 0x1c /* slave address */
+#define I2CMAR 0x20 /* master address */
+#define I2CRXTX 0x24 /* data port */
+#define I2CFCR 0x28 /* fifo control */
+#define I2CFSR 0x2C /* fifo status */
+#define I2CFIER 0x30 /* fifo irq enable */
+#define I2CRFDR 0x34 /* rx fifo count */
+#define I2CTFDR 0x38 /* tx fifo count */
+
+#define REGSIZE 0x3C
+
+#define MCR_MDBS 0x80 /* non-fifo mode switch */
+#define MCR_FSCL 0x40 /* override SCL pin */
+#define MCR_FSDA 0x20 /* override SDA pin */
+#define MCR_OBPC 0x10 /* override pins */
+#define MCR_MIE 0x08 /* master if enable */
+#define MCR_TSBE 0x04
+#define MCR_FSB 0x02 /* force stop bit */
+#define MCR_ESG 0x01 /* en startbit gen. */
+
+#define MSR_MNR 0x40 /* nack received */
+#define MSR_MAL 0x20 /* arbitration lost */
+#define MSR_MST 0x10 /* sent a stop */
+#define MSR_MDE 0x08
+#define MSR_MDT 0x04
+#define MSR_MDR 0x02
+#define MSR_MAT 0x01 /* slave addr xfer done */
+
+#define MIE_MNRE 0x40 /* nack irq en */
+#define MIE_MALE 0x20 /* arblos irq en */
+#define MIE_MSTE 0x10 /* stop irq en */
+#define MIE_MDEE 0x08
+#define MIE_MDTE 0x04
+#define MIE_MDRE 0x02
+#define MIE_MATE 0x01 /* address sent irq en */
+
+#define FCR_RFRST 0x02 /* reset rx fifo */
+#define FCR_TFRST 0x01 /* reset tx fifo */
+
+#define FSR_TEND 0x04 /* last byte sent */
+#define FSR_RDF 0x02 /* rx fifo trigger */
+#define FSR_TDFE 0x01 /* tx fifo empty */
+
+#define FIER_TEIE 0x04 /* tx fifo empty irq en */
+#define FIER_RXIE 0x02 /* rx fifo trig irq en */
+#define FIER_TXIE 0x01 /* tx fifo trig irq en */
+
+#define FIFO_SIZE 16
+
+struct cami2c {
+ void __iomem *iobase;
+ struct i2c_adapter adap;
+
+ /* message processing */
+ struct i2c_msg *msg;
+#define IDF_SEND 1
+#define IDF_RECV 2
+#define IDF_STOP 4
+ int flags;
+
+#define IDS_DONE 1
+#define IDS_ARBLOST 2
+#define IDS_NACK 4
+ int status;
+ struct completion xfer_done;
+
+ int irq;
+ struct resource *ioarea;
+};
+
+static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
+{
+ __raw_writel(val, (unsigned long)cam->iobase + reg);
+}
+
+static inline unsigned long IN32(struct cami2c *cam, int reg)
+{
+ return __raw_readl((unsigned long)cam->iobase + reg);
+}
+
+static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
+{
+ struct cami2c *id = ptr;
+ struct i2c_msg *msg = id->msg;
+ char *data = msg->buf;
+ unsigned long msr, fsr, fier, len;
+
+ msr = IN32(id, I2CMSR);
+ fsr = IN32(id, I2CFSR);
+
+ /* arbitration lost */
+ if (msr & MSR_MAL) {
+ OUT32(id, I2CMCR, 0);
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSAR, 0);
+ id->status |= IDS_DONE | IDS_ARBLOST;
+ goto out;
+ }
+
+ if (msr & MSR_MNR) {
+ /* NACK handling is very screwed up. After receiving a
+ * NAK IRQ one has to wait a bit before writing to any
+ * registers, or the ctl will lock up. After that delay
+ * do a normal i2c stop. Then wait at least 1 ms before
+ * attempting another transfer or ctl will stop working
+ */
+ udelay(100); /* wait or risk ctl hang */
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+ OUT32(id, I2CFIER, 0);
+ OUT32(id, I2CMIER, MIE_MSTE);
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSAR, 0);
+ id->status |= IDS_NACK;
+ msr &= ~MSR_MAT;
+ fsr = 0;
+ /* In some cases the MST bit is also set. */
+ }
+
+ /* i2c-stop was sent */
+ if (msr & MSR_MST) {
+ id->status |= IDS_DONE;
+ goto out;
+ }
+
+ /* i2c slave addr was sent; set to "normal" operation */
+ if (msr & MSR_MAT)
+ OUT32(id, I2CMCR, MCR_MIE);
+
+ fier = IN32(id, I2CFIER);
+
+ if (fsr & FSR_RDF) {
+ len = IN32(id, I2CRFDR);
+ if (msg->len <= len) {
+ if (id->flags & IDF_STOP) {
+ OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+ OUT32(id, I2CFIER, 0);
+ /* manual says: wait >= 0.5 SCL times */
+ udelay(5);
+ /* next int should be MST */
+ } else {
+ id->status |= IDS_DONE;
+ /* keep the RDF bit: ctrl holds SCL low
+ * until the setup for the next i2c_msg
+ * clears this bit.
+ */
+ fsr &= ~FSR_RDF;
+ }
+ }
+ while (msg->len && len) {
+ *data++ = IN32(id, I2CRXTX);
+ msg->len--;
+ len--;
+ }
+
+ if (msg->len) {
+ len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1
+ : msg->len - 1;
+
+ OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4));
+ }
+
+ } else if (id->flags & IDF_SEND) {
+ if ((fsr & FSR_TEND) && (msg->len < 1)) {
+ if (id->flags & IDF_STOP) {
+ OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+ } else {
+ id->status |= IDS_DONE;
+ /* keep the TEND bit: ctl holds SCL low
+ * until the setup for the next i2c_msg
+ * clears this bit.
+ */
+ fsr &= ~FSR_TEND;
+ }
+ }
+ if (fsr & FSR_TDFE) {
+ while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) {
+ OUT32(id, I2CRXTX, *data++);
+ msg->len--;
+ }
+
+ if (msg->len < 1) {
+ fier &= ~FIER_TXIE;
+ OUT32(id, I2CFIER, fier);
+ } else {
+ len = (msg->len >= FIFO_SIZE) ? 2 : 0;
+ OUT32(id, I2CFCR,
+ FCR_RFRST | ((len & 3) << 2));
+ }
+ }
+ }
+out:
+ if (id->status & IDS_DONE) {
+ OUT32(id, I2CMIER, 0);
+ OUT32(id, I2CFIER, 0);
+ id->msg = NULL;
+ complete(&id->xfer_done);
+ }
+ /* clear status flags and ctrl resumes work */
+ OUT32(id, I2CMSR, ~msr);
+ OUT32(id, I2CFSR, ~fsr);
+ OUT32(id, I2CSSR, 0);
+
+ return IRQ_HANDLED;
+}
+
+
+/* prepare and start a master receive operation */
+static void sh7760_i2c_mrecv(struct cami2c *id)
+{
+ int len;
+
+ id->flags |= IDF_RECV;
+
+ /* set the slave addr reg; otherwise rcv wont work! */
+ OUT32(id, I2CSAR, 0xfe);
+ OUT32(id, I2CMAR, (id->msg->addr << 1) | 1);
+
+ /* adjust rx fifo trigger */
+ if (id->msg->len >= FIFO_SIZE)
+ len = FIFO_SIZE - 1; /* trigger at fifo full */
+ else
+ len = id->msg->len - 1; /* trigger before all received */
+
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4));
+
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+ OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+ OUT32(id, I2CFIER, FIER_RXIE);
+}
+
+/* prepare and start a master send operation */
+static void sh7760_i2c_msend(struct cami2c *id)
+{
+ int len;
+
+ id->flags |= IDF_SEND;
+
+ /* set the slave addr reg; otherwise xmit wont work! */
+ OUT32(id, I2CSAR, 0xfe);
+ OUT32(id, I2CMAR, (id->msg->addr << 1) | 0);
+
+ /* adjust tx fifo trigger */
+ if (id->msg->len >= FIFO_SIZE)
+ len = 2; /* trig: 2 bytes left in TX fifo */
+ else
+ len = 0; /* trig: 8 bytes left in TX fifo */
+
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2));
+
+ while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) {
+ OUT32(id, I2CRXTX, *(id->msg->buf));
+ (id->msg->len)--;
+ (id->msg->buf)++;
+ }
+
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+ OUT32(id, I2CFSR, 0);
+ OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+ OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0));
+}
+
+static inline int sh7760_i2c_busy_check(struct cami2c *id)
+{
+ return (IN32(id, I2CMCR) & MCR_FSDA);
+}
+
+static int sh7760_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct cami2c *id = adap->algo_data;
+ int i, retr;
+
+ if (sh7760_i2c_busy_check(id)) {
+ dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr);
+ return -EBUSY;
+ }
+
+ i = 0;
+ while (i < num) {
+ retr = adap->retries;
+retry:
+ id->flags = ((i == (num-1)) ? IDF_STOP : 0);
+ id->status = 0;
+ id->msg = msgs;
+ init_completion(&id->xfer_done);
+
+ if (msgs->flags & I2C_M_RD)
+ sh7760_i2c_mrecv(id);
+ else
+ sh7760_i2c_msend(id);
+
+ wait_for_completion(&id->xfer_done);
+
+ if (id->status == 0) {
+ num = -EIO;
+ break;
+ }
+
+ if (id->status & IDS_NACK) {
+ /* wait a bit or i2c module stops working */
+ mdelay(1);
+ num = -EREMOTEIO;
+ break;
+ }
+
+ if (id->status & IDS_ARBLOST) {
+ if (retr--) {
+ mdelay(2);
+ goto retry;
+ }
+ num = -EREMOTEIO;
+ break;
+ }
+
+ msgs++;
+ i++;
+ }
+
+ id->msg = NULL;
+ id->flags = 0;
+ id->status = 0;
+
+ OUT32(id, I2CMCR, 0);
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMIER, 0);
+ OUT32(id, I2CFIER, 0);
+
+ /* reset slave module registers too: master mode enables slave
+ * module for receive ops (ack, data). Without this reset,
+ * eternal bus activity might be reported after NACK / ARBLOST.
+ */
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSAR, 0);
+ OUT32(id, I2CSSR, 0);
+
+ return num;
+}
+
+static u32 sh7760_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm sh7760_i2c_algo = {
+ .master_xfer = sh7760_i2c_master_xfer,
+ .functionality = sh7760_i2c_func,
+};
+
+/* calculate CCR register setting for a desired scl clock. SCL clock is
+ * derived from I2C module clock (iclk) which in turn is derived from
+ * peripheral module clock (mclk, usually around 33MHz):
+ * iclk = mclk/(CDF + 1). iclk must be < 20MHz.
+ * scl = iclk/(SCGD*8 + 20).
+ */
+static int calc_CCR(unsigned long scl_hz)
+{
+ struct clk *mclk;
+ unsigned long mck, m1, dff, odff, iclk;
+ signed char cdf, cdfm;
+ int scgd, scgdm, scgds;
+
+ mclk = clk_get(NULL, "peripheral_clk");
+ if (IS_ERR(mclk)) {
+ return PTR_ERR(mclk);
+ } else {
+ mck = mclk->rate;
+ clk_put(mclk);
+ }
+
+ odff = scl_hz;
+ scgdm = cdfm = m1 = 0;
+ for (cdf = 3; cdf >= 0; cdf--) {
+ iclk = mck / (1 + cdf);
+ if (iclk >= 20000000)
+ continue;
+ scgds = ((iclk / scl_hz) - 20) >> 3;
+ for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) {
+ m1 = iclk / (20 + (scgd << 3));
+ dff = abs(scl_hz - m1);
+ if (dff < odff) {
+ odff = dff;
+ cdfm = cdf;
+ scgdm = scgd;
+ }
+ }
+ }
+ /* fail if more than 25% off of requested SCL */
+ if (odff > (scl_hz >> 2))
+ return -EINVAL;
+
+ /* create a CCR register value */
+ return ((scgdm << 2) | cdfm);
+}
+
+static int sh7760_i2c_probe(struct platform_device *pdev)
+{
+ struct sh7760_i2c_platdata *pd;
+ struct resource *res;
+ struct cami2c *id;
+ int ret;
+
+ pd = dev_get_platdata(&pdev->dev);
+ if (!pd) {
+ dev_err(&pdev->dev, "no platform_data!\n");
+ ret = -ENODEV;
+ goto out0;
+ }
+
+ id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+ if (!id) {
+ dev_err(&pdev->dev, "no mem for private data\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mmio resources\n");
+ ret = -ENODEV;
+ goto out1;
+ }
+
+ id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name);
+ if (!id->ioarea) {
+ dev_err(&pdev->dev, "mmio already reserved\n");
+ ret = -EBUSY;
+ goto out1;
+ }
+
+ id->iobase = ioremap(res->start, REGSIZE);
+ if (!id->iobase) {
+ dev_err(&pdev->dev, "cannot ioremap\n");
+ ret = -ENODEV;
+ goto out2;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto out3;
+ id->irq = ret;
+
+ id->adap.nr = pdev->id;
+ id->adap.algo = &sh7760_i2c_algo;
+ id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ id->adap.retries = 3;
+ id->adap.algo_data = id;
+ id->adap.dev.parent = &pdev->dev;
+ snprintf(id->adap.name, sizeof(id->adap.name),
+ "SH7760 I2C at %08lx", (unsigned long)res->start);
+
+ OUT32(id, I2CMCR, 0);
+ OUT32(id, I2CMSR, 0);
+ OUT32(id, I2CMIER, 0);
+ OUT32(id, I2CMAR, 0);
+ OUT32(id, I2CSIER, 0);
+ OUT32(id, I2CSAR, 0);
+ OUT32(id, I2CSCR, 0);
+ OUT32(id, I2CSSR, 0);
+ OUT32(id, I2CFIER, 0);
+ OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+ OUT32(id, I2CFSR, 0);
+
+ ret = calc_CCR(pd->speed_khz * 1000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n",
+ pd->speed_khz);
+ goto out3;
+ }
+ OUT32(id, I2CCCR, ret);
+
+ if (request_irq(id->irq, sh7760_i2c_irq, 0,
+ SH7760_I2C_DEVNAME, id)) {
+ dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+ ret = -EBUSY;
+ goto out3;
+ }
+
+ ret = i2c_add_numbered_adapter(&id->adap);
+ if (ret < 0)
+ goto out4;
+
+ platform_set_drvdata(pdev, id);
+
+ dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n",
+ pd->speed_khz, res->start, id->irq);
+
+ return 0;
+
+out4:
+ free_irq(id->irq, id);
+out3:
+ iounmap(id->iobase);
+out2:
+ release_resource(id->ioarea);
+ kfree(id->ioarea);
+out1:
+ kfree(id);
+out0:
+ return ret;
+}
+
+static int sh7760_i2c_remove(struct platform_device *pdev)
+{
+ struct cami2c *id = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&id->adap);
+ free_irq(id->irq, id);
+ iounmap(id->iobase);
+ release_resource(id->ioarea);
+ kfree(id->ioarea);
+ kfree(id);
+
+ return 0;
+}
+
+static struct platform_driver sh7760_i2c_drv = {
+ .driver = {
+ .name = SH7760_I2C_DEVNAME,
+ },
+ .probe = sh7760_i2c_probe,
+ .remove = sh7760_i2c_remove,
+};
+
+module_platform_driver(sh7760_i2c_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 I2C bus driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
new file mode 100644
index 000000000..ddcfb6d34
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -0,0 +1,994 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SuperH Mobile I2C Controller
+ *
+ * Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com>
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Portions of the code based on out-of-tree driver i2c-sh7343.c
+ * Copyright (c) 2006 Carlos Munoz <carlos@kenati.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+/* Transmit operation: */
+/* */
+/* 0 byte transmit */
+/* BUS: S A8 ACK P(*) */
+/* IRQ: DTE WAIT */
+/* ICIC: */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 */
+/* */
+/* 1 byte transmit */
+/* BUS: S A8 ACK D8(1) ACK P(*) */
+/* IRQ: DTE WAIT WAIT */
+/* ICIC: -DTE */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 D8(1) */
+/* */
+/* 2 byte transmit */
+/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */
+/* IRQ: DTE WAIT WAIT WAIT */
+/* ICIC: -DTE */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 D8(1) D8(2) */
+/* */
+/* 3 bytes or more, +---------+ gets repeated */
+/* */
+/* */
+/* Receive operation: */
+/* */
+/* 0 byte receive - not supported since slave may hold SDA low */
+/* */
+/* 1 byte receive [TX] | [RX] */
+/* BUS: S A8 ACK | D8(1) ACK P(*) */
+/* IRQ: DTE WAIT | WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) */
+/* */
+/* 2 byte receive [TX]| [RX] */
+/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P(*) */
+/* IRQ: DTE WAIT | WAIT WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) D8(2) */
+/* */
+/* 3 byte receive [TX] | [RX] (*) */
+/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */
+/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) D8(2) D8(3) */
+/* */
+/* 4 bytes or more, this part is repeated +---------+ */
+/* */
+/* */
+/* Interrupt order and BUSY flag */
+/* ___ _ */
+/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */
+/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */
+/* */
+/* S D7 D6 D5 D4 D3 D2 D1 D0 P(*) */
+/* ___ */
+/* WAIT IRQ ________________________________/ \___________ */
+/* TACK IRQ ____________________________________/ \_______ */
+/* DTE IRQ __________________________________________/ \_ */
+/* AL IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* _______________________________________________ */
+/* BUSY __/ \_ */
+/* */
+/* (*) The STOP condition is only sent by the master at the end of the last */
+/* I2C message or if the I2C_M_STOP flag is set. Similarly, the BUSY bit is */
+/* only cleared after the STOP condition, so, between messages we have to */
+/* poll for the DTE bit. */
+/* */
+
+enum sh_mobile_i2c_op {
+ OP_START = 0,
+ OP_TX_FIRST,
+ OP_TX,
+ OP_TX_STOP,
+ OP_TX_TO_RX,
+ OP_RX,
+ OP_RX_STOP,
+ OP_RX_STOP_DATA,
+};
+
+struct sh_mobile_i2c_data {
+ struct device *dev;
+ void __iomem *reg;
+ struct i2c_adapter adap;
+ unsigned long bus_speed;
+ unsigned int clks_per_count;
+ struct clk *clk;
+ u_int8_t icic;
+ u_int8_t flags;
+ u_int16_t iccl;
+ u_int16_t icch;
+
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ struct i2c_msg *msg;
+ int pos;
+ int sr;
+ bool send_stop;
+ bool stop_after_dma;
+
+ struct resource *res;
+ struct dma_chan *dma_tx;
+ struct dma_chan *dma_rx;
+ struct scatterlist sg;
+ enum dma_data_direction dma_direction;
+ u8 *dma_buf;
+};
+
+struct sh_mobile_dt_config {
+ int clks_per_count;
+ int (*setup)(struct sh_mobile_i2c_data *pd);
+};
+
+#define IIC_FLAG_HAS_ICIC67 (1 << 0)
+
+#define STANDARD_MODE 100000
+#define FAST_MODE 400000
+
+/* Register offsets */
+#define ICDR 0x00
+#define ICCR 0x04
+#define ICSR 0x08
+#define ICIC 0x0c
+#define ICCL 0x10
+#define ICCH 0x14
+#define ICSTART 0x70
+
+/* Register bits */
+#define ICCR_ICE 0x80
+#define ICCR_RACK 0x40
+#define ICCR_TRS 0x10
+#define ICCR_BBSY 0x04
+#define ICCR_SCP 0x01
+
+#define ICSR_SCLM 0x80
+#define ICSR_SDAM 0x40
+#define SW_DONE 0x20
+#define ICSR_BUSY 0x10
+#define ICSR_AL 0x08
+#define ICSR_TACK 0x04
+#define ICSR_WAIT 0x02
+#define ICSR_DTE 0x01
+
+#define ICIC_ICCLB8 0x80
+#define ICIC_ICCHB8 0x40
+#define ICIC_TDMAE 0x20
+#define ICIC_RDMAE 0x10
+#define ICIC_ALE 0x08
+#define ICIC_TACKE 0x04
+#define ICIC_WAITE 0x02
+#define ICIC_DTEE 0x01
+
+#define ICSTART_ICSTART 0x10
+
+static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data)
+{
+ if (offs == ICIC)
+ data |= pd->icic;
+
+ iowrite8(data, pd->reg + offs);
+}
+
+static unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs)
+{
+ return ioread8(pd->reg + offs);
+}
+
+static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
+ unsigned char set, unsigned char clr)
+{
+ iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
+}
+
+static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf)
+{
+ /*
+ * Conditional expression:
+ * ICCL >= COUNT_CLK * (tLOW + tf)
+ *
+ * SH-Mobile IIC hardware starts counting the LOW period of
+ * the SCL signal (tLOW) as soon as it pulls the SCL line.
+ * In order to meet the tLOW timing spec, we need to take into
+ * account the fall time of SCL signal (tf). Default tf value
+ * should be 0.3 us, for safety.
+ */
+ return (((count_khz * (tLOW + tf)) + 5000) / 10000);
+}
+
+static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf)
+{
+ /*
+ * Conditional expression:
+ * ICCH >= COUNT_CLK * (tHIGH + tf)
+ *
+ * SH-Mobile IIC hardware is aware of SCL transition period 'tr',
+ * and can ignore it. SH-Mobile IIC controller starts counting
+ * the HIGH period of the SCL signal (tHIGH) after the SCL input
+ * voltage increases at VIH.
+ *
+ * Afterward it turned out calculating ICCH using only tHIGH spec
+ * will result in violation of the tHD;STA timing spec. We need
+ * to take into account the fall time of SDA signal (tf) at START
+ * condition, in order to meet both tHIGH and tHD;STA specs.
+ */
+ return (((count_khz * (tHIGH + tf)) + 5000) / 10000);
+}
+
+static int sh_mobile_i2c_check_timing(struct sh_mobile_i2c_data *pd)
+{
+ u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
+
+ if (pd->iccl > max_val || pd->icch > max_val) {
+ dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n",
+ pd->iccl, pd->icch);
+ return -EINVAL;
+ }
+
+ /* one more bit of ICCL in ICIC */
+ if (pd->iccl & 0x100)
+ pd->icic |= ICIC_ICCLB8;
+ else
+ pd->icic &= ~ICIC_ICCLB8;
+
+ /* one more bit of ICCH in ICIC */
+ if (pd->icch & 0x100)
+ pd->icic |= ICIC_ICCHB8;
+ else
+ pd->icic &= ~ICIC_ICCHB8;
+
+ dev_dbg(pd->dev, "timing values: L/H=0x%x/0x%x\n", pd->iccl, pd->icch);
+ return 0;
+}
+
+static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
+{
+ unsigned long i2c_clk_khz;
+ u32 tHIGH, tLOW, tf;
+
+ i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count;
+
+ if (pd->bus_speed == STANDARD_MODE) {
+ tLOW = 47; /* tLOW = 4.7 us */
+ tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */
+ tf = 3; /* tf = 0.3 us */
+ } else if (pd->bus_speed == FAST_MODE) {
+ tLOW = 13; /* tLOW = 1.3 us */
+ tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */
+ tf = 3; /* tf = 0.3 us */
+ } else {
+ dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
+ pd->bus_speed);
+ return -EINVAL;
+ }
+
+ pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
+ pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
+
+ return sh_mobile_i2c_check_timing(pd);
+}
+
+static int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd)
+{
+ unsigned long clks_per_cycle;
+
+ /* L = 5, H = 4, L + H = 9 */
+ clks_per_cycle = clk_get_rate(pd->clk) / pd->bus_speed;
+ pd->iccl = DIV_ROUND_UP(clks_per_cycle * 5 / 9 - 1, pd->clks_per_count);
+ pd->icch = DIV_ROUND_UP(clks_per_cycle * 4 / 9 - 5, pd->clks_per_count);
+
+ return sh_mobile_i2c_check_timing(pd);
+}
+
+static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
+ enum sh_mobile_i2c_op op, unsigned char data)
+{
+ unsigned char ret = 0;
+ unsigned long flags;
+
+ dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);
+
+ spin_lock_irqsave(&pd->lock, flags);
+
+ switch (op) {
+ case OP_START: /* issue start and trigger DTE interrupt */
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY);
+ break;
+ case OP_TX_FIRST: /* disable DTE interrupt and write data */
+ iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ iic_wr(pd, ICDR, data);
+ break;
+ case OP_TX: /* write data */
+ iic_wr(pd, ICDR, data);
+ break;
+ case OP_TX_STOP: /* issue a stop (or rep_start) */
+ iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
+ : ICCR_ICE | ICCR_TRS | ICCR_BBSY);
+ break;
+ case OP_TX_TO_RX: /* select read mode */
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
+ break;
+ case OP_RX: /* just read data */
+ ret = iic_rd(pd, ICDR);
+ break;
+ case OP_RX_STOP: /* enable DTE interrupt, issue stop */
+ iic_wr(pd, ICIC,
+ ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
+ break;
+ case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
+ iic_wr(pd, ICIC,
+ ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ ret = iic_rd(pd, ICDR);
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
+ break;
+ }
+
+ spin_unlock_irqrestore(&pd->lock, flags);
+
+ dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
+ return ret;
+}
+
+static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
+{
+ return pd->pos == -1;
+}
+
+static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
+ unsigned char *buf)
+{
+ switch (pd->pos) {
+ case -1:
+ *buf = i2c_8bit_addr_from_msg(pd->msg);
+ break;
+ default:
+ *buf = pd->msg->buf[pd->pos];
+ }
+}
+
+static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
+{
+ unsigned char data;
+
+ if (pd->pos == pd->msg->len) {
+ i2c_op(pd, OP_TX_STOP, 0);
+ return 1;
+ }
+
+ sh_mobile_i2c_get_data(pd, &data);
+ i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data);
+
+ pd->pos++;
+ return 0;
+}
+
+static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
+{
+ unsigned char data;
+ int real_pos;
+
+ do {
+ if (pd->pos <= -1) {
+ sh_mobile_i2c_get_data(pd, &data);
+
+ if (sh_mobile_i2c_is_first_byte(pd))
+ i2c_op(pd, OP_TX_FIRST, data);
+ else
+ i2c_op(pd, OP_TX, data);
+ break;
+ }
+
+ if (pd->pos == 0) {
+ i2c_op(pd, OP_TX_TO_RX, 0);
+ break;
+ }
+
+ real_pos = pd->pos - 2;
+
+ if (pd->pos == pd->msg->len) {
+ if (pd->stop_after_dma) {
+ /* Simulate PIO end condition after DMA transfer */
+ i2c_op(pd, OP_RX_STOP, 0);
+ pd->pos++;
+ break;
+ }
+
+ if (real_pos < 0) {
+ i2c_op(pd, OP_RX_STOP, 0);
+ break;
+ }
+ data = i2c_op(pd, OP_RX_STOP_DATA, 0);
+ } else if (real_pos >= 0) {
+ data = i2c_op(pd, OP_RX, 0);
+ }
+
+ if (real_pos >= 0)
+ pd->msg->buf[real_pos] = data;
+ } while (0);
+
+ pd->pos++;
+ return pd->pos == (pd->msg->len + 2);
+}
+
+static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
+{
+ struct sh_mobile_i2c_data *pd = dev_id;
+ unsigned char sr;
+ int wakeup = 0;
+
+ sr = iic_rd(pd, ICSR);
+ pd->sr |= sr; /* remember state */
+
+ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
+ (pd->msg->flags & I2C_M_RD) ? "read" : "write",
+ pd->pos, pd->msg->len);
+
+ /* Kick off TxDMA after preface was done */
+ if (pd->dma_direction == DMA_TO_DEVICE && pd->pos == 0)
+ iic_set_clr(pd, ICIC, ICIC_TDMAE, 0);
+ else if (sr & (ICSR_AL | ICSR_TACK))
+ /* don't interrupt transaction - continue to issue stop */
+ iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
+ else if (pd->msg->flags & I2C_M_RD)
+ wakeup = sh_mobile_i2c_isr_rx(pd);
+ else
+ wakeup = sh_mobile_i2c_isr_tx(pd);
+
+ /* Kick off RxDMA after preface was done */
+ if (pd->dma_direction == DMA_FROM_DEVICE && pd->pos == 1)
+ iic_set_clr(pd, ICIC, ICIC_RDMAE, 0);
+
+ if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
+ iic_wr(pd, ICSR, sr & ~ICSR_WAIT);
+
+ if (wakeup) {
+ pd->sr |= SW_DONE;
+ wake_up(&pd->wait);
+ }
+
+ /* defeat write posting to avoid spurious WAIT interrupts */
+ iic_rd(pd, ICSR);
+
+ return IRQ_HANDLED;
+}
+
+static void sh_mobile_i2c_dma_unmap(struct sh_mobile_i2c_data *pd)
+{
+ struct dma_chan *chan = pd->dma_direction == DMA_FROM_DEVICE
+ ? pd->dma_rx : pd->dma_tx;
+
+ dma_unmap_single(chan->device->dev, sg_dma_address(&pd->sg),
+ pd->msg->len, pd->dma_direction);
+
+ pd->dma_direction = DMA_NONE;
+}
+
+static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd)
+{
+ if (pd->dma_direction == DMA_NONE)
+ return;
+ else if (pd->dma_direction == DMA_FROM_DEVICE)
+ dmaengine_terminate_all(pd->dma_rx);
+ else if (pd->dma_direction == DMA_TO_DEVICE)
+ dmaengine_terminate_all(pd->dma_tx);
+
+ sh_mobile_i2c_dma_unmap(pd);
+}
+
+static void sh_mobile_i2c_dma_callback(void *data)
+{
+ struct sh_mobile_i2c_data *pd = data;
+
+ sh_mobile_i2c_dma_unmap(pd);
+ pd->pos = pd->msg->len;
+ pd->stop_after_dma = true;
+
+ iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
+}
+
+static struct dma_chan *sh_mobile_i2c_request_dma_chan(struct device *dev,
+ enum dma_transfer_direction dir, dma_addr_t port_addr)
+{
+ struct dma_chan *chan;
+ struct dma_slave_config cfg;
+ char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
+ int ret;
+
+ chan = dma_request_slave_channel_reason(dev, chan_name);
+ if (IS_ERR(chan)) {
+ dev_dbg(dev, "request_channel failed for %s (%ld)\n", chan_name,
+ PTR_ERR(chan));
+ return chan;
+ }
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.direction = dir;
+ if (dir == DMA_MEM_TO_DEV) {
+ cfg.dst_addr = port_addr;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ } else {
+ cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
+
+ ret = dmaengine_slave_config(chan, &cfg);
+ if (ret) {
+ dev_dbg(dev, "slave_config failed for %s (%d)\n", chan_name, ret);
+ dma_release_channel(chan);
+ return ERR_PTR(ret);
+ }
+
+ dev_dbg(dev, "got DMA channel for %s\n", chan_name);
+ return chan;
+}
+
+static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
+{
+ bool read = pd->msg->flags & I2C_M_RD;
+ enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ struct dma_chan *chan = read ? pd->dma_rx : pd->dma_tx;
+ struct dma_async_tx_descriptor *txdesc;
+ dma_addr_t dma_addr;
+ dma_cookie_t cookie;
+
+ if (PTR_ERR(chan) == -EPROBE_DEFER) {
+ if (read)
+ chan = pd->dma_rx = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM,
+ pd->res->start + ICDR);
+ else
+ chan = pd->dma_tx = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_MEM_TO_DEV,
+ pd->res->start + ICDR);
+ }
+
+ if (IS_ERR(chan))
+ return;
+
+ dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir);
+ if (dma_mapping_error(chan->device->dev, dma_addr)) {
+ dev_dbg(pd->dev, "dma map failed, using PIO\n");
+ return;
+ }
+
+ sg_dma_len(&pd->sg) = pd->msg->len;
+ sg_dma_address(&pd->sg) = dma_addr;
+
+ pd->dma_direction = dir;
+
+ txdesc = dmaengine_prep_slave_sg(chan, &pd->sg, 1,
+ read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc) {
+ dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n");
+ sh_mobile_i2c_cleanup_dma(pd);
+ return;
+ }
+
+ txdesc->callback = sh_mobile_i2c_dma_callback;
+ txdesc->callback_param = pd;
+
+ cookie = dmaengine_submit(txdesc);
+ if (dma_submit_error(cookie)) {
+ dev_dbg(pd->dev, "submitting dma failed, using PIO\n");
+ sh_mobile_i2c_cleanup_dma(pd);
+ return;
+ }
+
+ dma_async_issue_pending(chan);
+}
+
+static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
+ bool do_init)
+{
+ if (do_init) {
+ /* Initialize channel registers */
+ iic_wr(pd, ICCR, ICCR_SCP);
+
+ /* Enable channel and configure rx ack */
+ iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
+
+ /* Set the clock */
+ iic_wr(pd, ICCL, pd->iccl & 0xff);
+ iic_wr(pd, ICCH, pd->icch & 0xff);
+ }
+
+ pd->msg = usr_msg;
+ pd->pos = -1;
+ pd->sr = 0;
+
+ pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
+ if (pd->dma_buf)
+ sh_mobile_i2c_xfer_dma(pd);
+
+ /* Enable all interrupts to begin with */
+ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+}
+
+static int poll_dte(struct sh_mobile_i2c_data *pd)
+{
+ int i;
+
+ for (i = 1000; i; i--) {
+ u_int8_t val = iic_rd(pd, ICSR);
+
+ if (val & ICSR_DTE)
+ break;
+
+ if (val & ICSR_TACK)
+ return -ENXIO;
+
+ udelay(10);
+ }
+
+ return i ? 0 : -ETIMEDOUT;
+}
+
+static int poll_busy(struct sh_mobile_i2c_data *pd)
+{
+ int i;
+
+ for (i = 1000; i; i--) {
+ u_int8_t val = iic_rd(pd, ICSR);
+
+ dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
+
+ /* the interrupt handler may wake us up before the
+ * transfer is finished, so poll the hardware
+ * until we're done.
+ */
+ if (!(val & ICSR_BUSY)) {
+ /* handle missing acknowledge and arbitration lost */
+ val |= pd->sr;
+ if (val & ICSR_TACK)
+ return -ENXIO;
+ if (val & ICSR_AL)
+ return -EAGAIN;
+ break;
+ }
+
+ udelay(10);
+ }
+
+ return i ? 0 : -ETIMEDOUT;
+}
+
+static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+ struct i2c_msg *msg;
+ int err = 0;
+ int i;
+ long timeout;
+
+ /* Wake up device and enable clock */
+ pm_runtime_get_sync(pd->dev);
+
+ /* Process all messages */
+ for (i = 0; i < num; i++) {
+ bool do_start = pd->send_stop || !i;
+ msg = &msgs[i];
+ pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
+ pd->stop_after_dma = false;
+
+ start_ch(pd, msg, do_start);
+
+ if (do_start)
+ i2c_op(pd, OP_START, 0);
+
+ /* The interrupt handler takes care of the rest... */
+ timeout = wait_event_timeout(pd->wait,
+ pd->sr & (ICSR_TACK | SW_DONE),
+ adapter->timeout);
+
+ /* 'stop_after_dma' tells if DMA transfer was complete */
+ i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
+
+ if (!timeout) {
+ dev_err(pd->dev, "Transfer request timed out\n");
+ if (pd->dma_direction != DMA_NONE)
+ sh_mobile_i2c_cleanup_dma(pd);
+
+ err = -ETIMEDOUT;
+ break;
+ }
+
+ if (pd->send_stop)
+ err = poll_busy(pd);
+ else
+ err = poll_dte(pd);
+ if (err < 0)
+ break;
+ }
+
+ /* Disable channel */
+ iic_wr(pd, ICCR, ICCR_SCP);
+
+ /* Disable clock and mark device as idle */
+ pm_runtime_put_sync(pd->dev);
+
+ return err ?: num;
+}
+
+static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
+ .functionality = sh_mobile_i2c_func,
+ .master_xfer = sh_mobile_i2c_xfer,
+};
+
+static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN_READ,
+};
+
+/*
+ * r8a7740 chip has lasting errata on I2C I/O pad reset.
+ * this is work-around for it.
+ */
+static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
+{
+ iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+ iic_rd(pd, ICCR); /* dummy read */
+
+ iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0);
+ iic_rd(pd, ICSTART); /* dummy read */
+
+ udelay(10);
+
+ iic_wr(pd, ICCR, ICCR_SCP);
+ iic_wr(pd, ICSTART, 0);
+
+ udelay(10);
+
+ iic_wr(pd, ICCR, ICCR_TRS);
+ udelay(10);
+ iic_wr(pd, ICCR, 0);
+ udelay(10);
+ iic_wr(pd, ICCR, ICCR_TRS);
+ udelay(10);
+
+ return sh_mobile_i2c_init(pd);
+}
+
+static const struct sh_mobile_dt_config default_dt_config = {
+ .clks_per_count = 1,
+ .setup = sh_mobile_i2c_init,
+};
+
+static const struct sh_mobile_dt_config fast_clock_dt_config = {
+ .clks_per_count = 2,
+ .setup = sh_mobile_i2c_init,
+};
+
+static const struct sh_mobile_dt_config v2_freq_calc_dt_config = {
+ .clks_per_count = 2,
+ .setup = sh_mobile_i2c_v2_init,
+};
+
+static const struct sh_mobile_dt_config r8a7740_dt_config = {
+ .clks_per_count = 1,
+ .setup = sh_mobile_i2c_r8a7740_workaround,
+};
+
+static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
+ { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
+ { .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
+ { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids);
+
+static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd)
+{
+ if (!IS_ERR(pd->dma_tx)) {
+ dma_release_channel(pd->dma_tx);
+ pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
+ }
+
+ if (!IS_ERR(pd->dma_rx)) {
+ dma_release_channel(pd->dma_rx);
+ pd->dma_rx = ERR_PTR(-EPROBE_DEFER);
+ }
+}
+
+static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, struct sh_mobile_i2c_data *pd)
+{
+ struct resource *res;
+ resource_size_t n;
+ int k = 0, ret;
+
+ while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
+ for (n = res->start; n <= res->end; n++) {
+ ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr,
+ 0, dev_name(&dev->dev), pd);
+ if (ret) {
+ dev_err(&dev->dev, "cannot request IRQ %pa\n", &n);
+ return ret;
+ }
+ }
+ k++;
+ }
+
+ return k > 0 ? 0 : -ENOENT;
+}
+
+static int sh_mobile_i2c_probe(struct platform_device *dev)
+{
+ struct sh_mobile_i2c_data *pd;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ const struct sh_mobile_dt_config *config;
+ int ret;
+ u32 bus_speed;
+
+ pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pd->clk = devm_clk_get(&dev->dev, NULL);
+ if (IS_ERR(pd->clk)) {
+ dev_err(&dev->dev, "cannot get clock\n");
+ return PTR_ERR(pd->clk);
+ }
+
+ ret = sh_mobile_i2c_hook_irqs(dev, pd);
+ if (ret)
+ return ret;
+
+ pd->dev = &dev->dev;
+ platform_set_drvdata(dev, pd);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+ pd->res = res;
+ pd->reg = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(pd->reg))
+ return PTR_ERR(pd->reg);
+
+ ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
+ pd->bus_speed = (ret || !bus_speed) ? STANDARD_MODE : bus_speed;
+ pd->clks_per_count = 1;
+
+ /* Newer variants come with two new bits in ICIC */
+ if (resource_size(res) > 0x17)
+ pd->flags |= IIC_FLAG_HAS_ICIC67;
+
+ pm_runtime_enable(&dev->dev);
+ pm_runtime_get_sync(&dev->dev);
+
+ config = of_device_get_match_data(&dev->dev);
+ if (config) {
+ pd->clks_per_count = config->clks_per_count;
+ ret = config->setup(pd);
+ } else {
+ ret = sh_mobile_i2c_init(pd);
+ }
+
+ pm_runtime_put_sync(&dev->dev);
+ if (ret)
+ return ret;
+
+ /* Init DMA */
+ sg_init_table(&pd->sg, 1);
+ pd->dma_direction = DMA_NONE;
+ pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
+
+ /* setup the private data */
+ adap = &pd->adap;
+ i2c_set_adapdata(adap, pd);
+
+ adap->owner = THIS_MODULE;
+ adap->algo = &sh_mobile_i2c_algorithm;
+ adap->quirks = &sh_mobile_i2c_quirks;
+ adap->dev.parent = &dev->dev;
+ adap->retries = 5;
+ adap->nr = dev->id;
+ adap->dev.of_node = dev->dev.of_node;
+
+ strlcpy(adap->name, dev->name, sizeof(adap->name));
+
+ spin_lock_init(&pd->lock);
+ init_waitqueue_head(&pd->wait);
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret < 0) {
+ sh_mobile_i2c_release_dma(pd);
+ return ret;
+ }
+
+ dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz\n", adap->nr, pd->bus_speed);
+
+ return 0;
+}
+
+static int sh_mobile_i2c_remove(struct platform_device *dev)
+{
+ struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&pd->adap);
+ sh_mobile_i2c_release_dma(pd);
+ pm_runtime_disable(&dev->dev);
+ return 0;
+}
+
+static int sh_mobile_i2c_runtime_nop(struct device *dev)
+{
+ /* Runtime PM callback shared between ->runtime_suspend()
+ * and ->runtime_resume(). Simply returns success.
+ *
+ * This driver re-initializes all registers after
+ * pm_runtime_get_sync() anyway so there is no need
+ * to save and restore registers here.
+ */
+ return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
+ .runtime_suspend = sh_mobile_i2c_runtime_nop,
+ .runtime_resume = sh_mobile_i2c_runtime_nop,
+};
+
+static struct platform_driver sh_mobile_i2c_driver = {
+ .driver = {
+ .name = "i2c-sh_mobile",
+ .pm = &sh_mobile_i2c_dev_pm_ops,
+ .of_match_table = sh_mobile_i2c_dt_ids,
+ },
+ .probe = sh_mobile_i2c_probe,
+ .remove = sh_mobile_i2c_remove,
+};
+
+static int __init sh_mobile_i2c_adap_init(void)
+{
+ return platform_driver_register(&sh_mobile_i2c_driver);
+}
+subsys_initcall(sh_mobile_i2c_adap_init);
+
+static void __exit sh_mobile_i2c_adap_exit(void)
+{
+ platform_driver_unregister(&sh_mobile_i2c_driver);
+}
+module_exit(sh_mobile_i2c_adap_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
+MODULE_AUTHOR("Magnus Damm and Wolfram Sang");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-sh_mobile");
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
new file mode 100644
index 000000000..2b6219d86
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2004 Steven J. Hill
+ * Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 1995-2000 Simon G. Vogl
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_smbus.h>
+
+
+struct i2c_algo_sibyte_data {
+ void *data; /* private data */
+ int bus; /* which bus */
+ void *reg_base; /* CSR base */
+};
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+ int data_bytes = 0;
+ int error;
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ csr_out32((V_SMB_ADDR(addr) |
+ (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_LB(data->byte),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 2;
+ } else {
+ csr_out32(V_SMB_LB(data->word & 0xff),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32(V_SMB_MB(data->word >> 8),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+ if (error & M_SMB_ERROR) {
+ /* Clear error bit by writing a 1 */
+ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+ return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO;
+ }
+
+ if (data_bytes == 1)
+ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+ if (data_bytes == 2)
+ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+ return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm i2c_sibyte_algo = {
+ .smbus_xfer = smbus_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+ /* Register new adapter to i2c module... */
+ i2c_adap->algo = &i2c_sibyte_algo;
+
+ /* Set the requested frequency. */
+ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+ return i2c_add_numbered_adapter(i2c_adap);
+}
+
+
+static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
+ { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
+ { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
+};
+
+static struct i2c_adapter sibyte_board_adapter[2] = {
+ {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = NULL,
+ .algo_data = &sibyte_board_data[0],
+ .nr = 0,
+ .name = "SiByte SMBus 0",
+ },
+ {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = NULL,
+ .algo_data = &sibyte_board_data[1],
+ .nr = 1,
+ .name = "SiByte SMBus 1",
+ },
+};
+
+static int __init i2c_sibyte_init(void)
+{
+ pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n");
+ if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0)
+ return -ENODEV;
+ if (i2c_sibyte_add_bus(&sibyte_board_adapter[1],
+ K_SMB_FREQ_400KHZ) < 0) {
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit i2c_sibyte_exit(void)
+{
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ i2c_del_adapter(&sibyte_board_adapter[1]);
+}
+
+module_init(i2c_sibyte_init);
+module_exit(i2c_sibyte_exit);
+
+MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
new file mode 100644
index 000000000..adca51a99
--- /dev/null
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct simtec_i2c_data {
+ struct resource *ioarea;
+ void __iomem *reg;
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA (1<<2)
+#define CMD_SET_SCL (1<<3)
+
+#define STATE_SDA (1<<0)
+#define STATE_SCL (1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd;
+ struct resource *res;
+ int size;
+ int ret;
+
+ pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+ if (pd == NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(dev, pd);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&dev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ size = resource_size(res);
+
+ pd->ioarea = request_mem_region(res->start, size, dev->name);
+ if (pd->ioarea == NULL) {
+ dev_err(&dev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err;
+ }
+
+ pd->reg = ioremap(res->start, size);
+ if (pd->reg == NULL) {
+ dev_err(&dev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_res;
+ }
+
+ /* setup the private data */
+
+ pd->adap.owner = THIS_MODULE;
+ pd->adap.algo_data = &pd->bit;
+ pd->adap.dev.parent = &dev->dev;
+
+ strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+ pd->bit.data = pd;
+ pd->bit.setsda = simtec_i2c_setsda;
+ pd->bit.setscl = simtec_i2c_setscl;
+ pd->bit.getsda = simtec_i2c_getsda;
+ pd->bit.getscl = simtec_i2c_getscl;
+ pd->bit.timeout = HZ;
+ pd->bit.udelay = 20;
+
+ ret = i2c_bit_add_bus(&pd->adap);
+ if (ret)
+ goto err_all;
+
+ return 0;
+
+ err_all:
+ iounmap(pd->reg);
+
+ err_res:
+ release_mem_region(pd->ioarea->start, size);
+
+ err:
+ kfree(pd);
+ return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&pd->adap);
+
+ iounmap(pd->reg);
+ release_mem_region(pd->ioarea->start, resource_size(pd->ioarea));
+ kfree(pd);
+
+ return 0;
+}
+
+/* device driver */
+
+static struct platform_driver simtec_i2c_driver = {
+ .driver = {
+ .name = "simtec-i2c",
+ },
+ .probe = simtec_i2c_probe,
+ .remove = simtec_i2c_remove,
+};
+
+module_platform_driver(simtec_i2c_driver);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:simtec-i2c");
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
new file mode 100644
index 000000000..87197ece0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -0,0 +1,479 @@
+/*
+ * I2C bus driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#define SIRFSOC_I2C_CLK_CTRL 0x00
+#define SIRFSOC_I2C_STATUS 0x0C
+#define SIRFSOC_I2C_CTRL 0x10
+#define SIRFSOC_I2C_IO_CTRL 0x14
+#define SIRFSOC_I2C_SDA_DELAY 0x18
+#define SIRFSOC_I2C_CMD_START 0x1C
+#define SIRFSOC_I2C_CMD_BUF 0x30
+#define SIRFSOC_I2C_DATA_BUF 0x80
+
+#define SIRFSOC_I2C_CMD_BUF_MAX 16
+#define SIRFSOC_I2C_DATA_BUF_MAX 16
+
+#define SIRFSOC_I2C_CMD(x) (SIRFSOC_I2C_CMD_BUF + (x)*0x04)
+#define SIRFSOC_I2C_DATA_MASK(x) (0xFF<<(((x)&3)*8))
+#define SIRFSOC_I2C_DATA_SHIFT(x) (((x)&3)*8)
+
+#define SIRFSOC_I2C_DIV_MASK (0xFFFF)
+
+/* I2C status flags */
+#define SIRFSOC_I2C_STAT_BUSY BIT(0)
+#define SIRFSOC_I2C_STAT_TIP BIT(1)
+#define SIRFSOC_I2C_STAT_NACK BIT(2)
+#define SIRFSOC_I2C_STAT_TR_INT BIT(4)
+#define SIRFSOC_I2C_STAT_STOP BIT(6)
+#define SIRFSOC_I2C_STAT_CMD_DONE BIT(8)
+#define SIRFSOC_I2C_STAT_ERR BIT(9)
+#define SIRFSOC_I2C_CMD_INDEX (0x1F<<16)
+
+/* I2C control flags */
+#define SIRFSOC_I2C_RESET BIT(0)
+#define SIRFSOC_I2C_CORE_EN BIT(1)
+#define SIRFSOC_I2C_MASTER_MODE BIT(2)
+#define SIRFSOC_I2C_CMD_DONE_EN BIT(11)
+#define SIRFSOC_I2C_ERR_INT_EN BIT(12)
+
+#define SIRFSOC_I2C_SDA_DELAY_MASK (0xFF)
+#define SIRFSOC_I2C_SCLF_FILTER (3<<8)
+
+#define SIRFSOC_I2C_START_CMD BIT(0)
+
+#define SIRFSOC_I2C_CMD_RP(x) ((x)&0x7)
+#define SIRFSOC_I2C_NACK BIT(3)
+#define SIRFSOC_I2C_WRITE BIT(4)
+#define SIRFSOC_I2C_READ BIT(5)
+#define SIRFSOC_I2C_STOP BIT(6)
+#define SIRFSOC_I2C_START BIT(7)
+
+#define SIRFSOC_I2C_DEFAULT_SPEED 100000
+#define SIRFSOC_I2C_ERR_NOACK 1
+#define SIRFSOC_I2C_ERR_TIMEOUT 2
+
+struct sirfsoc_i2c {
+ void __iomem *base;
+ struct clk *clk;
+ u32 cmd_ptr; /* Current position in CMD buffer */
+ u8 *buf; /* Buffer passed by user */
+ u32 msg_len; /* Message length */
+ u32 finished_len; /* number of bytes read/written */
+ u32 read_cmd_len; /* number of read cmd sent */
+ int msg_read; /* 1 indicates a read message */
+ int err_status; /* 1 indicates an error on bus */
+
+ u32 sda_delay; /* For suspend/resume */
+ u32 clk_div;
+ int last; /* Last message in transfer, STOP cmd can be sent */
+
+ struct completion done; /* indicates completion of message transfer */
+ struct i2c_adapter adapter;
+};
+
+static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
+{
+ u32 data = 0;
+ int i;
+
+ for (i = 0; i < siic->read_cmd_len; i++) {
+ if (!(i & 0x3))
+ data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
+ siic->buf[siic->finished_len++] =
+ (u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
+ SIRFSOC_I2C_DATA_SHIFT(i));
+ }
+}
+
+static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
+{
+ u32 regval;
+ int i = 0;
+
+ if (siic->msg_read) {
+ while (((siic->finished_len + i) < siic->msg_len)
+ && (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
+ regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
+ if (((siic->finished_len + i) ==
+ (siic->msg_len - 1)) && siic->last)
+ regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
+ writel(regval,
+ siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+ i++;
+ }
+
+ siic->read_cmd_len = i;
+ } else {
+ while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
+ && (siic->finished_len < siic->msg_len)) {
+ regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
+ if ((siic->finished_len == (siic->msg_len - 1))
+ && siic->last)
+ regval |= SIRFSOC_I2C_STOP;
+ writel(regval,
+ siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+ writel(siic->buf[siic->finished_len++],
+ siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+ }
+ }
+ siic->cmd_ptr = 0;
+
+ /* Trigger the transfer */
+ writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
+}
+
+static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
+{
+ struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
+ u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
+
+ if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
+ /* Error conditions */
+ siic->err_status = SIRFSOC_I2C_ERR_NOACK;
+ writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
+
+ if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
+ dev_dbg(&siic->adapter.dev, "ACK not received\n");
+ else
+ dev_err(&siic->adapter.dev, "I2C error\n");
+
+ /*
+ * Due to hardware ANOMALY, we need to reset I2C earlier after
+ * we get NOACK while accessing non-existing clients, otherwise
+ * we will get errors even we access existing clients later
+ */
+ writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+ siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
+
+ complete(&siic->done);
+ } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
+ /* CMD buffer execution complete */
+ if (siic->msg_read)
+ i2c_sirfsoc_read_data(siic);
+ if (siic->finished_len == siic->msg_len)
+ complete(&siic->done);
+ else /* Fill a new CMD buffer for left data */
+ i2c_sirfsoc_queue_cmd(siic);
+
+ writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
+ struct i2c_msg *msg)
+{
+ unsigned char addr;
+ u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
+
+ /* no data and last message -> add STOP */
+ if (siic->last && (msg->len == 0))
+ regval |= SIRFSOC_I2C_STOP;
+
+ writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+
+ addr = i2c_8bit_addr_from_msg(msg);
+
+ /* Reverse direction bit */
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
+ writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+}
+
+static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
+{
+ u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
+ /* timeout waiting for the xfer to finish or fail */
+ int timeout = msecs_to_jiffies((msg->len + 1) * 50);
+
+ i2c_sirfsoc_set_address(siic, msg);
+
+ writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
+ siic->base + SIRFSOC_I2C_CTRL);
+ i2c_sirfsoc_queue_cmd(siic);
+
+ if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
+ siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT;
+ dev_err(&siic->adapter.dev, "Transfer timeout\n");
+ }
+
+ writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
+ siic->base + SIRFSOC_I2C_CTRL);
+ writel(0, siic->base + SIRFSOC_I2C_CMD_START);
+
+ /* i2c control doesn't response, reset it */
+ if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) {
+ writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+ siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
+ }
+ return siic->err_status ? -EAGAIN : 0;
+}
+
+static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct sirfsoc_i2c *siic = adap->algo_data;
+ int i, ret;
+
+ clk_enable(siic->clk);
+
+ for (i = 0; i < num; i++) {
+ siic->buf = msgs[i].buf;
+ siic->msg_len = msgs[i].len;
+ siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
+ siic->err_status = 0;
+ siic->cmd_ptr = 0;
+ siic->finished_len = 0;
+ siic->last = (i == (num - 1));
+
+ ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
+ if (ret) {
+ clk_disable(siic->clk);
+ return ret;
+ }
+ }
+
+ clk_disable(siic->clk);
+ return num;
+}
+
+/* I2C algorithms associated with this master controller driver */
+static const struct i2c_algorithm i2c_sirfsoc_algo = {
+ .master_xfer = i2c_sirfsoc_xfer,
+ .functionality = i2c_sirfsoc_func,
+};
+
+static int i2c_sirfsoc_probe(struct platform_device *pdev)
+{
+ struct sirfsoc_i2c *siic;
+ struct i2c_adapter *adap;
+ struct resource *mem_res;
+ struct clk *clk;
+ int bitrate;
+ int ctrl_speed;
+ int irq;
+
+ int err;
+ u32 regval;
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ err = PTR_ERR(clk);
+ dev_err(&pdev->dev, "Clock get failed\n");
+ goto err_get_clk;
+ }
+
+ err = clk_prepare(clk);
+ if (err) {
+ dev_err(&pdev->dev, "Clock prepare failed\n");
+ goto err_clk_prep;
+ }
+
+ err = clk_enable(clk);
+ if (err) {
+ dev_err(&pdev->dev, "Clock enable failed\n");
+ goto err_clk_en;
+ }
+
+ ctrl_speed = clk_get_rate(clk);
+
+ siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
+ if (!siic) {
+ err = -ENOMEM;
+ goto out;
+ }
+ adap = &siic->adapter;
+ adap->class = I2C_CLASS_DEPRECATED;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(siic->base)) {
+ err = PTR_ERR(siic->base);
+ goto out;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ err = irq;
+ goto out;
+ }
+ err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
+ dev_name(&pdev->dev), siic);
+ if (err)
+ goto out;
+
+ adap->algo = &i2c_sirfsoc_algo;
+ adap->algo_data = siic;
+ adap->retries = 3;
+
+ adap->dev.of_node = pdev->dev.of_node;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+
+ strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
+
+ platform_set_drvdata(pdev, adap);
+ init_completion(&siic->done);
+
+ /* Controller initialisation */
+
+ writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
+ writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+ siic->base + SIRFSOC_I2C_CTRL);
+
+ siic->clk = clk;
+
+ err = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &bitrate);
+ if (err < 0)
+ bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
+
+ /*
+ * Due to some hardware design issues, we need to tune the formula.
+ * Since i2c is open drain interface that allows the slave to
+ * stall the transaction by holding the SCL line at '0', the RTL
+ * implementation is waiting for SCL feedback from the pin after
+ * setting it to High-Z ('1'). This wait adds to the high-time
+ * interval counter few cycles of the input synchronization
+ * (depending on the SCL_FILTER_REG field), and also the time it
+ * takes for the board pull-up resistor to rise the SCL line.
+ * For slow SCL settings these additions are negligible,
+ * but they start to affect the speed when clock is set to faster
+ * frequencies.
+ * Through the actual tests, use the different user_div value(which
+ * in the divider formula 'Fio / (Fi2c * user_div)') to adapt
+ * the different ranges of i2c bus clock frequency, to make the SCL
+ * more accurate.
+ */
+ if (bitrate <= 30000)
+ regval = ctrl_speed / (bitrate * 5);
+ else if (bitrate > 30000 && bitrate <= 280000)
+ regval = (2 * ctrl_speed) / (bitrate * 11);
+ else
+ regval = ctrl_speed / (bitrate * 6);
+
+ writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
+ if (regval > 0xFF)
+ writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
+ else
+ writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
+
+ err = i2c_add_numbered_adapter(adap);
+ if (err < 0)
+ goto out;
+
+ clk_disable(clk);
+
+ dev_info(&pdev->dev, " I2C adapter ready to operate\n");
+
+ return 0;
+
+out:
+ clk_disable(clk);
+err_clk_en:
+ clk_unprepare(clk);
+err_clk_prep:
+ clk_put(clk);
+err_get_clk:
+ return err;
+}
+
+static int i2c_sirfsoc_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct sirfsoc_i2c *siic = adapter->algo_data;
+
+ writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+ i2c_del_adapter(adapter);
+ clk_unprepare(siic->clk);
+ clk_put(siic->clk);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_sirfsoc_suspend(struct device *dev)
+{
+ struct i2c_adapter *adapter = dev_get_drvdata(dev);
+ struct sirfsoc_i2c *siic = adapter->algo_data;
+
+ clk_enable(siic->clk);
+ siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
+ siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
+ clk_disable(siic->clk);
+ return 0;
+}
+
+static int i2c_sirfsoc_resume(struct device *dev)
+{
+ struct i2c_adapter *adapter = dev_get_drvdata(dev);
+ struct sirfsoc_i2c *siic = adapter->algo_data;
+
+ clk_enable(siic->clk);
+ writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
+ writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+ siic->base + SIRFSOC_I2C_CTRL);
+ writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
+ writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
+ clk_disable(siic->clk);
+ return 0;
+}
+
+static const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
+ .suspend = i2c_sirfsoc_suspend,
+ .resume = i2c_sirfsoc_resume,
+};
+#endif
+
+static const struct of_device_id sirfsoc_i2c_of_match[] = {
+ { .compatible = "sirf,prima2-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
+
+static struct platform_driver i2c_sirfsoc_driver = {
+ .driver = {
+ .name = "sirfsoc_i2c",
+#ifdef CONFIG_PM
+ .pm = &i2c_sirfsoc_pm_ops,
+#endif
+ .of_match_table = sirfsoc_i2c_of_match,
+ },
+ .probe = i2c_sirfsoc_probe,
+ .remove = i2c_sirfsoc_remove,
+};
+module_platform_driver(i2c_sirfsoc_driver);
+
+MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
+MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
+ "Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
new file mode 100644
index 000000000..d543a9867
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -0,0 +1,430 @@
+/*
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/* Note: we assume there can only be one SIS5595 with one SMBus interface */
+
+/*
+ Note: all have mfr. ID 0x1039.
+ SUPPORTED PCI ID
+ 5595 0008
+
+ Note: these chips contain a 0008 device which is incompatible with the
+ 5595. We recognize these by the presence of the listed
+ "blacklist" PCI ID and refuse to load.
+
+ NOT SUPPORTED PCI ID BLACKLIST PCI ID
+ 540 0008 0540
+ 550 0008 0550
+ 5513 0008 5511
+ 5581 0008 5597
+ 5582 0008 5597
+ 5597 0008 5597
+ 5598 0008 5597/5598
+ 630 0008 0630
+ 645 0008 0645
+ 646 0008 0646
+ 648 0008 0648
+ 650 0008 0650
+ 651 0008 0651
+ 730 0008 0730
+ 735 0008 0735
+ 745 0008 0745
+ 746 0008 0746
+*/
+
+/* TO DO:
+ * Add Block Transfers (ugly, but supported by the adapter)
+ * Add adapter resets
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static int blacklist[] = {
+ PCI_DEVICE_ID_SI_540,
+ PCI_DEVICE_ID_SI_550,
+ PCI_DEVICE_ID_SI_630,
+ PCI_DEVICE_ID_SI_645,
+ PCI_DEVICE_ID_SI_646,
+ PCI_DEVICE_ID_SI_648,
+ PCI_DEVICE_ID_SI_650,
+ PCI_DEVICE_ID_SI_651,
+ PCI_DEVICE_ID_SI_730,
+ PCI_DEVICE_ID_SI_735,
+ PCI_DEVICE_ID_SI_745,
+ PCI_DEVICE_ID_SI_746,
+ PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but that ID
+ shows up in other chips so we use the 5511
+ ID for recognition */
+ PCI_DEVICE_ID_SI_5597,
+ PCI_DEVICE_ID_SI_5598,
+ 0, /* terminates the list */
+};
+
+/* Length of ISA address segment */
+#define SIS5595_EXTENT 8
+/* SIS5595 SMBus registers */
+#define SMB_STS_LO 0x00
+#define SMB_STS_HI 0x01
+#define SMB_CTL_LO 0x02
+#define SMB_CTL_HI 0x03
+#define SMB_ADDR 0x04
+#define SMB_CMD 0x05
+#define SMB_PCNT 0x06
+#define SMB_CNT 0x07
+#define SMB_BYTE 0x08
+#define SMB_DEV 0x10
+#define SMB_DB0 0x11
+#define SMB_DB1 0x12
+#define SMB_HAA 0x13
+
+/* PCI Address Constants */
+#define SMB_INDEX 0x38
+#define SMB_DAT 0x39
+#define SIS5595_ENABLE_REG 0x40
+#define ACPI_BASE 0x90
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SIS5595 constants */
+#define SIS5595_QUICK 0x00
+#define SIS5595_BYTE 0x02
+#define SIS5595_BYTE_DATA 0x04
+#define SIS5595_WORD_DATA 0x06
+#define SIS5595_PROC_CALL 0x08
+#define SIS5595_BLOCK_DATA 0x0A
+
+/* insmod parameters */
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the device at the given address. */
+static u16 force_addr;
+module_param_hw(force_addr, ushort, ioport, 0);
+MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
+
+static struct pci_driver sis5595_driver;
+static unsigned short sis5595_base;
+static struct pci_dev *sis5595_pdev;
+
+static u8 sis5595_read(u8 reg)
+{
+ outb(reg, sis5595_base + SMB_INDEX);
+ return inb(sis5595_base + SMB_DAT);
+}
+
+static void sis5595_write(u8 reg, u8 data)
+{
+ outb(reg, sis5595_base + SMB_INDEX);
+ outb(data, sis5595_base + SMB_DAT);
+}
+
+static int sis5595_setup(struct pci_dev *SIS5595_dev)
+{
+ u16 a;
+ u8 val;
+ int *i;
+ int retval;
+
+ /* Look for imposters */
+ for (i = blacklist; *i != 0; i++) {
+ struct pci_dev *dev;
+ dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
+ if (dev) {
+ dev_err(&SIS5595_dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+ pci_dev_put(dev);
+ return -ENODEV;
+ }
+ }
+
+ /* Determine the address of the SMBus areas */
+ pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
+ if (sis5595_base == 0 && force_addr == 0) {
+ dev_err(&SIS5595_dev->dev, "ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+
+ if (force_addr)
+ sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
+ dev_dbg(&SIS5595_dev->dev, "ACPI Base address: %04x\n", sis5595_base);
+
+ /* NB: We grab just the two SMBus registers here, but this may still
+ * interfere with ACPI :-( */
+ retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
+ sis5595_driver.name);
+ if (retval)
+ return retval;
+
+ if (!request_region(sis5595_base + SMB_INDEX, 2,
+ sis5595_driver.name)) {
+ dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
+ sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1);
+ return -ENODEV;
+ }
+
+ if (force_addr) {
+ dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base);
+ if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
+ /* doesn't work for some chips! */
+ dev_err(&SIS5595_dev->dev, "force address failed - not supported?\n");
+ goto error;
+ }
+ }
+
+ if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if ((val & 0x80) == 0) {
+ dev_info(&SIS5595_dev->dev, "enabling ACPI\n");
+ if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
+ != PCIBIOS_SUCCESSFUL)
+ goto error;
+ if ((val & 0x80) == 0) {
+ /* doesn't work for some chips? */
+ dev_err(&SIS5595_dev->dev, "ACPI enable failed - not supported?\n");
+ goto error;
+ }
+ }
+
+ /* Everything is happy */
+ return 0;
+
+error:
+ release_region(sis5595_base + SMB_INDEX, 2);
+ return -ENODEV;
+}
+
+static int sis5595_transaction(struct i2c_adapter *adap)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+ if (temp != 0x00) {
+ dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp);
+ sis5595_write(SMB_STS_LO, temp & 0xff);
+ sis5595_write(SMB_STS_HI, temp >> 8);
+ if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
+ dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&adap->dev, "Successful!\n");
+ }
+ }
+
+ /* start the transaction by setting bit 4 */
+ sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10);
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = sis5595_read(SMB_STS_LO);
+ } while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+
+ if (temp & 0x10) {
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ result = -ENXIO;
+ }
+
+ if (temp & 0x20) {
+ dev_err(&adap->dev, "Bus collision! SMBus may be locked until "
+ "next hard reset (or not...)\n");
+ /* Clock stops and slave is stuck in mid-transmission */
+ result = -EIO;
+ }
+
+ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+ if (temp != 0x00) {
+ sis5595_write(SMB_STS_LO, temp & 0xff);
+ sis5595_write(SMB_STS_HI, temp >> 8);
+ }
+
+ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+ if (temp != 0x00)
+ dev_dbg(&adap->dev, "Failed reset at end of transaction (%02x)\n", temp);
+
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ size = SIS5595_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ if (read_write == I2C_SMBUS_WRITE)
+ sis5595_write(SMB_CMD, command);
+ size = SIS5595_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis5595_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE)
+ sis5595_write(SMB_BYTE, data->byte);
+ size = SIS5595_BYTE_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ case I2C_SMBUS_WORD_DATA:
+ sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis5595_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ sis5595_write(SMB_BYTE, data->word & 0xff);
+ sis5595_write(SMB_BYTE + 1,
+ (data->word & 0xff00) >> 8);
+ }
+ size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
+ break;
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
+
+ status = sis5595_transaction(adap);
+ if (status)
+ return status;
+
+ if ((size != SIS5595_PROC_CALL) &&
+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
+ return 0;
+
+
+ switch (size) {
+ case SIS5595_BYTE:
+ case SIS5595_BYTE_DATA:
+ data->byte = sis5595_read(SMB_BYTE);
+ break;
+ case SIS5595_WORD_DATA:
+ case SIS5595_PROC_CALL:
+ data->word = sis5595_read(SMB_BYTE) + (sis5595_read(SMB_BYTE + 1) << 8);
+ break;
+ }
+ return 0;
+}
+
+static u32 sis5595_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis5595_access,
+ .functionality = sis5595_func,
+};
+
+static struct i2c_adapter sis5595_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id sis5595_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis5595_ids);
+
+static int sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int err;
+
+ if (sis5595_setup(dev)) {
+ dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ sis5595_adapter.dev.parent = &dev->dev;
+
+ snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name),
+ "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX);
+ err = i2c_add_adapter(&sis5595_adapter);
+ if (err) {
+ release_region(sis5595_base + SMB_INDEX, 2);
+ return err;
+ }
+
+ /* Always return failure here. This is to allow other drivers to bind
+ * to this pci device. We don't really want to have control over the
+ * pci device, we only wanted to read as few register values from it.
+ */
+ sis5595_pdev = pci_dev_get(dev);
+ return -ENODEV;
+}
+
+static struct pci_driver sis5595_driver = {
+ .name = "sis5595_smbus",
+ .id_table = sis5595_ids,
+ .probe = sis5595_probe,
+};
+
+static int __init i2c_sis5595_init(void)
+{
+ return pci_register_driver(&sis5595_driver);
+}
+
+static void __exit i2c_sis5595_exit(void)
+{
+ pci_unregister_driver(&sis5595_driver);
+ if (sis5595_pdev) {
+ i2c_del_adapter(&sis5595_adapter);
+ release_region(sis5595_base + SMB_INDEX, 2);
+ pci_dev_put(sis5595_pdev);
+ sis5595_pdev = NULL;
+ }
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("SIS5595 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_sis5595_init);
+module_exit(i2c_sis5595_exit);
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
new file mode 100644
index 000000000..1e6805b5c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -0,0 +1,557 @@
+/*
+ Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ Status: beta
+
+ Supports:
+ SIS 630
+ SIS 730
+ SIS 964
+
+ Notable differences between chips:
+ +------------------------+--------------------+-------------------+
+ | | SIS630/730 | SIS964 |
+ +------------------------+--------------------+-------------------+
+ | Clock | 14kHz/56kHz | 55.56kHz/27.78kHz |
+ | SMBus registers offset | 0x80 | 0xE0 |
+ | SMB_CNT | Bit 1 = Slave Busy | Bit 1 = Bus probe |
+ | (not used yet) | Bit 3 is reserved | Bit 3 = Last byte |
+ | SMB_PCOUNT | Offset + 0x06 | Offset + 0x14 |
+ | SMB_COUNT | 4:0 bits | 5:0 bits |
+ +------------------------+--------------------+-------------------+
+ (Other differences don't affect the functions provided by the driver)
+
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* SIS964 id is defined here as we are the only file using it */
+#define PCI_DEVICE_ID_SI_964 0x0964
+
+/* SIS630/730/964 SMBus registers */
+#define SMB_STS 0x00 /* status */
+#define SMB_CNT 0x02 /* control */
+#define SMBHOST_CNT 0x03 /* host control */
+#define SMB_ADDR 0x04 /* address */
+#define SMB_CMD 0x05 /* command */
+#define SMB_COUNT 0x07 /* byte count */
+#define SMB_BYTE 0x08 /* ~0x8F data byte field */
+
+/* SMB_STS register */
+#define BYTE_DONE_STS 0x10 /* Byte Done Status / Block Array */
+#define SMBCOL_STS 0x04 /* Collision */
+#define SMBERR_STS 0x02 /* Device error */
+
+/* SMB_CNT register */
+#define MSTO_EN 0x40 /* Host Master Timeout Enable */
+#define SMBCLK_SEL 0x20 /* Host master clock selection */
+#define SMB_PROBE 0x02 /* Bus Probe/Slave busy */
+#define SMB_HOSTBUSY 0x01 /* Host Busy */
+
+/* SMBHOST_CNT register */
+#define SMB_KILL 0x20 /* Kill */
+#define SMB_START 0x10 /* Start */
+
+/* register count for request_region
+ * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964
+ */
+#define SIS630_SMB_IOREGION 20
+
+/* PCI address constants */
+/* acpi base address register */
+#define SIS630_ACPI_BASE_REG 0x74
+/* bios control register */
+#define SIS630_BIOS_CTL_REG 0x40
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SIS630 constants */
+#define SIS630_QUICK 0x00
+#define SIS630_BYTE 0x01
+#define SIS630_BYTE_DATA 0x02
+#define SIS630_WORD_DATA 0x03
+#define SIS630_PCALL 0x04
+#define SIS630_BLOCK_DATA 0x05
+
+static struct pci_driver sis630_driver;
+
+/* insmod parameters */
+static bool high_clock;
+static bool force;
+module_param(high_clock, bool, 0);
+MODULE_PARM_DESC(high_clock,
+ "Set Host Master Clock to 56KHz (default 14KHz) (SIS630/730 only).");
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
+
+/* SMBus base adress */
+static unsigned short smbus_base;
+
+/* supported chips */
+static int supported[] = {
+ PCI_DEVICE_ID_SI_630,
+ PCI_DEVICE_ID_SI_730,
+ PCI_DEVICE_ID_SI_760,
+ 0 /* terminates the list */
+};
+
+static inline u8 sis630_read(u8 reg)
+{
+ return inb(smbus_base + reg);
+}
+
+static inline void sis630_write(u8 reg, u8 data)
+{
+ outb(data, smbus_base + reg);
+}
+
+static int sis630_transaction_start(struct i2c_adapter *adap, int size,
+ u8 *oldclock)
+{
+ int temp;
+
+ /* Make sure the SMBus host is ready to start transmitting. */
+ temp = sis630_read(SMB_CNT);
+ if ((temp & (SMB_PROBE | SMB_HOSTBUSY)) != 0x00) {
+ dev_dbg(&adap->dev, "SMBus busy (%02x). Resetting...\n", temp);
+ /* kill smbus transaction */
+ sis630_write(SMBHOST_CNT, SMB_KILL);
+
+ temp = sis630_read(SMB_CNT);
+ if (temp & (SMB_PROBE | SMB_HOSTBUSY)) {
+ dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&adap->dev, "Successful!\n");
+ }
+ }
+
+ /* save old clock, so we can prevent machine for hung */
+ *oldclock = sis630_read(SMB_CNT);
+
+ dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock);
+
+ /* disable timeout interrupt,
+ * set Host Master Clock to 56KHz if requested */
+ if (high_clock)
+ sis630_write(SMB_CNT, SMBCLK_SEL);
+ else
+ sis630_write(SMB_CNT, (*oldclock & ~MSTO_EN));
+
+ /* clear all sticky bits */
+ temp = sis630_read(SMB_STS);
+ sis630_write(SMB_STS, temp & 0x1e);
+
+ /* start the transaction by setting bit 4 and size */
+ sis630_write(SMBHOST_CNT, SMB_START | (size & 0x07));
+
+ return 0;
+}
+
+static int sis630_transaction_wait(struct i2c_adapter *adap, int size)
+{
+ int temp, result = 0, timeout = 0;
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = sis630_read(SMB_STS);
+ /* check if block transmitted */
+ if (size == SIS630_BLOCK_DATA && (temp & BYTE_DONE_STS))
+ break;
+ } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ result = -ETIMEDOUT;
+ }
+
+ if (temp & SMBERR_STS) {
+ dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+ result = -ENXIO;
+ }
+
+ if (temp & SMBCOL_STS) {
+ dev_err(&adap->dev, "Bus collision!\n");
+ result = -EAGAIN;
+ }
+
+ return result;
+}
+
+static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock)
+{
+ /* clear all status "sticky" bits */
+ sis630_write(SMB_STS, 0xFF);
+
+ dev_dbg(&adap->dev,
+ "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT));
+
+ /*
+ * restore old Host Master Clock if high_clock is set
+ * and oldclock was not 56KHz
+ */
+ if (high_clock && !(oldclock & SMBCLK_SEL))
+ sis630_write(SMB_CNT, sis630_read(SMB_CNT) & ~SMBCLK_SEL);
+
+ dev_dbg(&adap->dev,
+ "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT));
+}
+
+static int sis630_transaction(struct i2c_adapter *adap, int size)
+{
+ int result = 0;
+ u8 oldclock = 0;
+
+ result = sis630_transaction_start(adap, size, &oldclock);
+ if (!result) {
+ result = sis630_transaction_wait(adap, size);
+ sis630_transaction_end(adap, oldclock);
+ }
+
+ return result;
+}
+
+static int sis630_block_data(struct i2c_adapter *adap,
+ union i2c_smbus_data *data, int read_write)
+{
+ int i, len = 0, rc = 0;
+ u8 oldclock = 0;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len < 0)
+ len = 0;
+ else if (len > 32)
+ len = 32;
+ sis630_write(SMB_COUNT, len);
+ for (i = 1; i <= len; i++) {
+ dev_dbg(&adap->dev,
+ "set data 0x%02x\n", data->block[i]);
+ /* set data */
+ sis630_write(SMB_BYTE + (i - 1) % 8, data->block[i]);
+ if (i == 8 || (len < 8 && i == len)) {
+ dev_dbg(&adap->dev,
+ "start trans len=%d i=%d\n", len, i);
+ /* first transaction */
+ rc = sis630_transaction_start(adap,
+ SIS630_BLOCK_DATA, &oldclock);
+ if (rc)
+ return rc;
+ } else if ((i - 1) % 8 == 7 || i == len) {
+ dev_dbg(&adap->dev,
+ "trans_wait len=%d i=%d\n", len, i);
+ if (i > 8) {
+ dev_dbg(&adap->dev,
+ "clear smbary_sts"
+ " len=%d i=%d\n", len, i);
+ /*
+ If this is not first transaction,
+ we must clear sticky bit.
+ clear SMBARY_STS
+ */
+ sis630_write(SMB_STS, BYTE_DONE_STS);
+ }
+ rc = sis630_transaction_wait(adap,
+ SIS630_BLOCK_DATA);
+ if (rc) {
+ dev_dbg(&adap->dev,
+ "trans_wait failed\n");
+ break;
+ }
+ }
+ }
+ } else {
+ /* read request */
+ data->block[0] = len = 0;
+ rc = sis630_transaction_start(adap,
+ SIS630_BLOCK_DATA, &oldclock);
+ if (rc)
+ return rc;
+ do {
+ rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA);
+ if (rc) {
+ dev_dbg(&adap->dev, "trans_wait failed\n");
+ break;
+ }
+ /* if this first transaction then read byte count */
+ if (len == 0)
+ data->block[0] = sis630_read(SMB_COUNT);
+
+ /* just to be sure */
+ if (data->block[0] > 32)
+ data->block[0] = 32;
+
+ dev_dbg(&adap->dev,
+ "block data read len=0x%x\n", data->block[0]);
+
+ for (i = 0; i < 8 && len < data->block[0]; i++, len++) {
+ dev_dbg(&adap->dev,
+ "read i=%d len=%d\n", i, len);
+ data->block[len + 1] = sis630_read(SMB_BYTE +
+ i);
+ }
+
+ dev_dbg(&adap->dev,
+ "clear smbary_sts len=%d i=%d\n", len, i);
+
+ /* clear SMBARY_STS */
+ sis630_write(SMB_STS, BYTE_DONE_STS);
+ } while (len < data->block[0]);
+ }
+
+ sis630_transaction_end(adap, oldclock);
+
+ return rc;
+}
+
+/* Return negative errno on error. */
+static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ sis630_write(SMB_ADDR,
+ ((addr & 0x7f) << 1) | (read_write & 0x01));
+ size = SIS630_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ sis630_write(SMB_ADDR,
+ ((addr & 0x7f) << 1) | (read_write & 0x01));
+ if (read_write == I2C_SMBUS_WRITE)
+ sis630_write(SMB_CMD, command);
+ size = SIS630_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ sis630_write(SMB_ADDR,
+ ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis630_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE)
+ sis630_write(SMB_BYTE, data->byte);
+ size = SIS630_BYTE_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ case I2C_SMBUS_WORD_DATA:
+ sis630_write(SMB_ADDR,
+ ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis630_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ sis630_write(SMB_BYTE, data->word & 0xff);
+ sis630_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
+ }
+ size = (size == I2C_SMBUS_PROC_CALL ?
+ SIS630_PCALL : SIS630_WORD_DATA);
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ sis630_write(SMB_ADDR,
+ ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis630_write(SMB_CMD, command);
+ size = SIS630_BLOCK_DATA;
+ return sis630_block_data(adap, data, read_write);
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ status = sis630_transaction(adap, size);
+ if (status)
+ return status;
+
+ if ((size != SIS630_PCALL) &&
+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
+ return 0;
+ }
+
+ switch (size) {
+ case SIS630_BYTE:
+ case SIS630_BYTE_DATA:
+ data->byte = sis630_read(SMB_BYTE);
+ break;
+ case SIS630_PCALL:
+ case SIS630_WORD_DATA:
+ data->word = sis630_read(SMB_BYTE) +
+ (sis630_read(SMB_BYTE + 1) << 8);
+ break;
+ }
+
+ return 0;
+}
+
+static u32 sis630_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int sis630_setup(struct pci_dev *sis630_dev)
+{
+ unsigned char b;
+ struct pci_dev *dummy = NULL;
+ int retval, i;
+ /* acpi base address */
+ unsigned short acpi_base;
+
+ /* check for supported SiS devices */
+ for (i = 0; supported[i] > 0; i++) {
+ dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy);
+ if (dummy)
+ break; /* found */
+ }
+
+ if (dummy) {
+ pci_dev_put(dummy);
+ } else if (force) {
+ dev_err(&sis630_dev->dev,
+ "WARNING: Can't detect SIS630 compatible device, but "
+ "loading because of force option enabled\n");
+ } else {
+ return -ENODEV;
+ }
+
+ /*
+ Enable ACPI first , so we can accsess reg 74-75
+ in acpi io space and read acpi base addr
+ */
+ if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, &b)) {
+ dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+ /* if ACPI already enabled , do nothing */
+ if (!(b & 0x80) &&
+ pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
+ dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* Determine the ACPI base address */
+ if (pci_read_config_word(sis630_dev,
+ SIS630_ACPI_BASE_REG, &acpi_base)) {
+ dev_err(&sis630_dev->dev,
+ "Error: Can't determine ACPI base address\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04hx\n", acpi_base);
+
+ if (supported[i] == PCI_DEVICE_ID_SI_760)
+ smbus_base = acpi_base + 0xE0;
+ else
+ smbus_base = acpi_base + 0x80;
+
+ dev_dbg(&sis630_dev->dev, "SMBus base at 0x%04hx\n", smbus_base);
+
+ retval = acpi_check_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
+ sis630_driver.name);
+ if (retval)
+ goto exit;
+
+ /* Everything is happy, let's grab the memory and set things up. */
+ if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
+ sis630_driver.name)) {
+ dev_err(&sis630_dev->dev,
+ "I/O Region 0x%04hx-0x%04hx for SMBus already in use.\n",
+ smbus_base + SMB_STS,
+ smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ retval = 0;
+
+exit:
+ if (retval)
+ smbus_base = 0;
+ return retval;
+}
+
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis630_access,
+ .functionality = sis630_func,
+};
+
+static struct i2c_adapter sis630_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+ .retries = 3
+};
+
+static const struct pci_device_id sis630_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, sis630_ids);
+
+static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if (sis630_setup(dev)) {
+ dev_err(&dev->dev,
+ "SIS630 compatible bus not detected, "
+ "module not inserted.\n");
+ return -ENODEV;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ sis630_adapter.dev.parent = &dev->dev;
+
+ snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
+ "SMBus SIS630 adapter at %04hx", smbus_base + SMB_STS);
+
+ return i2c_add_adapter(&sis630_adapter);
+}
+
+static void sis630_remove(struct pci_dev *dev)
+{
+ if (smbus_base) {
+ i2c_del_adapter(&sis630_adapter);
+ release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION);
+ smbus_base = 0;
+ }
+}
+
+
+static struct pci_driver sis630_driver = {
+ .name = "sis630_smbus",
+ .id_table = sis630_ids,
+ .probe = sis630_probe,
+ .remove = sis630_remove,
+};
+
+module_pci_driver(sis630_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
+MODULE_DESCRIPTION("SIS630 SMBus driver");
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
new file mode 100644
index 000000000..44b904426
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -0,0 +1,326 @@
+/*
+ Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ This module must be considered BETA unless and until
+ the chipset manufacturer releases a datasheet.
+ The register definitions are based on the SiS630.
+
+ This module relies on quirk_sis_96x_smbus (drivers/pci/quirks.c)
+ for just about every machine for which users have reported.
+ If this module isn't detecting your 96x south bridge, have a
+ look there.
+
+ We assume there can only be one SiS96x with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* base address register in PCI config space */
+#define SIS96x_BAR 0x04
+
+/* SiS96x SMBus registers */
+#define SMB_STS 0x00
+#define SMB_EN 0x01
+#define SMB_CNT 0x02
+#define SMB_HOST_CNT 0x03
+#define SMB_ADDR 0x04
+#define SMB_CMD 0x05
+#define SMB_PCOUNT 0x06
+#define SMB_COUNT 0x07
+#define SMB_BYTE 0x08
+#define SMB_DEV_ADDR 0x10
+#define SMB_DB0 0x11
+#define SMB_DB1 0x12
+#define SMB_SAA 0x13
+
+/* register count for request_region */
+#define SMB_IOSIZE 0x20
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SiS96x SMBus constants */
+#define SIS96x_QUICK 0x00
+#define SIS96x_BYTE 0x01
+#define SIS96x_BYTE_DATA 0x02
+#define SIS96x_WORD_DATA 0x03
+#define SIS96x_PROC_CALL 0x04
+#define SIS96x_BLOCK_DATA 0x05
+
+static struct pci_driver sis96x_driver;
+static struct i2c_adapter sis96x_adapter;
+static u16 sis96x_smbus_base;
+
+static inline u8 sis96x_read(u8 reg)
+{
+ return inb(sis96x_smbus_base + reg) ;
+}
+
+static inline void sis96x_write(u8 reg, u8 data)
+{
+ outb(data, sis96x_smbus_base + reg) ;
+}
+
+/* Execute a SMBus transaction.
+ int size is from SIS96x_QUICK to SIS96x_BLOCK_DATA
+ */
+static int sis96x_transaction(int size)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ dev_dbg(&sis96x_adapter.dev, "SMBus transaction %d\n", size);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+
+ dev_dbg(&sis96x_adapter.dev, "SMBus busy (0x%02x). "
+ "Resetting...\n", temp);
+
+ /* kill the transaction */
+ sis96x_write(SMB_HOST_CNT, 0x20);
+
+ /* check it again */
+ if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+ dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
+ return -EBUSY;
+ } else {
+ dev_dbg(&sis96x_adapter.dev, "Successful\n");
+ }
+ }
+
+ /* Turn off timeout interrupts, set fast host clock */
+ sis96x_write(SMB_CNT, 0x20);
+
+ /* clear all (sticky) status flags */
+ temp = sis96x_read(SMB_STS);
+ sis96x_write(SMB_STS, temp & 0x1e);
+
+ /* start the transaction by setting bit 4 and size bits */
+ sis96x_write(SMB_HOST_CNT, 0x10 | (size & 0x07));
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ msleep(1);
+ temp = sis96x_read(SMB_STS);
+ } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout > MAX_TIMEOUT) {
+ dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
+ result = -ETIMEDOUT;
+ }
+
+ /* device error - probably missing ACK */
+ if (temp & 0x02) {
+ dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
+ result = -ENXIO;
+ }
+
+ /* bus collision */
+ if (temp & 0x04) {
+ dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
+ result = -EIO;
+ }
+
+ /* Finish up by resetting the bus */
+ sis96x_write(SMB_STS, temp);
+ if ((temp = sis96x_read(SMB_STS))) {
+ dev_dbg(&sis96x_adapter.dev, "Failed reset at "
+ "end of transaction! (0x%02x)\n", temp);
+ }
+
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 sis96x_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ size = SIS96x_QUICK;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ if (read_write == I2C_SMBUS_WRITE)
+ sis96x_write(SMB_CMD, command);
+ size = SIS96x_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis96x_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE)
+ sis96x_write(SMB_BYTE, data->byte);
+ size = SIS96x_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_PROC_CALL:
+ case I2C_SMBUS_WORD_DATA:
+ sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+ sis96x_write(SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ sis96x_write(SMB_BYTE, data->word & 0xff);
+ sis96x_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
+ }
+ size = (size == I2C_SMBUS_PROC_CALL ?
+ SIS96x_PROC_CALL : SIS96x_WORD_DATA);
+ break;
+
+ default:
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ status = sis96x_transaction(size);
+ if (status)
+ return status;
+
+ if ((size != SIS96x_PROC_CALL) &&
+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS96x_QUICK)))
+ return 0;
+
+ switch (size) {
+ case SIS96x_BYTE:
+ case SIS96x_BYTE_DATA:
+ data->byte = sis96x_read(SMB_BYTE);
+ break;
+
+ case SIS96x_WORD_DATA:
+ case SIS96x_PROC_CALL:
+ data->word = sis96x_read(SMB_BYTE) +
+ (sis96x_read(SMB_BYTE + 1) << 8);
+ break;
+ }
+ return 0;
+}
+
+static u32 sis96x_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = sis96x_access,
+ .functionality = sis96x_func,
+};
+
+static struct i2c_adapter sis96x_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static const struct pci_device_id sis96x_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis96x_ids);
+
+static int sis96x_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ u16 ww = 0;
+ int retval;
+
+ if (sis96x_smbus_base) {
+ dev_err(&dev->dev, "Only one device supported.\n");
+ return -EBUSY;
+ }
+
+ pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
+ if (PCI_CLASS_SERIAL_SMBUS != ww) {
+ dev_err(&dev->dev, "Unsupported device class 0x%04x!\n", ww);
+ return -ENODEV;
+ }
+
+ sis96x_smbus_base = pci_resource_start(dev, SIS96x_BAR);
+ if (!sis96x_smbus_base) {
+ dev_err(&dev->dev, "SiS96x SMBus base address "
+ "not initialized!\n");
+ return -EINVAL;
+ }
+ dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
+ sis96x_smbus_base);
+
+ retval = acpi_check_resource_conflict(&dev->resource[SIS96x_BAR]);
+ if (retval)
+ return -ENODEV;
+
+ /* Everything is happy, let's grab the memory and set things up. */
+ if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
+ sis96x_driver.name)) {
+ dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x "
+ "already in use!\n", sis96x_smbus_base,
+ sis96x_smbus_base + SMB_IOSIZE - 1);
+
+ sis96x_smbus_base = 0;
+ return -EINVAL;
+ }
+
+ /* set up the sysfs linkage to our parent device */
+ sis96x_adapter.dev.parent = &dev->dev;
+
+ snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name),
+ "SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
+
+ if ((retval = i2c_add_adapter(&sis96x_adapter))) {
+ dev_err(&dev->dev, "Couldn't register adapter!\n");
+ release_region(sis96x_smbus_base, SMB_IOSIZE);
+ sis96x_smbus_base = 0;
+ }
+
+ return retval;
+}
+
+static void sis96x_remove(struct pci_dev *dev)
+{
+ if (sis96x_smbus_base) {
+ i2c_del_adapter(&sis96x_adapter);
+ release_region(sis96x_smbus_base, SMB_IOSIZE);
+ sis96x_smbus_base = 0;
+ }
+}
+
+static struct pci_driver sis96x_driver = {
+ .name = "sis96x_smbus",
+ .id_table = sis96x_ids,
+ .probe = sis96x_probe,
+ .remove = sis96x_remove,
+};
+
+module_pci_driver(sis96x_driver);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("SiS96x SMBus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c
new file mode 100644
index 000000000..bb1478e78
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sprd.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#define I2C_CTL 0x00
+#define I2C_ADDR_CFG 0x04
+#define I2C_COUNT 0x08
+#define I2C_RX 0x0c
+#define I2C_TX 0x10
+#define I2C_STATUS 0x14
+#define I2C_HSMODE_CFG 0x18
+#define I2C_VERSION 0x1c
+#define ADDR_DVD0 0x20
+#define ADDR_DVD1 0x24
+#define ADDR_STA0_DVD 0x28
+#define ADDR_RST 0x2c
+
+/* I2C_CTL */
+#define STP_EN BIT(20)
+#define FIFO_AF_LVL_MASK GENMASK(19, 16)
+#define FIFO_AF_LVL 16
+#define FIFO_AE_LVL_MASK GENMASK(15, 12)
+#define FIFO_AE_LVL 12
+#define I2C_DMA_EN BIT(11)
+#define FULL_INTEN BIT(10)
+#define EMPTY_INTEN BIT(9)
+#define I2C_DVD_OPT BIT(8)
+#define I2C_OUT_OPT BIT(7)
+#define I2C_TRIM_OPT BIT(6)
+#define I2C_HS_MODE BIT(4)
+#define I2C_MODE BIT(3)
+#define I2C_EN BIT(2)
+#define I2C_INT_EN BIT(1)
+#define I2C_START BIT(0)
+
+/* I2C_STATUS */
+#define SDA_IN BIT(21)
+#define SCL_IN BIT(20)
+#define FIFO_FULL BIT(4)
+#define FIFO_EMPTY BIT(3)
+#define I2C_INT BIT(2)
+#define I2C_RX_ACK BIT(1)
+#define I2C_BUSY BIT(0)
+
+/* ADDR_RST */
+#define I2C_RST BIT(0)
+
+#define I2C_FIFO_DEEP 12
+#define I2C_FIFO_FULL_THLD 15
+#define I2C_FIFO_EMPTY_THLD 4
+#define I2C_DATA_STEP 8
+#define I2C_ADDR_DVD0_CALC(high, low) \
+ ((((high) & GENMASK(15, 0)) << 16) | ((low) & GENMASK(15, 0)))
+#define I2C_ADDR_DVD1_CALC(high, low) \
+ (((high) & GENMASK(31, 16)) | (((low) & GENMASK(31, 16)) >> 16))
+
+/* timeout (ms) for pm runtime autosuspend */
+#define SPRD_I2C_PM_TIMEOUT 1000
+/* timeout (ms) for transfer message */
+#define I2C_XFER_TIMEOUT 1000
+
+/* SPRD i2c data structure */
+struct sprd_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_msg *msg;
+ struct clk *clk;
+ u32 src_clk;
+ u32 bus_freq;
+ struct completion complete;
+ u8 *buf;
+ u32 count;
+ int irq;
+ int err;
+ bool is_suspended;
+};
+
+static void sprd_i2c_set_count(struct sprd_i2c *i2c_dev, u32 count)
+{
+ writel(count, i2c_dev->base + I2C_COUNT);
+}
+
+static void sprd_i2c_send_stop(struct sprd_i2c *i2c_dev, int stop)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ if (stop)
+ writel(tmp & ~STP_EN, i2c_dev->base + I2C_CTL);
+ else
+ writel(tmp | STP_EN, i2c_dev->base + I2C_CTL);
+}
+
+static void sprd_i2c_clear_start(struct sprd_i2c *i2c_dev)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ writel(tmp & ~I2C_START, i2c_dev->base + I2C_CTL);
+}
+
+static void sprd_i2c_clear_ack(struct sprd_i2c *i2c_dev)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_STATUS);
+
+ writel(tmp & ~I2C_RX_ACK, i2c_dev->base + I2C_STATUS);
+}
+
+static void sprd_i2c_clear_irq(struct sprd_i2c *i2c_dev)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_STATUS);
+
+ writel(tmp & ~I2C_INT, i2c_dev->base + I2C_STATUS);
+}
+
+static void sprd_i2c_reset_fifo(struct sprd_i2c *i2c_dev)
+{
+ writel(I2C_RST, i2c_dev->base + ADDR_RST);
+}
+
+static void sprd_i2c_set_devaddr(struct sprd_i2c *i2c_dev, struct i2c_msg *m)
+{
+ writel(m->addr << 1, i2c_dev->base + I2C_ADDR_CFG);
+}
+
+static void sprd_i2c_write_bytes(struct sprd_i2c *i2c_dev, u8 *buf, u32 len)
+{
+ u32 i;
+
+ for (i = 0; i < len; i++)
+ writeb(buf[i], i2c_dev->base + I2C_TX);
+}
+
+static void sprd_i2c_read_bytes(struct sprd_i2c *i2c_dev, u8 *buf, u32 len)
+{
+ u32 i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = readb(i2c_dev->base + I2C_RX);
+}
+
+static void sprd_i2c_set_full_thld(struct sprd_i2c *i2c_dev, u32 full_thld)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ tmp &= ~FIFO_AF_LVL_MASK;
+ tmp |= full_thld << FIFO_AF_LVL;
+ writel(tmp, i2c_dev->base + I2C_CTL);
+};
+
+static void sprd_i2c_set_empty_thld(struct sprd_i2c *i2c_dev, u32 empty_thld)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ tmp &= ~FIFO_AE_LVL_MASK;
+ tmp |= empty_thld << FIFO_AE_LVL;
+ writel(tmp, i2c_dev->base + I2C_CTL);
+};
+
+static void sprd_i2c_set_fifo_full_int(struct sprd_i2c *i2c_dev, int enable)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ if (enable)
+ tmp |= FULL_INTEN;
+ else
+ tmp &= ~FULL_INTEN;
+
+ writel(tmp, i2c_dev->base + I2C_CTL);
+};
+
+static void sprd_i2c_set_fifo_empty_int(struct sprd_i2c *i2c_dev, int enable)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ if (enable)
+ tmp |= EMPTY_INTEN;
+ else
+ tmp &= ~EMPTY_INTEN;
+
+ writel(tmp, i2c_dev->base + I2C_CTL);
+};
+
+static void sprd_i2c_opt_start(struct sprd_i2c *i2c_dev)
+{
+ u32 tmp = readl(i2c_dev->base + I2C_CTL);
+
+ writel(tmp | I2C_START, i2c_dev->base + I2C_CTL);
+}
+
+static void sprd_i2c_opt_mode(struct sprd_i2c *i2c_dev, int rw)
+{
+ u32 cmd = readl(i2c_dev->base + I2C_CTL) & ~I2C_MODE;
+
+ writel(cmd | rw << 3, i2c_dev->base + I2C_CTL);
+}
+
+static void sprd_i2c_data_transfer(struct sprd_i2c *i2c_dev)
+{
+ u32 i2c_count = i2c_dev->count;
+ u32 need_tran = i2c_count <= I2C_FIFO_DEEP ? i2c_count : I2C_FIFO_DEEP;
+ struct i2c_msg *msg = i2c_dev->msg;
+
+ if (msg->flags & I2C_M_RD) {
+ sprd_i2c_read_bytes(i2c_dev, i2c_dev->buf, I2C_FIFO_FULL_THLD);
+ i2c_dev->count -= I2C_FIFO_FULL_THLD;
+ i2c_dev->buf += I2C_FIFO_FULL_THLD;
+
+ /*
+ * If the read data count is larger than rx fifo full threshold,
+ * we should enable the rx fifo full interrupt to read data
+ * again.
+ */
+ if (i2c_dev->count >= I2C_FIFO_FULL_THLD)
+ sprd_i2c_set_fifo_full_int(i2c_dev, 1);
+ } else {
+ sprd_i2c_write_bytes(i2c_dev, i2c_dev->buf, need_tran);
+ i2c_dev->buf += need_tran;
+ i2c_dev->count -= need_tran;
+
+ /*
+ * If the write data count is arger than tx fifo depth which
+ * means we can not write all data in one time, then we should
+ * enable the tx fifo empty interrupt to write again.
+ */
+ if (i2c_count > I2C_FIFO_DEEP)
+ sprd_i2c_set_fifo_empty_int(i2c_dev, 1);
+ }
+}
+
+static int sprd_i2c_handle_msg(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msg, bool is_last_msg)
+{
+ struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
+ unsigned long time_left;
+
+ i2c_dev->msg = msg;
+ i2c_dev->buf = msg->buf;
+ i2c_dev->count = msg->len;
+
+ reinit_completion(&i2c_dev->complete);
+ sprd_i2c_reset_fifo(i2c_dev);
+ sprd_i2c_set_devaddr(i2c_dev, msg);
+ sprd_i2c_set_count(i2c_dev, msg->len);
+
+ if (msg->flags & I2C_M_RD) {
+ sprd_i2c_opt_mode(i2c_dev, 1);
+ sprd_i2c_send_stop(i2c_dev, 1);
+ } else {
+ sprd_i2c_opt_mode(i2c_dev, 0);
+ sprd_i2c_send_stop(i2c_dev, !!is_last_msg);
+ }
+
+ /*
+ * We should enable rx fifo full interrupt to get data when receiving
+ * full data.
+ */
+ if (msg->flags & I2C_M_RD)
+ sprd_i2c_set_fifo_full_int(i2c_dev, 1);
+ else
+ sprd_i2c_data_transfer(i2c_dev);
+
+ sprd_i2c_opt_start(i2c_dev);
+
+ time_left = wait_for_completion_timeout(&i2c_dev->complete,
+ msecs_to_jiffies(I2C_XFER_TIMEOUT));
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ return i2c_dev->err;
+}
+
+static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
+ int im, ret;
+
+ if (i2c_dev->is_suspended)
+ return -EBUSY;
+
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
+ return ret;
+
+ for (im = 0; im < num - 1; im++) {
+ ret = sprd_i2c_handle_msg(i2c_adap, &msgs[im], 0);
+ if (ret)
+ goto err_msg;
+ }
+
+ ret = sprd_i2c_handle_msg(i2c_adap, &msgs[im++], 1);
+
+err_msg:
+ pm_runtime_mark_last_busy(i2c_dev->dev);
+ pm_runtime_put_autosuspend(i2c_dev->dev);
+
+ return ret < 0 ? ret : im;
+}
+
+static u32 sprd_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm sprd_i2c_algo = {
+ .master_xfer = sprd_i2c_master_xfer,
+ .functionality = sprd_i2c_func,
+};
+
+static void sprd_i2c_set_clk(struct sprd_i2c *i2c_dev, u32 freq)
+{
+ u32 apb_clk = i2c_dev->src_clk;
+ /*
+ * From I2C databook, the prescale calculation formula:
+ * prescale = freq_i2c / (4 * freq_scl) - 1;
+ */
+ u32 i2c_dvd = apb_clk / (4 * freq) - 1;
+ /*
+ * From I2C databook, the high period of SCL clock is recommended as
+ * 40% (2/5), and the low period of SCL clock is recommended as 60%
+ * (3/5), then the formula should be:
+ * high = (prescale * 2 * 2) / 5
+ * low = (prescale * 2 * 3) / 5
+ */
+ u32 high = ((i2c_dvd << 1) * 2) / 5;
+ u32 low = ((i2c_dvd << 1) * 3) / 5;
+ u32 div0 = I2C_ADDR_DVD0_CALC(high, low);
+ u32 div1 = I2C_ADDR_DVD1_CALC(high, low);
+
+ writel(div0, i2c_dev->base + ADDR_DVD0);
+ writel(div1, i2c_dev->base + ADDR_DVD1);
+
+ /* Start hold timing = hold time(us) * source clock */
+ if (freq == 400000)
+ writel((6 * apb_clk) / 10000000, i2c_dev->base + ADDR_STA0_DVD);
+ else if (freq == 100000)
+ writel((4 * apb_clk) / 1000000, i2c_dev->base + ADDR_STA0_DVD);
+}
+
+static void sprd_i2c_enable(struct sprd_i2c *i2c_dev)
+{
+ u32 tmp = I2C_DVD_OPT;
+
+ writel(tmp, i2c_dev->base + I2C_CTL);
+
+ sprd_i2c_set_full_thld(i2c_dev, I2C_FIFO_FULL_THLD);
+ sprd_i2c_set_empty_thld(i2c_dev, I2C_FIFO_EMPTY_THLD);
+
+ sprd_i2c_set_clk(i2c_dev, i2c_dev->bus_freq);
+ sprd_i2c_reset_fifo(i2c_dev);
+ sprd_i2c_clear_irq(i2c_dev);
+
+ tmp = readl(i2c_dev->base + I2C_CTL);
+ writel(tmp | I2C_EN | I2C_INT_EN, i2c_dev->base + I2C_CTL);
+}
+
+static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id)
+{
+ struct sprd_i2c *i2c_dev = dev_id;
+ struct i2c_msg *msg = i2c_dev->msg;
+ bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK);
+ u32 i2c_tran;
+
+ if (msg->flags & I2C_M_RD)
+ i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD;
+ else
+ i2c_tran = i2c_dev->count;
+
+ /*
+ * If we got one ACK from slave when writing data, and we did not
+ * finish this transmission (i2c_tran is not zero), then we should
+ * continue to write data.
+ *
+ * For reading data, ack is always true, if i2c_tran is not 0 which
+ * means we still need to contine to read data from slave.
+ */
+ if (i2c_tran && ack) {
+ sprd_i2c_data_transfer(i2c_dev);
+ return IRQ_HANDLED;
+ }
+
+ i2c_dev->err = 0;
+
+ /*
+ * If we did not get one ACK from slave when writing data, we should
+ * return -EIO to notify users.
+ */
+ if (!ack)
+ i2c_dev->err = -EIO;
+ else if (msg->flags & I2C_M_RD && i2c_dev->count)
+ sprd_i2c_read_bytes(i2c_dev, i2c_dev->buf, i2c_dev->count);
+
+ /* Transmission is done and clear ack and start operation */
+ sprd_i2c_clear_ack(i2c_dev);
+ sprd_i2c_clear_start(i2c_dev);
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sprd_i2c_isr(int irq, void *dev_id)
+{
+ struct sprd_i2c *i2c_dev = dev_id;
+ struct i2c_msg *msg = i2c_dev->msg;
+ bool ack = !(readl(i2c_dev->base + I2C_STATUS) & I2C_RX_ACK);
+ u32 i2c_tran;
+
+ if (msg->flags & I2C_M_RD)
+ i2c_tran = i2c_dev->count >= I2C_FIFO_FULL_THLD;
+ else
+ i2c_tran = i2c_dev->count;
+
+ /*
+ * If we did not get one ACK from slave when writing data, then we
+ * should finish this transmission since we got some errors.
+ *
+ * When writing data, if i2c_tran == 0 which means we have writen
+ * done all data, then we can finish this transmission.
+ *
+ * When reading data, if conut < rx fifo full threshold, which
+ * means we can read all data in one time, then we can finish this
+ * transmission too.
+ */
+ if (!i2c_tran || !ack) {
+ sprd_i2c_clear_start(i2c_dev);
+ sprd_i2c_clear_irq(i2c_dev);
+ }
+
+ sprd_i2c_set_fifo_empty_int(i2c_dev, 0);
+ sprd_i2c_set_fifo_full_int(i2c_dev, 0);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int sprd_i2c_clk_init(struct sprd_i2c *i2c_dev)
+{
+ struct clk *clk_i2c, *clk_parent;
+
+ clk_i2c = devm_clk_get(i2c_dev->dev, "i2c");
+ if (IS_ERR(clk_i2c)) {
+ dev_warn(i2c_dev->dev, "i2c%d can't get the i2c clock\n",
+ i2c_dev->adap.nr);
+ clk_i2c = NULL;
+ }
+
+ clk_parent = devm_clk_get(i2c_dev->dev, "source");
+ if (IS_ERR(clk_parent)) {
+ dev_warn(i2c_dev->dev, "i2c%d can't get the source clock\n",
+ i2c_dev->adap.nr);
+ clk_parent = NULL;
+ }
+
+ if (clk_set_parent(clk_i2c, clk_parent))
+ i2c_dev->src_clk = clk_get_rate(clk_i2c);
+ else
+ i2c_dev->src_clk = 26000000;
+
+ dev_dbg(i2c_dev->dev, "i2c%d set source clock is %d\n",
+ i2c_dev->adap.nr, i2c_dev->src_clk);
+
+ i2c_dev->clk = devm_clk_get(i2c_dev->dev, "enable");
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_warn(i2c_dev->dev, "i2c%d can't get the enable clock\n",
+ i2c_dev->adap.nr);
+ i2c_dev->clk = NULL;
+ }
+
+ return 0;
+}
+
+static int sprd_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sprd_i2c *i2c_dev;
+ struct resource *res;
+ u32 prop;
+ int ret;
+
+ pdev->id = of_alias_get_id(dev->of_node, "i2c");
+
+ i2c_dev = devm_kzalloc(dev, sizeof(struct sprd_i2c), GFP_KERNEL);
+ if (!i2c_dev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c_dev->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(i2c_dev->base))
+ return PTR_ERR(i2c_dev->base);
+
+ i2c_dev->irq = platform_get_irq(pdev, 0);
+ if (i2c_dev->irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ return i2c_dev->irq;
+ }
+
+ i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
+ init_completion(&i2c_dev->complete);
+ snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name),
+ "%s", "sprd-i2c");
+
+ i2c_dev->bus_freq = 100000;
+ i2c_dev->adap.owner = THIS_MODULE;
+ i2c_dev->dev = dev;
+ i2c_dev->adap.retries = 3;
+ i2c_dev->adap.algo = &sprd_i2c_algo;
+ i2c_dev->adap.algo_data = i2c_dev;
+ i2c_dev->adap.dev.parent = dev;
+ i2c_dev->adap.nr = pdev->id;
+ i2c_dev->adap.dev.of_node = dev->of_node;
+
+ if (!of_property_read_u32(dev->of_node, "clock-frequency", &prop))
+ i2c_dev->bus_freq = prop;
+
+ /* We only support 100k and 400k now, otherwise will return error. */
+ if (i2c_dev->bus_freq != 100000 && i2c_dev->bus_freq != 400000)
+ return -EINVAL;
+
+ sprd_i2c_clk_init(i2c_dev);
+ platform_set_drvdata(pdev, i2c_dev);
+
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret)
+ return ret;
+
+ sprd_i2c_enable(i2c_dev);
+
+ pm_runtime_set_autosuspend_delay(i2c_dev->dev, SPRD_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(i2c_dev->dev);
+ pm_runtime_set_active(i2c_dev->dev);
+ pm_runtime_enable(i2c_dev->dev);
+
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
+ goto err_rpm_put;
+
+ ret = devm_request_threaded_irq(dev, i2c_dev->irq,
+ sprd_i2c_isr, sprd_i2c_isr_thread,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq %d\n", i2c_dev->irq);
+ goto err_rpm_put;
+ }
+
+ ret = i2c_add_numbered_adapter(&i2c_dev->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "add adapter failed\n");
+ goto err_rpm_put;
+ }
+
+ pm_runtime_mark_last_busy(i2c_dev->dev);
+ pm_runtime_put_autosuspend(i2c_dev->dev);
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put_noidle(i2c_dev->dev);
+ pm_runtime_disable(i2c_dev->dev);
+ clk_disable_unprepare(i2c_dev->clk);
+ return ret;
+}
+
+static int sprd_i2c_remove(struct platform_device *pdev)
+{
+ struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0)
+ return ret;
+
+ i2c_del_adapter(&i2c_dev->adap);
+ clk_disable_unprepare(i2c_dev->clk);
+
+ pm_runtime_put_noidle(i2c_dev->dev);
+ pm_runtime_disable(i2c_dev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev)
+{
+ struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
+
+ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
+ i2c_dev->is_suspended = true;
+ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
+
+ return pm_runtime_force_suspend(pdev);
+}
+
+static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev)
+{
+ struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
+
+ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
+ i2c_dev->is_suspended = false;
+ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
+
+ return pm_runtime_force_resume(pdev);
+}
+
+static int __maybe_unused sprd_i2c_runtime_suspend(struct device *pdev)
+{
+ struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2c_dev->clk);
+
+ return 0;
+}
+
+static int __maybe_unused sprd_i2c_runtime_resume(struct device *pdev)
+{
+ struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
+ int ret;
+
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret)
+ return ret;
+
+ sprd_i2c_enable(i2c_dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops sprd_i2c_pm_ops = {
+ SET_RUNTIME_PM_OPS(sprd_i2c_runtime_suspend,
+ sprd_i2c_runtime_resume, NULL)
+
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sprd_i2c_suspend_noirq,
+ sprd_i2c_resume_noirq)
+};
+
+static const struct of_device_id sprd_i2c_of_match[] = {
+ { .compatible = "sprd,sc9860-i2c", },
+ {},
+};
+
+static struct platform_driver sprd_i2c_driver = {
+ .probe = sprd_i2c_probe,
+ .remove = sprd_i2c_remove,
+ .driver = {
+ .name = "sprd-i2c",
+ .of_match_table = sprd_i2c_of_match,
+ .pm = &sprd_i2c_pm_ops,
+ },
+};
+
+static int sprd_i2c_init(void)
+{
+ return platform_driver_register(&sprd_i2c_driver);
+}
+arch_initcall_sync(sprd_i2c_init);
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
new file mode 100644
index 000000000..81158ae8b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-st.c
@@ -0,0 +1,917 @@
+/*
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.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.
+ *
+ * All the values below have +10% margin added to be
+ * compatible with some out-of-spec devices,
+ * like HDMI link of the Toshiba 19AV600 TV.
+ */
+static struct st_i2c_timings i2c_timings[] = {
+ [I2C_MODE_STANDARD] = {
+ .rate = 100000,
+ .rep_start_hold = 4400,
+ .rep_start_setup = 5170,
+ .start_hold = 4400,
+ .data_setup_time = 275,
+ .stop_setup_time = 4400,
+ .bus_free_time = 5170,
+ },
+ [I2C_MODE_FAST] = {
+ .rate = 400000,
+ .rep_start_hold = 660,
+ .rep_start_setup = 660,
+ .start_hold = 660,
+ .data_setup_time = 110,
+ .stop_setup_time = 660,
+ .bus_free_time = 1430,
+ },
+};
+
+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_recover_bus(struct i2c_adapter *i2c_adap)
+{
+ struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+ u32 ctl;
+
+ dev_dbg(i2c_dev->dev, "Trying to recover bus\n");
+
+ /*
+ * SSP IP is dual role SPI/I2C to generate 9 clock pulses
+ * we switch to SPI node, 9 bit words and write a 0. This
+ * has been validate with a oscilloscope and is easier
+ * than switching to GPIO mode.
+ */
+
+ /* Disable interrupts */
+ writel_relaxed(0, i2c_dev->base + SSC_IEN);
+
+ st_i2c_hw_config(i2c_dev);
+
+ 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);
+
+ st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
+ usleep_range(8000, 10000);
+
+ writel_relaxed(0, i2c_dev->base + SSC_TBUF);
+ usleep_range(2000, 4000);
+ st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
+
+ return 0;
+}
+
+static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
+{
+ u32 sta;
+ int i, ret;
+
+ 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);
+
+ ret = i2c_recover_bus(&i2c_dev->adap);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
+ return ret;
+ }
+
+ 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
+ * @max: Maximum amount of data to fill into the Tx FIFO
+ *
+ * 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 = -EAGAIN;
+ 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 = i2c_8bit_addr_from_msg(msg);
+ 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 st_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ 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 const struct i2c_algorithm st_i2c_algo = {
+ .master_xfer = st_i2c_xfer,
+ .functionality = st_i2c_func,
+};
+
+static struct i2c_bus_recovery_info st_i2c_recovery_info = {
+ .recover_bus = st_i2c_recover_bus,
+};
+
+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(%pa)", &res->start);
+ adap->owner = THIS_MODULE;
+ adap->timeout = 2 * HZ;
+ adap->retries = 0;
+ adap->algo = &st_i2c_algo;
+ adap->bus_recovery_info = &st_i2c_recovery_info;
+ 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)
+ 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 const 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",
+ .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");
diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c
new file mode 100644
index 000000000..667f8032f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stm32.c
@@ -0,0 +1,153 @@
+/*
+ * i2c-stm32.c
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2017
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include "i2c-stm32.h"
+
+/* Functions for DMA support */
+struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
+ dma_addr_t phy_addr,
+ u32 txdr_offset,
+ u32 rxdr_offset)
+{
+ struct stm32_i2c_dma *dma;
+ struct dma_slave_config dma_sconfig;
+ int ret;
+
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return ERR_PTR(-ENOMEM);
+
+ /* Request and configure I2C TX dma channel */
+ dma->chan_tx = dma_request_chan(dev, "tx");
+ if (IS_ERR(dma->chan_tx)) {
+ dev_dbg(dev, "can't request DMA tx channel\n");
+ ret = PTR_ERR(dma->chan_tx);
+ goto fail_al;
+ }
+
+ memset(&dma_sconfig, 0, sizeof(dma_sconfig));
+ dma_sconfig.dst_addr = phy_addr + txdr_offset;
+ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconfig.dst_maxburst = 1;
+ dma_sconfig.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
+ if (ret < 0) {
+ dev_err(dev, "can't configure tx channel\n");
+ goto fail_tx;
+ }
+
+ /* Request and configure I2C RX dma channel */
+ dma->chan_rx = dma_request_chan(dev, "rx");
+ if (IS_ERR(dma->chan_rx)) {
+ dev_err(dev, "can't request DMA rx channel\n");
+ ret = PTR_ERR(dma->chan_rx);
+ goto fail_tx;
+ }
+
+ memset(&dma_sconfig, 0, sizeof(dma_sconfig));
+ dma_sconfig.src_addr = phy_addr + rxdr_offset;
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconfig.src_maxburst = 1;
+ dma_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
+ if (ret < 0) {
+ dev_err(dev, "can't configure rx channel\n");
+ goto fail_rx;
+ }
+
+ init_completion(&dma->dma_complete);
+
+ dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+ return dma;
+
+fail_rx:
+ dma_release_channel(dma->chan_rx);
+fail_tx:
+ dma_release_channel(dma->chan_tx);
+fail_al:
+ devm_kfree(dev, dma);
+ dev_info(dev, "can't use DMA\n");
+
+ return ERR_PTR(ret);
+}
+
+void stm32_i2c_dma_free(struct stm32_i2c_dma *dma)
+{
+ dma->dma_buf = 0;
+ dma->dma_len = 0;
+
+ dma_release_channel(dma->chan_tx);
+ dma->chan_tx = NULL;
+
+ dma_release_channel(dma->chan_rx);
+ dma->chan_rx = NULL;
+
+ dma->chan_using = NULL;
+}
+
+int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
+ bool rd_wr, u32 len, u8 *buf,
+ dma_async_tx_callback callback,
+ void *dma_async_param)
+{
+ struct dma_async_tx_descriptor *txdesc;
+ struct device *chan_dev;
+ int ret;
+
+ if (rd_wr) {
+ dma->chan_using = dma->chan_rx;
+ dma->dma_transfer_dir = DMA_DEV_TO_MEM;
+ dma->dma_data_dir = DMA_FROM_DEVICE;
+ } else {
+ dma->chan_using = dma->chan_tx;
+ dma->dma_transfer_dir = DMA_MEM_TO_DEV;
+ dma->dma_data_dir = DMA_TO_DEVICE;
+ }
+
+ dma->dma_len = len;
+ chan_dev = dma->chan_using->device->dev;
+
+ dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len,
+ dma->dma_data_dir);
+ if (dma_mapping_error(chan_dev, dma->dma_buf)) {
+ dev_err(dev, "DMA mapping failed\n");
+ return -EINVAL;
+ }
+
+ txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
+ dma->dma_len,
+ dma->dma_transfer_dir,
+ DMA_PREP_INTERRUPT);
+ if (!txdesc) {
+ dev_err(dev, "Not able to get desc for DMA xfer\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ reinit_completion(&dma->dma_complete);
+
+ txdesc->callback = callback;
+ txdesc->callback_param = dma_async_param;
+ ret = dma_submit_error(dmaengine_submit(txdesc));
+ if (ret < 0) {
+ dev_err(dev, "DMA submit failed\n");
+ goto err;
+ }
+
+ dma_async_issue_pending(dma->chan_using);
+
+ return 0;
+
+err:
+ dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len,
+ dma->dma_data_dir);
+ return ret;
+}
diff --git a/drivers/i2c/busses/i2c-stm32.h b/drivers/i2c/busses/i2c-stm32.h
new file mode 100644
index 000000000..868755f82
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stm32.h
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i2c-stm32.h
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2017
+ * Copyright (C) STMicroelectronics 2017
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ */
+
+#ifndef _I2C_STM32_H
+#define _I2C_STM32_H
+
+#include <linux/dma-direction.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+
+enum stm32_i2c_speed {
+ STM32_I2C_SPEED_STANDARD, /* 100 kHz */
+ STM32_I2C_SPEED_FAST, /* 400 kHz */
+ STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */
+ STM32_I2C_SPEED_END,
+};
+
+/**
+ * struct stm32_i2c_dma - DMA specific data
+ * @chan_tx: dma channel for TX transfer
+ * @chan_rx: dma channel for RX transfer
+ * @chan_using: dma channel used for the current transfer (TX or RX)
+ * @dma_buf: dma buffer
+ * @dma_len: dma buffer len
+ * @dma_transfer_dir: dma transfer direction indicator
+ * @dma_data_dir: dma transfer mode indicator
+ * @dma_complete: dma transfer completion
+ */
+struct stm32_i2c_dma {
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_using;
+ dma_addr_t dma_buf;
+ unsigned int dma_len;
+ enum dma_transfer_direction dma_transfer_dir;
+ enum dma_data_direction dma_data_dir;
+ struct completion dma_complete;
+};
+
+struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
+ dma_addr_t phy_addr,
+ u32 txdr_offset, u32 rxdr_offset);
+
+void stm32_i2c_dma_free(struct stm32_i2c_dma *dma);
+
+int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
+ bool rd_wr, u32 len, u8 *buf,
+ dma_async_tx_callback callback,
+ void *dma_async_param);
+
+#endif /* _I2C_STM32_H */
diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
new file mode 100644
index 000000000..ba600d77a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stm32f4.c
@@ -0,0 +1,894 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STMicroelectronics STM32 I2C controller
+ *
+ * This I2C controller is described in the STM32F429/439 Soc reference manual.
+ * Please see below a link to the documentation:
+ * http://www.st.com/resource/en/reference_manual/DM00031020.pdf
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2016
+ * Copyright (C) STMicroelectronics 2017
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * This driver is based on i2c-st.c
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include "i2c-stm32.h"
+
+/* STM32F4 I2C offset registers */
+#define STM32F4_I2C_CR1 0x00
+#define STM32F4_I2C_CR2 0x04
+#define STM32F4_I2C_DR 0x10
+#define STM32F4_I2C_SR1 0x14
+#define STM32F4_I2C_SR2 0x18
+#define STM32F4_I2C_CCR 0x1C
+#define STM32F4_I2C_TRISE 0x20
+#define STM32F4_I2C_FLTR 0x24
+
+/* STM32F4 I2C control 1*/
+#define STM32F4_I2C_CR1_POS BIT(11)
+#define STM32F4_I2C_CR1_ACK BIT(10)
+#define STM32F4_I2C_CR1_STOP BIT(9)
+#define STM32F4_I2C_CR1_START BIT(8)
+#define STM32F4_I2C_CR1_PE BIT(0)
+
+/* STM32F4 I2C control 2 */
+#define STM32F4_I2C_CR2_FREQ_MASK GENMASK(5, 0)
+#define STM32F4_I2C_CR2_FREQ(n) ((n) & STM32F4_I2C_CR2_FREQ_MASK)
+#define STM32F4_I2C_CR2_ITBUFEN BIT(10)
+#define STM32F4_I2C_CR2_ITEVTEN BIT(9)
+#define STM32F4_I2C_CR2_ITERREN BIT(8)
+#define STM32F4_I2C_CR2_IRQ_MASK (STM32F4_I2C_CR2_ITBUFEN | \
+ STM32F4_I2C_CR2_ITEVTEN | \
+ STM32F4_I2C_CR2_ITERREN)
+
+/* STM32F4 I2C Status 1 */
+#define STM32F4_I2C_SR1_AF BIT(10)
+#define STM32F4_I2C_SR1_ARLO BIT(9)
+#define STM32F4_I2C_SR1_BERR BIT(8)
+#define STM32F4_I2C_SR1_TXE BIT(7)
+#define STM32F4_I2C_SR1_RXNE BIT(6)
+#define STM32F4_I2C_SR1_BTF BIT(2)
+#define STM32F4_I2C_SR1_ADDR BIT(1)
+#define STM32F4_I2C_SR1_SB BIT(0)
+#define STM32F4_I2C_SR1_ITEVTEN_MASK (STM32F4_I2C_SR1_BTF | \
+ STM32F4_I2C_SR1_ADDR | \
+ STM32F4_I2C_SR1_SB)
+#define STM32F4_I2C_SR1_ITBUFEN_MASK (STM32F4_I2C_SR1_TXE | \
+ STM32F4_I2C_SR1_RXNE)
+#define STM32F4_I2C_SR1_ITERREN_MASK (STM32F4_I2C_SR1_AF | \
+ STM32F4_I2C_SR1_ARLO | \
+ STM32F4_I2C_SR1_BERR)
+
+/* STM32F4 I2C Status 2 */
+#define STM32F4_I2C_SR2_BUSY BIT(1)
+
+/* STM32F4 I2C Control Clock */
+#define STM32F4_I2C_CCR_CCR_MASK GENMASK(11, 0)
+#define STM32F4_I2C_CCR_CCR(n) ((n) & STM32F4_I2C_CCR_CCR_MASK)
+#define STM32F4_I2C_CCR_FS BIT(15)
+#define STM32F4_I2C_CCR_DUTY BIT(14)
+
+/* STM32F4 I2C Trise */
+#define STM32F4_I2C_TRISE_VALUE_MASK GENMASK(5, 0)
+#define STM32F4_I2C_TRISE_VALUE(n) ((n) & STM32F4_I2C_TRISE_VALUE_MASK)
+
+#define STM32F4_I2C_MIN_STANDARD_FREQ 2U
+#define STM32F4_I2C_MIN_FAST_FREQ 6U
+#define STM32F4_I2C_MAX_FREQ 46U
+#define HZ_TO_MHZ 1000000
+
+/**
+ * struct stm32f4_i2c_msg - client specific data
+ * @addr: 8-bit slave addr, including r/w bit
+ * @count: number of bytes to be transferred
+ * @buf: data buffer
+ * @result: result of the transfer
+ * @stop: last I2C msg to be sent, i.e. STOP to be generated
+ */
+struct stm32f4_i2c_msg {
+ u8 addr;
+ u32 count;
+ u8 *buf;
+ int result;
+ bool stop;
+};
+
+/**
+ * struct stm32f4_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
+ * @clk: hw i2c clock
+ * @speed: I2C clock frequency of the controller. Standard or Fast are supported
+ * @parent_rate: I2C clock parent rate in MHz
+ * @msg: I2C transfer information
+ */
+struct stm32f4_i2c_dev {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ struct completion complete;
+ struct clk *clk;
+ int speed;
+ int parent_rate;
+ struct stm32f4_i2c_msg msg;
+};
+
+static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) | mask, reg);
+}
+
+static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) & ~mask, reg);
+}
+
+static void stm32f4_i2c_disable_irq(struct stm32f4_i2c_dev *i2c_dev)
+{
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
+}
+
+static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 freq;
+ u32 cr2 = 0;
+
+ i2c_dev->parent_rate = clk_get_rate(i2c_dev->clk);
+ freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
+
+ if (i2c_dev->speed == STM32_I2C_SPEED_STANDARD) {
+ /*
+ * To reach 100 kHz, the parent clk frequency should be between
+ * a minimum value of 2 MHz and a maximum value of 46 MHz due
+ * to hardware limitation
+ */
+ if (freq < STM32F4_I2C_MIN_STANDARD_FREQ ||
+ freq > STM32F4_I2C_MAX_FREQ) {
+ dev_err(i2c_dev->dev,
+ "bad parent clk freq for standard mode\n");
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * To be as close as possible to 400 kHz, the parent clk
+ * frequency should be between a minimum value of 6 MHz and a
+ * maximum value of 46 MHz due to hardware limitation
+ */
+ if (freq < STM32F4_I2C_MIN_FAST_FREQ ||
+ freq > STM32F4_I2C_MAX_FREQ) {
+ dev_err(i2c_dev->dev,
+ "bad parent clk freq for fast mode\n");
+ return -EINVAL;
+ }
+ }
+
+ cr2 |= STM32F4_I2C_CR2_FREQ(freq);
+ writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
+
+ return 0;
+}
+
+static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
+ u32 trise;
+
+ /*
+ * These bits must be programmed with the maximum SCL rise time given in
+ * the I2C bus specification, incremented by 1.
+ *
+ * In standard mode, the maximum allowed SCL rise time is 1000 ns.
+ * If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to
+ * 0x08 so period = 125 ns therefore the TRISE[5:0] bits must be
+ * programmed with 0x9. (1000 ns / 125 ns + 1)
+ * So, for I2C standard mode TRISE = FREQ[5:0] + 1
+ *
+ * In fast mode, the maximum allowed SCL rise time is 300 ns.
+ * If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to
+ * 0x08 so period = 125 ns therefore the TRISE[5:0] bits must be
+ * programmed with 0x3. (300 ns / 125 ns + 1)
+ * So, for I2C fast mode TRISE = FREQ[5:0] * 300 / 1000 + 1
+ *
+ * Function stm32f4_i2c_set_periph_clk_freq made sure that parent rate
+ * is not higher than 46 MHz . As a result trise is at most 4 bits wide
+ * and so fits into the TRISE bits [5:0].
+ */
+ if (i2c_dev->speed == STM32_I2C_SPEED_STANDARD)
+ trise = freq + 1;
+ else
+ trise = freq * 3 / 10 + 1;
+
+ writel_relaxed(STM32F4_I2C_TRISE_VALUE(trise),
+ i2c_dev->base + STM32F4_I2C_TRISE);
+}
+
+static void stm32f4_i2c_set_speed_mode(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 val;
+ u32 ccr = 0;
+
+ if (i2c_dev->speed == STM32_I2C_SPEED_STANDARD) {
+ /*
+ * In standard mode:
+ * t_scl_high = t_scl_low = CCR * I2C parent clk period
+ * So to reach 100 kHz, we have:
+ * CCR = I2C parent rate / 100 kHz >> 1
+ *
+ * For example with parent rate = 2 MHz:
+ * CCR = 2000000 / (100000 << 1) = 10
+ * t_scl_high = t_scl_low = 10 * (1 / 2000000) = 5000 ns
+ * t_scl_high + t_scl_low = 10000 ns so 100 kHz is reached
+ *
+ * Function stm32f4_i2c_set_periph_clk_freq made sure that
+ * parent rate is not higher than 46 MHz . As a result val
+ * is at most 8 bits wide and so fits into the CCR bits [11:0].
+ */
+ val = i2c_dev->parent_rate / (100000 << 1);
+ } else {
+ /*
+ * In fast mode, we compute CCR with duty = 0 as with low
+ * frequencies we are not able to reach 400 kHz.
+ * In that case:
+ * t_scl_high = CCR * I2C parent clk period
+ * t_scl_low = 2 * CCR * I2C parent clk period
+ * So, CCR = I2C parent rate / (400 kHz * 3)
+ *
+ * For example with parent rate = 6 MHz:
+ * CCR = 6000000 / (400000 * 3) = 5
+ * t_scl_high = 5 * (1 / 6000000) = 833 ns > 600 ns
+ * t_scl_low = 2 * 5 * (1 / 6000000) = 1667 ns > 1300 ns
+ * t_scl_high + t_scl_low = 2500 ns so 400 kHz is reached
+ *
+ * Function stm32f4_i2c_set_periph_clk_freq made sure that
+ * parent rate is not higher than 46 MHz . As a result val
+ * is at most 6 bits wide and so fits into the CCR bits [11:0].
+ */
+ val = DIV_ROUND_UP(i2c_dev->parent_rate, 400000 * 3);
+
+ /* Select Fast mode */
+ ccr |= STM32F4_I2C_CCR_FS;
+ }
+
+ ccr |= STM32F4_I2C_CCR_CCR(val);
+ writel_relaxed(ccr, i2c_dev->base + STM32F4_I2C_CCR);
+}
+
+/**
+ * stm32f4_i2c_hw_config() - Prepare I2C block
+ * @i2c_dev: Controller's private data
+ */
+static int stm32f4_i2c_hw_config(struct stm32f4_i2c_dev *i2c_dev)
+{
+ int ret;
+
+ ret = stm32f4_i2c_set_periph_clk_freq(i2c_dev);
+ if (ret)
+ return ret;
+
+ stm32f4_i2c_set_rise_time(i2c_dev);
+
+ stm32f4_i2c_set_speed_mode(i2c_dev);
+
+ /* Enable I2C */
+ writel_relaxed(STM32F4_I2C_CR1_PE, i2c_dev->base + STM32F4_I2C_CR1);
+
+ return 0;
+}
+
+static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 status;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
+ status,
+ !(status & STM32F4_I2C_SR2_BUSY),
+ 10, 1000);
+ if (ret) {
+ dev_dbg(i2c_dev->dev, "bus not free\n");
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+/**
+ * stm32f4_i2c_write_ byte() - Write a byte in the data register
+ * @i2c_dev: Controller's private data
+ * @byte: Data to write in the register
+ */
+static void stm32f4_i2c_write_byte(struct stm32f4_i2c_dev *i2c_dev, u8 byte)
+{
+ writel_relaxed(byte, i2c_dev->base + STM32F4_I2C_DR);
+}
+
+/**
+ * stm32f4_i2c_write_msg() - Fill the data register in write mode
+ * @i2c_dev: Controller's private data
+ *
+ * This function fills the data register with I2C transfer buffer
+ */
+static void stm32f4_i2c_write_msg(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+
+ stm32f4_i2c_write_byte(i2c_dev, *msg->buf++);
+ msg->count--;
+}
+
+static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 rbuf;
+
+ rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
+ *msg->buf++ = rbuf;
+ msg->count--;
+}
+
+static void stm32f4_i2c_terminate_xfer(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+
+ stm32f4_i2c_disable_irq(i2c_dev);
+
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+
+ complete(&i2c_dev->complete);
+}
+
+/**
+ * stm32f4_i2c_handle_write() - Handle FIFO empty interrupt in case of write
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_write(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ if (msg->count) {
+ stm32f4_i2c_write_msg(i2c_dev);
+ if (!msg->count) {
+ /*
+ * Disable buffer interrupts for RX not empty and TX
+ * empty events
+ */
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ }
+ } else {
+ stm32f4_i2c_terminate_xfer(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
+ * @i2c_dev: Controller's private data
+ *
+ * This function is called when a new data is received in data register
+ */
+static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ switch (msg->count) {
+ case 1:
+ stm32f4_i2c_disable_irq(i2c_dev);
+ stm32f4_i2c_read_msg(i2c_dev);
+ complete(&i2c_dev->complete);
+ break;
+ /*
+ * For 2-byte reception, 3-byte reception and for Data N-2, N-1 and N
+ * for N-byte reception with N > 3, we do not have to read the data
+ * register when RX not empty event occurs as we have to wait for byte
+ * transferred finished event before reading data.
+ * So, here we just disable buffer interrupt in order to avoid another
+ * system preemption due to RX not empty event.
+ */
+ case 2:
+ case 3:
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ break;
+ /*
+ * For N byte reception with N > 3 we directly read data register
+ * until N-2 data.
+ */
+ default:
+ stm32f4_i2c_read_msg(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_rx_done() - Handle byte transfer finished interrupt
+ * in case of read
+ * @i2c_dev: Controller's private data
+ *
+ * This function is called when a new data is received in the shift register
+ * but data register has not been read yet.
+ */
+static void stm32f4_i2c_handle_rx_done(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 mask;
+ int i;
+
+ switch (msg->count) {
+ case 2:
+ /*
+ * In order to correctly send the Stop or Repeated Start
+ * condition on the I2C bus, the STOP/START bit has to be set
+ * before reading the last two bytes (data N-1 and N).
+ * After that, we could read the last two bytes, disable
+ * remaining interrupts and notify the end of xfer to the
+ * client
+ */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+
+ for (i = 2; i > 0; i--)
+ stm32f4_i2c_read_msg(i2c_dev);
+
+ reg = i2c_dev->base + STM32F4_I2C_CR2;
+ mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
+ stm32f4_i2c_clr_bits(reg, mask);
+
+ complete(&i2c_dev->complete);
+ break;
+ case 3:
+ /*
+ * In order to correctly generate the NACK pulse after the last
+ * received data byte, we have to enable NACK before reading N-2
+ * data
+ */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
+ stm32f4_i2c_read_msg(i2c_dev);
+ break;
+ default:
+ stm32f4_i2c_read_msg(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
+ * master receiver
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 cr1;
+
+ switch (msg->count) {
+ case 0:
+ stm32f4_i2c_terminate_xfer(i2c_dev);
+
+ /* Clear ADDR flag */
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+ case 1:
+ /*
+ * Single byte reception:
+ * Enable NACK and reset POS (Acknowledge position).
+ * Then, clear ADDR flag and set STOP or RepSTART.
+ * In that way, the NACK and STOP or RepStart pulses will be
+ * sent as soon as the byte will be received in shift register
+ */
+ cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
+ cr1 &= ~(STM32F4_I2C_CR1_ACK | STM32F4_I2C_CR1_POS);
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+
+ if (msg->stop)
+ cr1 |= STM32F4_I2C_CR1_STOP;
+ else
+ cr1 |= STM32F4_I2C_CR1_START;
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+ break;
+ case 2:
+ /*
+ * 2-byte reception:
+ * Enable NACK, set POS (NACK position) and clear ADDR flag.
+ * In that way, NACK will be sent for the next byte which will
+ * be received in the shift register instead of the current
+ * one.
+ */
+ cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
+ cr1 &= ~STM32F4_I2C_CR1_ACK;
+ cr1 |= STM32F4_I2C_CR1_POS;
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+
+ default:
+ /*
+ * N-byte reception:
+ * Enable ACK, reset POS (ACK postion) and clear ADDR flag.
+ * In that way, ACK will be sent as soon as the current byte
+ * will be received in the shift register
+ */
+ cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
+ cr1 |= STM32F4_I2C_CR1_ACK;
+ cr1 &= ~STM32F4_I2C_CR1_POS;
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+ }
+}
+
+/**
+ * stm32f4_i2c_isr_event() - Interrupt routine for I2C bus event
+ * @irq: interrupt number
+ * @data: Controller's private data
+ */
+static irqreturn_t stm32f4_i2c_isr_event(int irq, void *data)
+{
+ struct stm32f4_i2c_dev *i2c_dev = data;
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 possible_status = STM32F4_I2C_SR1_ITEVTEN_MASK;
+ u32 status, ien, event, cr2;
+
+ cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
+ ien = cr2 & STM32F4_I2C_CR2_IRQ_MASK;
+
+ /* Update possible_status if buffer interrupt is enabled */
+ if (ien & STM32F4_I2C_CR2_ITBUFEN)
+ possible_status |= STM32F4_I2C_SR1_ITBUFEN_MASK;
+
+ status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
+ event = status & possible_status;
+ if (!event) {
+ dev_dbg(i2c_dev->dev,
+ "spurious evt irq (status=0x%08x, ien=0x%08x)\n",
+ status, ien);
+ return IRQ_NONE;
+ }
+
+ /* Start condition generated */
+ if (event & STM32F4_I2C_SR1_SB)
+ stm32f4_i2c_write_byte(i2c_dev, msg->addr);
+
+ /* I2C Address sent */
+ if (event & STM32F4_I2C_SR1_ADDR) {
+ if (msg->addr & I2C_M_RD)
+ stm32f4_i2c_handle_rx_addr(i2c_dev);
+ else
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+
+ /*
+ * Enable buffer interrupts for RX not empty and TX empty
+ * events
+ */
+ cr2 |= STM32F4_I2C_CR2_ITBUFEN;
+ writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
+ }
+
+ /* TX empty */
+ if ((event & STM32F4_I2C_SR1_TXE) && !(msg->addr & I2C_M_RD))
+ stm32f4_i2c_handle_write(i2c_dev);
+
+ /* RX not empty */
+ if ((event & STM32F4_I2C_SR1_RXNE) && (msg->addr & I2C_M_RD))
+ stm32f4_i2c_handle_read(i2c_dev);
+
+ /*
+ * The BTF (Byte Transfer finished) event occurs when:
+ * - in reception : a new byte is received in the shift register
+ * but the previous byte has not been read yet from data register
+ * - in transmission: a new byte should be sent but the data register
+ * has not been written yet
+ */
+ if (event & STM32F4_I2C_SR1_BTF) {
+ if (msg->addr & I2C_M_RD)
+ stm32f4_i2c_handle_rx_done(i2c_dev);
+ else
+ stm32f4_i2c_handle_write(i2c_dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * stm32f4_i2c_isr_error() - Interrupt routine for I2C bus error
+ * @irq: interrupt number
+ * @data: Controller's private data
+ */
+static irqreturn_t stm32f4_i2c_isr_error(int irq, void *data)
+{
+ struct stm32f4_i2c_dev *i2c_dev = data;
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 status;
+
+ status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
+
+ /* Arbitration lost */
+ if (status & STM32F4_I2C_SR1_ARLO) {
+ status &= ~STM32F4_I2C_SR1_ARLO;
+ writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
+ msg->result = -EAGAIN;
+ }
+
+ /*
+ * Acknowledge failure:
+ * In master transmitter mode a Stop must be generated by software
+ */
+ if (status & STM32F4_I2C_SR1_AF) {
+ if (!(msg->addr & I2C_M_RD)) {
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ }
+ status &= ~STM32F4_I2C_SR1_AF;
+ writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
+ msg->result = -EIO;
+ }
+
+ /* Bus error */
+ if (status & STM32F4_I2C_SR1_BERR) {
+ status &= ~STM32F4_I2C_SR1_BERR;
+ writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
+ msg->result = -EIO;
+ }
+
+ stm32f4_i2c_disable_irq(i2c_dev);
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * stm32f4_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 stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, bool is_first,
+ bool is_last)
+{
+ struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
+ unsigned long timeout;
+ u32 mask;
+ int ret;
+
+ f4_msg->addr = i2c_8bit_addr_from_msg(msg);
+ f4_msg->buf = msg->buf;
+ f4_msg->count = msg->len;
+ f4_msg->result = 0;
+ f4_msg->stop = is_last;
+
+ reinit_completion(&i2c_dev->complete);
+
+ /* Enable events and errors interrupts */
+ mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
+ stm32f4_i2c_set_bits(i2c_dev->base + STM32F4_I2C_CR2, mask);
+
+ if (is_first) {
+ ret = stm32f4_i2c_wait_free_bus(i2c_dev);
+ if (ret)
+ return ret;
+
+ /* START generation */
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+ }
+
+ timeout = wait_for_completion_timeout(&i2c_dev->complete,
+ i2c_dev->adap.timeout);
+ ret = f4_msg->result;
+
+ if (!timeout)
+ ret = -ETIMEDOUT;
+
+ return ret;
+}
+
+/**
+ * stm32f4_i2c_xfer() - Transfer combined 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 stm32f4_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct stm32f4_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+ int ret, i;
+
+ ret = clk_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ for (i = 0; i < num && !ret; i++)
+ ret = stm32f4_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0,
+ i == num - 1);
+
+ clk_disable(i2c_dev->clk);
+
+ return (ret < 0) ? ret : num;
+}
+
+static u32 stm32f4_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm stm32f4_i2c_algo = {
+ .master_xfer = stm32f4_i2c_xfer,
+ .functionality = stm32f4_i2c_func,
+};
+
+static int stm32f4_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct stm32f4_i2c_dev *i2c_dev;
+ struct resource *res;
+ u32 irq_event, irq_error, clk_rate;
+ struct i2c_adapter *adap;
+ struct reset_control *rst;
+ 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);
+
+ irq_event = irq_of_parse_and_map(np, 0);
+ if (!irq_event) {
+ dev_err(&pdev->dev, "IRQ event missing or invalid\n");
+ return -EINVAL;
+ }
+
+ irq_error = irq_of_parse_and_map(np, 1);
+ if (!irq_error) {
+ dev_err(&pdev->dev, "IRQ error missing or invalid\n");
+ return -EINVAL;
+ }
+
+ i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_err(&pdev->dev, "Error: Missing controller clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to prepare_enable clock\n");
+ return ret;
+ }
+
+ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(rst)) {
+ dev_err(&pdev->dev, "Error: Missing controller reset\n");
+ ret = PTR_ERR(rst);
+ goto clk_free;
+ }
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+
+ i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
+ ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
+ if (!ret && clk_rate >= 400000)
+ i2c_dev->speed = STM32_I2C_SPEED_FAST;
+
+ i2c_dev->dev = &pdev->dev;
+
+ ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq event %i\n",
+ irq_event);
+ goto clk_free;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq error %i\n",
+ irq_error);
+ goto clk_free;
+ }
+
+ ret = stm32f4_i2c_hw_config(i2c_dev);
+ if (ret)
+ goto clk_free;
+
+ adap = &i2c_dev->adap;
+ i2c_set_adapdata(adap, i2c_dev);
+ snprintf(adap->name, sizeof(adap->name), "STM32 I2C(%pa)", &res->start);
+ adap->owner = THIS_MODULE;
+ adap->timeout = 2 * HZ;
+ adap->retries = 0;
+ adap->algo = &stm32f4_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)
+ goto clk_free;
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ clk_disable(i2c_dev->clk);
+
+ dev_info(i2c_dev->dev, "STM32F4 I2C driver registered\n");
+
+ return 0;
+
+clk_free:
+ clk_disable_unprepare(i2c_dev->clk);
+ return ret;
+}
+
+static int stm32f4_i2c_remove(struct platform_device *pdev)
+{
+ struct stm32f4_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c_dev->adap);
+
+ clk_unprepare(i2c_dev->clk);
+
+ return 0;
+}
+
+static const struct of_device_id stm32f4_i2c_match[] = {
+ { .compatible = "st,stm32f4-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32f4_i2c_match);
+
+static struct platform_driver stm32f4_i2c_driver = {
+ .driver = {
+ .name = "stm32f4-i2c",
+ .of_match_table = stm32f4_i2c_match,
+ },
+ .probe = stm32f4_i2c_probe,
+ .remove = stm32f4_i2c_remove,
+};
+
+module_platform_driver(stm32f4_i2c_driver);
+
+MODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32F4 I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
new file mode 100644
index 000000000..e352c1608
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -0,0 +1,1996 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STMicroelectronics STM32F7 I2C controller
+ *
+ * This I2C controller is described in the STM32F75xxx and STM32F74xxx Soc
+ * reference manual.
+ * Please see below a link to the documentation:
+ * http://www.st.com/resource/en/reference_manual/dm00124865.pdf
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2017
+ * Copyright (C) STMicroelectronics 2017
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * This driver is based on i2c-stm32f4.c
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include "i2c-stm32.h"
+
+/* STM32F7 I2C registers */
+#define STM32F7_I2C_CR1 0x00
+#define STM32F7_I2C_CR2 0x04
+#define STM32F7_I2C_OAR1 0x08
+#define STM32F7_I2C_OAR2 0x0C
+#define STM32F7_I2C_PECR 0x20
+#define STM32F7_I2C_TIMINGR 0x10
+#define STM32F7_I2C_ISR 0x18
+#define STM32F7_I2C_ICR 0x1C
+#define STM32F7_I2C_RXDR 0x24
+#define STM32F7_I2C_TXDR 0x28
+
+/* STM32F7 I2C control 1 */
+#define STM32F7_I2C_CR1_PECEN BIT(23)
+#define STM32F7_I2C_CR1_SBC BIT(16)
+#define STM32F7_I2C_CR1_RXDMAEN BIT(15)
+#define STM32F7_I2C_CR1_TXDMAEN BIT(14)
+#define STM32F7_I2C_CR1_ANFOFF BIT(12)
+#define STM32F7_I2C_CR1_DNF_MASK GENMASK(11, 8)
+#define STM32F7_I2C_CR1_DNF(n) (((n) & 0xf) << 8)
+#define STM32F7_I2C_CR1_ERRIE BIT(7)
+#define STM32F7_I2C_CR1_TCIE BIT(6)
+#define STM32F7_I2C_CR1_STOPIE BIT(5)
+#define STM32F7_I2C_CR1_NACKIE BIT(4)
+#define STM32F7_I2C_CR1_ADDRIE BIT(3)
+#define STM32F7_I2C_CR1_RXIE BIT(2)
+#define STM32F7_I2C_CR1_TXIE BIT(1)
+#define STM32F7_I2C_CR1_PE BIT(0)
+#define STM32F7_I2C_ALL_IRQ_MASK (STM32F7_I2C_CR1_ERRIE \
+ | STM32F7_I2C_CR1_TCIE \
+ | STM32F7_I2C_CR1_STOPIE \
+ | STM32F7_I2C_CR1_NACKIE \
+ | STM32F7_I2C_CR1_RXIE \
+ | STM32F7_I2C_CR1_TXIE)
+#define STM32F7_I2C_XFER_IRQ_MASK (STM32F7_I2C_CR1_TCIE \
+ | STM32F7_I2C_CR1_STOPIE \
+ | STM32F7_I2C_CR1_NACKIE \
+ | STM32F7_I2C_CR1_RXIE \
+ | STM32F7_I2C_CR1_TXIE)
+
+/* STM32F7 I2C control 2 */
+#define STM32F7_I2C_CR2_PECBYTE BIT(26)
+#define STM32F7_I2C_CR2_RELOAD BIT(24)
+#define STM32F7_I2C_CR2_NBYTES_MASK GENMASK(23, 16)
+#define STM32F7_I2C_CR2_NBYTES(n) (((n) & 0xff) << 16)
+#define STM32F7_I2C_CR2_NACK BIT(15)
+#define STM32F7_I2C_CR2_STOP BIT(14)
+#define STM32F7_I2C_CR2_START BIT(13)
+#define STM32F7_I2C_CR2_HEAD10R BIT(12)
+#define STM32F7_I2C_CR2_ADD10 BIT(11)
+#define STM32F7_I2C_CR2_RD_WRN BIT(10)
+#define STM32F7_I2C_CR2_SADD10_MASK GENMASK(9, 0)
+#define STM32F7_I2C_CR2_SADD10(n) (((n) & \
+ STM32F7_I2C_CR2_SADD10_MASK))
+#define STM32F7_I2C_CR2_SADD7_MASK GENMASK(7, 1)
+#define STM32F7_I2C_CR2_SADD7(n) (((n) & 0x7f) << 1)
+
+/* STM32F7 I2C Own Address 1 */
+#define STM32F7_I2C_OAR1_OA1EN BIT(15)
+#define STM32F7_I2C_OAR1_OA1MODE BIT(10)
+#define STM32F7_I2C_OAR1_OA1_10_MASK GENMASK(9, 0)
+#define STM32F7_I2C_OAR1_OA1_10(n) (((n) & \
+ STM32F7_I2C_OAR1_OA1_10_MASK))
+#define STM32F7_I2C_OAR1_OA1_7_MASK GENMASK(7, 1)
+#define STM32F7_I2C_OAR1_OA1_7(n) (((n) & 0x7f) << 1)
+#define STM32F7_I2C_OAR1_MASK (STM32F7_I2C_OAR1_OA1_7_MASK \
+ | STM32F7_I2C_OAR1_OA1_10_MASK \
+ | STM32F7_I2C_OAR1_OA1EN \
+ | STM32F7_I2C_OAR1_OA1MODE)
+
+/* STM32F7 I2C Own Address 2 */
+#define STM32F7_I2C_OAR2_OA2EN BIT(15)
+#define STM32F7_I2C_OAR2_OA2MSK_MASK GENMASK(10, 8)
+#define STM32F7_I2C_OAR2_OA2MSK(n) (((n) & 0x7) << 8)
+#define STM32F7_I2C_OAR2_OA2_7_MASK GENMASK(7, 1)
+#define STM32F7_I2C_OAR2_OA2_7(n) (((n) & 0x7f) << 1)
+#define STM32F7_I2C_OAR2_MASK (STM32F7_I2C_OAR2_OA2MSK_MASK \
+ | STM32F7_I2C_OAR2_OA2_7_MASK \
+ | STM32F7_I2C_OAR2_OA2EN)
+
+/* STM32F7 I2C Interrupt Status */
+#define STM32F7_I2C_ISR_ADDCODE_MASK GENMASK(23, 17)
+#define STM32F7_I2C_ISR_ADDCODE_GET(n) \
+ (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
+#define STM32F7_I2C_ISR_DIR BIT(16)
+#define STM32F7_I2C_ISR_BUSY BIT(15)
+#define STM32F7_I2C_ISR_PECERR BIT(11)
+#define STM32F7_I2C_ISR_ARLO BIT(9)
+#define STM32F7_I2C_ISR_BERR BIT(8)
+#define STM32F7_I2C_ISR_TCR BIT(7)
+#define STM32F7_I2C_ISR_TC BIT(6)
+#define STM32F7_I2C_ISR_STOPF BIT(5)
+#define STM32F7_I2C_ISR_NACKF BIT(4)
+#define STM32F7_I2C_ISR_ADDR BIT(3)
+#define STM32F7_I2C_ISR_RXNE BIT(2)
+#define STM32F7_I2C_ISR_TXIS BIT(1)
+#define STM32F7_I2C_ISR_TXE BIT(0)
+
+/* STM32F7 I2C Interrupt Clear */
+#define STM32F7_I2C_ICR_PECCF BIT(11)
+#define STM32F7_I2C_ICR_ARLOCF BIT(9)
+#define STM32F7_I2C_ICR_BERRCF BIT(8)
+#define STM32F7_I2C_ICR_STOPCF BIT(5)
+#define STM32F7_I2C_ICR_NACKCF BIT(4)
+#define STM32F7_I2C_ICR_ADDRCF BIT(3)
+
+/* STM32F7 I2C Timing */
+#define STM32F7_I2C_TIMINGR_PRESC(n) (((n) & 0xf) << 28)
+#define STM32F7_I2C_TIMINGR_SCLDEL(n) (((n) & 0xf) << 20)
+#define STM32F7_I2C_TIMINGR_SDADEL(n) (((n) & 0xf) << 16)
+#define STM32F7_I2C_TIMINGR_SCLH(n) (((n) & 0xff) << 8)
+#define STM32F7_I2C_TIMINGR_SCLL(n) ((n) & 0xff)
+
+#define STM32F7_I2C_MAX_LEN 0xff
+#define STM32F7_I2C_DMA_LEN_MIN 0x16
+#define STM32F7_I2C_MAX_SLAVE 0x2
+
+#define STM32F7_I2C_DNF_DEFAULT 0
+#define STM32F7_I2C_DNF_MAX 15
+
+#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1
+#define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
+#define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
+
+#define STM32F7_I2C_RISE_TIME_DEFAULT 25 /* ns */
+#define STM32F7_I2C_FALL_TIME_DEFAULT 10 /* ns */
+
+#define STM32F7_PRESC_MAX BIT(4)
+#define STM32F7_SCLDEL_MAX BIT(4)
+#define STM32F7_SDADEL_MAX BIT(4)
+#define STM32F7_SCLH_MAX BIT(8)
+#define STM32F7_SCLL_MAX BIT(8)
+
+/**
+ * struct stm32f7_i2c_spec - private i2c specification timing
+ * @rate: I2C bus speed (Hz)
+ * @rate_min: 80% of I2C bus speed (Hz)
+ * @rate_max: 100% of I2C bus speed (Hz)
+ * @fall_max: Max fall time of both SDA and SCL signals (ns)
+ * @rise_max: Max rise time of both SDA and SCL signals (ns)
+ * @hddat_min: Min data hold time (ns)
+ * @vddat_max: Max data valid time (ns)
+ * @sudat_min: Min data setup time (ns)
+ * @l_min: Min low period of the SCL clock (ns)
+ * @h_min: Min high period of the SCL clock (ns)
+ */
+struct stm32f7_i2c_spec {
+ u32 rate;
+ u32 rate_min;
+ u32 rate_max;
+ u32 fall_max;
+ u32 rise_max;
+ u32 hddat_min;
+ u32 vddat_max;
+ u32 sudat_min;
+ u32 l_min;
+ u32 h_min;
+};
+
+/**
+ * struct stm32f7_i2c_setup - private I2C timing setup parameters
+ * @speed: I2C speed mode (standard, Fast Plus)
+ * @speed_freq: I2C speed frequency (Hz)
+ * @clock_src: I2C clock source frequency (Hz)
+ * @rise_time: Rise time (ns)
+ * @fall_time: Fall time (ns)
+ * @dnf: Digital filter coefficient (0-16)
+ * @analog_filter: Analog filter delay (On/Off)
+ */
+struct stm32f7_i2c_setup {
+ enum stm32_i2c_speed speed;
+ u32 speed_freq;
+ u32 clock_src;
+ u32 rise_time;
+ u32 fall_time;
+ u8 dnf;
+ bool analog_filter;
+};
+
+/**
+ * struct stm32f7_i2c_timings - private I2C output parameters
+ * @node: List entry
+ * @presc: Prescaler value
+ * @scldel: Data setup time
+ * @sdadel: Data hold time
+ * @sclh: SCL high period (master mode)
+ * @scll: SCL low period (master mode)
+ */
+struct stm32f7_i2c_timings {
+ struct list_head node;
+ u8 presc;
+ u8 scldel;
+ u8 sdadel;
+ u8 sclh;
+ u8 scll;
+};
+
+/**
+ * struct stm32f7_i2c_msg - client specific data
+ * @addr: 8-bit or 10-bit slave addr, including r/w bit
+ * @count: number of bytes to be transferred
+ * @buf: data buffer
+ * @result: result of the transfer
+ * @stop: last I2C msg to be sent, i.e. STOP to be generated
+ * @smbus: boolean to know if the I2C IP is used in SMBus mode
+ * @size: type of SMBus protocol
+ * @read_write: direction of SMBus protocol
+ * SMBus block read and SMBus block write - block read process call protocols
+ * @smbus_buf: buffer to be used for SMBus protocol transfer. It will
+ * contain a maximum of 32 bytes of data + byte command + byte count + PEC
+ * This buffer has to be 32-bit aligned to be compliant with memory address
+ * register in DMA mode.
+ */
+struct stm32f7_i2c_msg {
+ u16 addr;
+ u32 count;
+ u8 *buf;
+ int result;
+ bool stop;
+ bool smbus;
+ int size;
+ char read_write;
+ u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4);
+};
+
+/**
+ * struct stm32f7_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
+ * @clk: hw i2c clock
+ * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+
+ * @msg: Pointer to data to be written
+ * @msg_num: number of I2C messages to be executed
+ * @msg_id: message identifiant
+ * @f7_msg: customized i2c msg for driver usage
+ * @setup: I2C timing input setup
+ * @timing: I2C computed timings
+ * @slave: list of slave devices registered on the I2C bus
+ * @slave_running: slave device currently used
+ * @slave_dir: transfer direction for the current slave device
+ * @master_mode: boolean to know in which mode the I2C is running (master or
+ * slave)
+ * @dma: dma data
+ * @use_dma: boolean to know if dma is used in the current transfer
+ */
+struct stm32f7_i2c_dev {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ struct completion complete;
+ struct clk *clk;
+ int speed;
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int msg_id;
+ struct stm32f7_i2c_msg f7_msg;
+ struct stm32f7_i2c_setup setup;
+ struct stm32f7_i2c_timings timing;
+ struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
+ struct i2c_client *slave_running;
+ u32 slave_dir;
+ bool master_mode;
+ struct stm32_i2c_dma *dma;
+ bool use_dma;
+};
+
+/*
+ * All these values are coming from I2C Specification, Version 6.0, 4th of
+ * April 2014.
+ *
+ * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast,
+ * and Fast-mode Plus I2C-bus devices
+ */
+static struct stm32f7_i2c_spec i2c_specs[] = {
+ [STM32_I2C_SPEED_STANDARD] = {
+ .rate = 100000,
+ .rate_min = 80000,
+ .rate_max = 100000,
+ .fall_max = 300,
+ .rise_max = 1000,
+ .hddat_min = 0,
+ .vddat_max = 3450,
+ .sudat_min = 250,
+ .l_min = 4700,
+ .h_min = 4000,
+ },
+ [STM32_I2C_SPEED_FAST] = {
+ .rate = 400000,
+ .rate_min = 320000,
+ .rate_max = 400000,
+ .fall_max = 300,
+ .rise_max = 300,
+ .hddat_min = 0,
+ .vddat_max = 900,
+ .sudat_min = 100,
+ .l_min = 1300,
+ .h_min = 600,
+ },
+ [STM32_I2C_SPEED_FAST_PLUS] = {
+ .rate = 1000000,
+ .rate_min = 800000,
+ .rate_max = 1000000,
+ .fall_max = 100,
+ .rise_max = 120,
+ .hddat_min = 0,
+ .vddat_max = 450,
+ .sudat_min = 50,
+ .l_min = 500,
+ .h_min = 260,
+ },
+};
+
+static const struct stm32f7_i2c_setup stm32f7_setup = {
+ .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
+ .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
+ .dnf = STM32F7_I2C_DNF_DEFAULT,
+ .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE,
+};
+
+static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) | mask, reg);
+}
+
+static inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) & ~mask, reg);
+}
+
+static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)
+{
+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);
+}
+
+static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
+ struct stm32f7_i2c_setup *setup,
+ struct stm32f7_i2c_timings *output)
+{
+ u32 p_prev = STM32F7_PRESC_MAX;
+ u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
+ setup->clock_src);
+ u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
+ setup->speed_freq);
+ u32 clk_error_prev = i2cbus;
+ u32 tsync;
+ u32 af_delay_min, af_delay_max;
+ u32 dnf_delay;
+ u32 clk_min, clk_max;
+ int sdadel_min, sdadel_max;
+ int scldel_min;
+ struct stm32f7_i2c_timings *v, *_v, *s;
+ struct list_head solutions;
+ u16 p, l, a, h;
+ int ret = 0;
+
+ if (setup->speed >= STM32_I2C_SPEED_END) {
+ dev_err(i2c_dev->dev, "speed out of bound {%d/%d}\n",
+ setup->speed, STM32_I2C_SPEED_END - 1);
+ return -EINVAL;
+ }
+
+ if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
+ (setup->fall_time > i2c_specs[setup->speed].fall_max)) {
+ dev_err(i2c_dev->dev,
+ "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
+ setup->rise_time, i2c_specs[setup->speed].rise_max,
+ setup->fall_time, i2c_specs[setup->speed].fall_max);
+ return -EINVAL;
+ }
+
+ if (setup->dnf > STM32F7_I2C_DNF_MAX) {
+ dev_err(i2c_dev->dev,
+ "DNF out of bound %d/%d\n",
+ setup->dnf, STM32F7_I2C_DNF_MAX);
+ return -EINVAL;
+ }
+
+ if (setup->speed_freq > i2c_specs[setup->speed].rate) {
+ dev_err(i2c_dev->dev, "ERROR: Freq {%d/%d}\n",
+ setup->speed_freq, i2c_specs[setup->speed].rate);
+ return -EINVAL;
+ }
+
+ /* Analog and Digital Filters */
+ af_delay_min =
+ (setup->analog_filter ?
+ STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0);
+ af_delay_max =
+ (setup->analog_filter ?
+ STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
+ dnf_delay = setup->dnf * i2cclk;
+
+ sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
+ af_delay_min - (setup->dnf + 3) * i2cclk;
+
+ sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
+ af_delay_max - (setup->dnf + 4) * i2cclk;
+
+ scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
+
+ if (sdadel_min < 0)
+ sdadel_min = 0;
+ if (sdadel_max < 0)
+ sdadel_max = 0;
+
+ dev_dbg(i2c_dev->dev, "SDADEL(min/max): %i/%i, SCLDEL(Min): %i\n",
+ sdadel_min, sdadel_max, scldel_min);
+
+ INIT_LIST_HEAD(&solutions);
+ /* Compute possible values for PRESC, SCLDEL and SDADEL */
+ for (p = 0; p < STM32F7_PRESC_MAX; p++) {
+ for (l = 0; l < STM32F7_SCLDEL_MAX; l++) {
+ u32 scldel = (l + 1) * (p + 1) * i2cclk;
+
+ if (scldel < scldel_min)
+ continue;
+
+ for (a = 0; a < STM32F7_SDADEL_MAX; a++) {
+ u32 sdadel = (a * (p + 1) + 1) * i2cclk;
+
+ if (((sdadel >= sdadel_min) &&
+ (sdadel <= sdadel_max)) &&
+ (p != p_prev)) {
+ v = kmalloc(sizeof(*v), GFP_KERNEL);
+ if (!v) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ v->presc = p;
+ v->scldel = l;
+ v->sdadel = a;
+ p_prev = p;
+
+ list_add_tail(&v->node,
+ &solutions);
+ }
+ }
+ }
+ }
+
+ if (list_empty(&solutions)) {
+ dev_err(i2c_dev->dev, "no Prescaler solution\n");
+ ret = -EPERM;
+ goto exit;
+ }
+
+ tsync = af_delay_min + dnf_delay + (2 * i2cclk);
+ s = NULL;
+ clk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
+ clk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
+
+ /*
+ * Among Prescaler possibilities discovered above figures out SCL Low
+ * and High Period. Provided:
+ * - SCL Low Period has to be higher than SCL Clock Low Period
+ * defined by I2C Specification. I2C Clock has to be lower than
+ * (SCL Low Period - Analog/Digital filters) / 4.
+ * - SCL High Period has to be lower than SCL Clock High Period
+ * defined by I2C Specification
+ * - I2C Clock has to be lower than SCL High Period
+ */
+ list_for_each_entry(v, &solutions, node) {
+ u32 prescaler = (v->presc + 1) * i2cclk;
+
+ for (l = 0; l < STM32F7_SCLL_MAX; l++) {
+ u32 tscl_l = (l + 1) * prescaler + tsync;
+
+ if ((tscl_l < i2c_specs[setup->speed].l_min) ||
+ (i2cclk >=
+ ((tscl_l - af_delay_min - dnf_delay) / 4))) {
+ continue;
+ }
+
+ for (h = 0; h < STM32F7_SCLH_MAX; h++) {
+ u32 tscl_h = (h + 1) * prescaler + tsync;
+ u32 tscl = tscl_l + tscl_h +
+ setup->rise_time + setup->fall_time;
+
+ if ((tscl >= clk_min) && (tscl <= clk_max) &&
+ (tscl_h >= i2c_specs[setup->speed].h_min) &&
+ (i2cclk < tscl_h)) {
+ int clk_error = tscl - i2cbus;
+
+ if (clk_error < 0)
+ clk_error = -clk_error;
+
+ if (clk_error < clk_error_prev) {
+ clk_error_prev = clk_error;
+ v->scll = l;
+ v->sclh = h;
+ s = v;
+ }
+ }
+ }
+ }
+ }
+
+ if (!s) {
+ dev_err(i2c_dev->dev, "no solution at all\n");
+ ret = -EPERM;
+ goto exit;
+ }
+
+ output->presc = s->presc;
+ output->scldel = s->scldel;
+ output->sdadel = s->sdadel;
+ output->scll = s->scll;
+ output->sclh = s->sclh;
+
+ dev_dbg(i2c_dev->dev,
+ "Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n",
+ output->presc,
+ output->scldel, output->sdadel,
+ output->scll, output->sclh);
+
+exit:
+ /* Release list and memory */
+ list_for_each_entry_safe(v, _v, &solutions, node) {
+ list_del(&v->node);
+ kfree(v);
+ }
+
+ return ret;
+}
+
+static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
+ struct stm32f7_i2c_setup *setup)
+{
+ int ret = 0;
+
+ setup->speed = i2c_dev->speed;
+ setup->speed_freq = i2c_specs[setup->speed].rate;
+ setup->clock_src = clk_get_rate(i2c_dev->clk);
+
+ if (!setup->clock_src) {
+ dev_err(i2c_dev->dev, "clock rate is 0\n");
+ return -EINVAL;
+ }
+
+ do {
+ ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
+ &i2c_dev->timing);
+ if (ret) {
+ dev_err(i2c_dev->dev,
+ "failed to compute I2C timings.\n");
+ if (i2c_dev->speed > STM32_I2C_SPEED_STANDARD) {
+ i2c_dev->speed--;
+ setup->speed = i2c_dev->speed;
+ setup->speed_freq =
+ i2c_specs[setup->speed].rate;
+ dev_warn(i2c_dev->dev,
+ "downgrade I2C Speed Freq to (%i)\n",
+ i2c_specs[setup->speed].rate);
+ } else {
+ break;
+ }
+ }
+ } while (ret);
+
+ if (ret) {
+ dev_err(i2c_dev->dev, "Impossible to compute I2C timings.\n");
+ return ret;
+ }
+
+ dev_dbg(i2c_dev->dev, "I2C Speed(%i), Freq(%i), Clk Source(%i)\n",
+ setup->speed, setup->speed_freq, setup->clock_src);
+ dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
+ setup->rise_time, setup->fall_time);
+ dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
+ (setup->analog_filter ? "On" : "Off"), setup->dnf);
+
+ return 0;
+}
+
+static void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev)
+{
+ void __iomem *base = i2c_dev->base;
+ u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN;
+
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
+}
+
+static void stm32f7_i2c_dma_callback(void *arg)
+{
+ struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
+ struct device *dev = dma->chan_using->device->dev;
+
+ stm32f7_i2c_disable_dma_req(i2c_dev);
+ dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir);
+ complete(&dma->dma_complete);
+}
+
+static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_timings *t = &i2c_dev->timing;
+ u32 timing = 0;
+
+ /* Timing settings */
+ timing |= STM32F7_I2C_TIMINGR_PRESC(t->presc);
+ timing |= STM32F7_I2C_TIMINGR_SCLDEL(t->scldel);
+ timing |= STM32F7_I2C_TIMINGR_SDADEL(t->sdadel);
+ timing |= STM32F7_I2C_TIMINGR_SCLH(t->sclh);
+ timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll);
+ writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR);
+
+ /* Enable I2C */
+ if (i2c_dev->setup.analog_filter)
+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_ANFOFF);
+ else
+ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_ANFOFF);
+
+ /* Program the Digital Filter */
+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_DNF_MASK);
+ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf));
+
+ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_PE);
+}
+
+static void stm32f7_i2c_write_tx_data(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ void __iomem *base = i2c_dev->base;
+
+ if (f7_msg->count) {
+ writeb_relaxed(*f7_msg->buf++, base + STM32F7_I2C_TXDR);
+ f7_msg->count--;
+ }
+}
+
+static void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ void __iomem *base = i2c_dev->base;
+
+ if (f7_msg->count) {
+ *f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR);
+ f7_msg->count--;
+ } else {
+ /* Flush RX buffer has no data is expected */
+ readb_relaxed(base + STM32F7_I2C_RXDR);
+ }
+}
+
+static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ u32 cr2;
+
+ if (i2c_dev->use_dma)
+ f7_msg->count -= STM32F7_I2C_MAX_LEN;
+
+ cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
+
+ cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK;
+ if (f7_msg->count > STM32F7_I2C_MAX_LEN) {
+ cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);
+ } else {
+ cr2 &= ~STM32F7_I2C_CR2_RELOAD;
+ cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+ }
+
+ writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
+}
+
+static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ u32 cr2;
+ u8 *val;
+
+ /*
+ * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first
+ * data received inform us how many data will follow.
+ */
+ stm32f7_i2c_read_rx_data(i2c_dev);
+
+ /*
+ * Update NBYTES with the value read to continue the transfer
+ */
+ val = f7_msg->buf - sizeof(u8);
+ f7_msg->count = *val;
+ cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
+ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
+ cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+ writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
+}
+
+static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap)
+{
+ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+
+ dev_info(i2c_dev->dev, "Trying to recover bus\n");
+
+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_PE);
+
+ stm32f7_i2c_hw_config(i2c_dev);
+
+ return 0;
+}
+
+static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev)
+{
+ u32 status;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F7_I2C_ISR,
+ status,
+ !(status & STM32F7_I2C_ISR_BUSY),
+ 10, 1000);
+ if (!ret)
+ return 0;
+
+ dev_info(i2c_dev->dev, "bus busy\n");
+
+ ret = stm32f7_i2c_release_bus(&i2c_dev->adap);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
+ return ret;
+ }
+
+ return -EBUSY;
+}
+
+static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
+ struct i2c_msg *msg)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ void __iomem *base = i2c_dev->base;
+ u32 cr1, cr2;
+ int ret;
+
+ f7_msg->addr = msg->addr;
+ f7_msg->buf = msg->buf;
+ f7_msg->count = msg->len;
+ f7_msg->result = 0;
+ f7_msg->stop = (i2c_dev->msg_id >= i2c_dev->msg_num - 1);
+
+ reinit_completion(&i2c_dev->complete);
+
+ cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
+ cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
+
+ /* Set transfer direction */
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ if (msg->flags & I2C_M_RD)
+ cr2 |= STM32F7_I2C_CR2_RD_WRN;
+
+ /* Set slave address */
+ cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10);
+ if (msg->flags & I2C_M_TEN) {
+ cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK;
+ cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr);
+ cr2 |= STM32F7_I2C_CR2_ADD10;
+ } else {
+ cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK;
+ cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
+ }
+
+ /* Set nb bytes to transfer and reload if needed */
+ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
+ if (f7_msg->count > STM32F7_I2C_MAX_LEN) {
+ cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);
+ cr2 |= STM32F7_I2C_CR2_RELOAD;
+ } else {
+ cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+ }
+
+ /* Enable NACK, STOP, error and transfer complete interrupts */
+ cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
+ STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
+
+ /* Clear DMA req and TX/RX interrupt */
+ cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
+ STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
+
+ /* Configure DMA or enable RX/TX interrupt */
+ i2c_dev->use_dma = false;
+ if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
+ ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
+ msg->flags & I2C_M_RD,
+ f7_msg->count, f7_msg->buf,
+ stm32f7_i2c_dma_callback,
+ i2c_dev);
+ if (!ret)
+ i2c_dev->use_dma = true;
+ else
+ dev_warn(i2c_dev->dev, "can't use DMA\n");
+ }
+
+ if (!i2c_dev->use_dma) {
+ if (msg->flags & I2C_M_RD)
+ cr1 |= STM32F7_I2C_CR1_RXIE;
+ else
+ cr1 |= STM32F7_I2C_CR1_TXIE;
+ } else {
+ if (msg->flags & I2C_M_RD)
+ cr1 |= STM32F7_I2C_CR1_RXDMAEN;
+ else
+ cr1 |= STM32F7_I2C_CR1_TXDMAEN;
+ }
+
+ /* Configure Start/Repeated Start */
+ cr2 |= STM32F7_I2C_CR2_START;
+
+ i2c_dev->master_mode = true;
+
+ /* Write configurations registers */
+ writel_relaxed(cr1, base + STM32F7_I2C_CR1);
+ writel_relaxed(cr2, base + STM32F7_I2C_CR2);
+}
+
+static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
+ unsigned short flags, u8 command,
+ union i2c_smbus_data *data)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ struct device *dev = i2c_dev->dev;
+ void __iomem *base = i2c_dev->base;
+ u32 cr1, cr2;
+ int i, ret;
+
+ f7_msg->result = 0;
+ reinit_completion(&i2c_dev->complete);
+
+ cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
+ cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
+
+ /* Set transfer direction */
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ if (f7_msg->read_write)
+ cr2 |= STM32F7_I2C_CR2_RD_WRN;
+
+ /* Set slave address */
+ cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK);
+ cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
+
+ f7_msg->smbus_buf[0] = command;
+ switch (f7_msg->size) {
+ case I2C_SMBUS_QUICK:
+ f7_msg->stop = true;
+ f7_msg->count = 0;
+ break;
+ case I2C_SMBUS_BYTE:
+ f7_msg->stop = true;
+ f7_msg->count = 1;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (f7_msg->read_write) {
+ f7_msg->stop = false;
+ f7_msg->count = 1;
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ } else {
+ f7_msg->stop = true;
+ f7_msg->count = 2;
+ f7_msg->smbus_buf[1] = data->byte;
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (f7_msg->read_write) {
+ f7_msg->stop = false;
+ f7_msg->count = 1;
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ } else {
+ f7_msg->stop = true;
+ f7_msg->count = 3;
+ f7_msg->smbus_buf[1] = data->word & 0xff;
+ f7_msg->smbus_buf[2] = data->word >> 8;
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (f7_msg->read_write) {
+ f7_msg->stop = false;
+ f7_msg->count = 1;
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ } else {
+ f7_msg->stop = true;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX ||
+ !data->block[0]) {
+ dev_err(dev, "Invalid block write size %d\n",
+ data->block[0]);
+ return -EINVAL;
+ }
+ f7_msg->count = data->block[0] + 2;
+ for (i = 1; i < f7_msg->count; i++)
+ f7_msg->smbus_buf[i] = data->block[i - 1];
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ f7_msg->stop = false;
+ f7_msg->count = 3;
+ f7_msg->smbus_buf[1] = data->word & 0xff;
+ f7_msg->smbus_buf[2] = data->word >> 8;
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ f7_msg->read_write = I2C_SMBUS_READ;
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ f7_msg->stop = false;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) {
+ dev_err(dev, "Invalid block write size %d\n",
+ data->block[0]);
+ return -EINVAL;
+ }
+ f7_msg->count = data->block[0] + 2;
+ for (i = 1; i < f7_msg->count; i++)
+ f7_msg->smbus_buf[i] = data->block[i - 1];
+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+ f7_msg->read_write = I2C_SMBUS_READ;
+ break;
+ default:
+ dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
+ return -EOPNOTSUPP;
+ }
+
+ f7_msg->buf = f7_msg->smbus_buf;
+
+ /* Configure PEC */
+ if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
+ cr1 |= STM32F7_I2C_CR1_PECEN;
+ cr2 |= STM32F7_I2C_CR2_PECBYTE;
+ if (!f7_msg->read_write)
+ f7_msg->count++;
+ } else {
+ cr1 &= ~STM32F7_I2C_CR1_PECEN;
+ cr2 &= ~STM32F7_I2C_CR2_PECBYTE;
+ }
+
+ /* Set number of bytes to be transferred */
+ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
+ cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+
+ /* Enable NACK, STOP, error and transfer complete interrupts */
+ cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
+ STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
+
+ /* Clear DMA req and TX/RX interrupt */
+ cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
+ STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
+
+ /* Configure DMA or enable RX/TX interrupt */
+ i2c_dev->use_dma = false;
+ if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
+ ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
+ cr2 & STM32F7_I2C_CR2_RD_WRN,
+ f7_msg->count, f7_msg->buf,
+ stm32f7_i2c_dma_callback,
+ i2c_dev);
+ if (!ret)
+ i2c_dev->use_dma = true;
+ else
+ dev_warn(i2c_dev->dev, "can't use DMA\n");
+ }
+
+ if (!i2c_dev->use_dma) {
+ if (cr2 & STM32F7_I2C_CR2_RD_WRN)
+ cr1 |= STM32F7_I2C_CR1_RXIE;
+ else
+ cr1 |= STM32F7_I2C_CR1_TXIE;
+ } else {
+ if (cr2 & STM32F7_I2C_CR2_RD_WRN)
+ cr1 |= STM32F7_I2C_CR1_RXDMAEN;
+ else
+ cr1 |= STM32F7_I2C_CR1_TXDMAEN;
+ }
+
+ /* Set Start bit */
+ cr2 |= STM32F7_I2C_CR2_START;
+
+ i2c_dev->master_mode = true;
+
+ /* Write configurations registers */
+ writel_relaxed(cr1, base + STM32F7_I2C_CR1);
+ writel_relaxed(cr2, base + STM32F7_I2C_CR2);
+
+ return 0;
+}
+
+static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ void __iomem *base = i2c_dev->base;
+ u32 cr1, cr2;
+ int ret;
+
+ cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
+ cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
+
+ /* Set transfer direction */
+ cr2 |= STM32F7_I2C_CR2_RD_WRN;
+
+ switch (f7_msg->size) {
+ case I2C_SMBUS_BYTE_DATA:
+ f7_msg->count = 1;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ f7_msg->count = 2;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ f7_msg->count = 1;
+ cr2 |= STM32F7_I2C_CR2_RELOAD;
+ break;
+ }
+
+ f7_msg->buf = f7_msg->smbus_buf;
+ f7_msg->stop = true;
+
+ /* Add one byte for PEC if needed */
+ if (cr1 & STM32F7_I2C_CR1_PECEN)
+ f7_msg->count++;
+
+ /* Set number of bytes to be transferred */
+ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);
+ cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+
+ /*
+ * Configure RX/TX interrupt:
+ */
+ cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE);
+ cr1 |= STM32F7_I2C_CR1_RXIE;
+
+ /*
+ * Configure DMA or enable RX/TX interrupt:
+ * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use
+ * dma as we don't know in advance how many data will be received
+ */
+ cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
+ STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
+
+ i2c_dev->use_dma = false;
+ if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN &&
+ f7_msg->size != I2C_SMBUS_BLOCK_DATA &&
+ f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) {
+ ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
+ cr2 & STM32F7_I2C_CR2_RD_WRN,
+ f7_msg->count, f7_msg->buf,
+ stm32f7_i2c_dma_callback,
+ i2c_dev);
+
+ if (!ret)
+ i2c_dev->use_dma = true;
+ else
+ dev_warn(i2c_dev->dev, "can't use DMA\n");
+ }
+
+ if (!i2c_dev->use_dma)
+ cr1 |= STM32F7_I2C_CR1_RXIE;
+ else
+ cr1 |= STM32F7_I2C_CR1_RXDMAEN;
+
+ /* Configure Repeated Start */
+ cr2 |= STM32F7_I2C_CR2_START;
+
+ /* Write configurations registers */
+ writel_relaxed(cr1, base + STM32F7_I2C_CR1);
+ writel_relaxed(cr2, base + STM32F7_I2C_CR2);
+}
+
+static int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ u8 count, internal_pec, received_pec;
+
+ internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
+
+ switch (f7_msg->size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ received_pec = f7_msg->smbus_buf[1];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ received_pec = f7_msg->smbus_buf[2];
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ count = f7_msg->smbus_buf[0];
+ received_pec = f7_msg->smbus_buf[count];
+ break;
+ default:
+ dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n");
+ return -EINVAL;
+ }
+
+ if (internal_pec != received_pec) {
+ dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n",
+ internal_pec, received_pec);
+ return -EBADMSG;
+ }
+
+ return 0;
+}
+
+static bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode)
+{
+ u32 addr;
+
+ if (!slave)
+ return false;
+
+ if (slave->flags & I2C_CLIENT_TEN) {
+ /*
+ * For 10-bit addr, addcode = 11110XY with
+ * X = Bit 9 of slave address
+ * Y = Bit 8 of slave address
+ */
+ addr = slave->addr >> 8;
+ addr |= 0x78;
+ if (addr == addcode)
+ return true;
+ } else {
+ addr = slave->addr & 0x7f;
+ if (addr == addcode)
+ return true;
+ }
+
+ return false;
+}
+
+static void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct i2c_client *slave = i2c_dev->slave_running;
+ void __iomem *base = i2c_dev->base;
+ u32 mask;
+ u8 value = 0;
+
+ if (i2c_dev->slave_dir) {
+ /* Notify i2c slave that new read transfer is starting */
+ i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
+
+ /*
+ * Disable slave TX config in case of I2C combined message
+ * (I2C Write followed by I2C Read)
+ */
+ mask = STM32F7_I2C_CR2_RELOAD;
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask);
+ mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
+ STM32F7_I2C_CR1_TCIE;
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
+
+ /* Enable TX empty, STOP, NACK interrupts */
+ mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
+ STM32F7_I2C_CR1_TXIE;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+
+ /* Write 1st data byte */
+ writel_relaxed(value, base + STM32F7_I2C_TXDR);
+ } else {
+ /* Notify i2c slave that new write transfer is starting */
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+
+ /* Set reload mode to be able to ACK/NACK each received byte */
+ mask = STM32F7_I2C_CR2_RELOAD;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
+
+ /*
+ * Set STOP, NACK, RX empty and transfer complete interrupts.*
+ * Set Slave Byte Control to be able to ACK/NACK each data
+ * byte received
+ */
+ mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
+ STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
+ STM32F7_I2C_CR1_TCIE;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+ }
+}
+
+static void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev)
+{
+ void __iomem *base = i2c_dev->base;
+ u32 isr, addcode, dir, mask;
+ int i;
+
+ isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+ addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr);
+ dir = isr & STM32F7_I2C_ISR_DIR;
+
+ for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+ if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) {
+ i2c_dev->slave_running = i2c_dev->slave[i];
+ i2c_dev->slave_dir = dir;
+
+ /* Start I2C slave processing */
+ stm32f7_i2c_slave_start(i2c_dev);
+
+ /* Clear ADDR flag */
+ mask = STM32F7_I2C_ICR_ADDRCF;
+ writel_relaxed(mask, base + STM32F7_I2C_ICR);
+ break;
+ }
+ }
+}
+
+static int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev,
+ struct i2c_client *slave, int *id)
+{
+ int i;
+
+ for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+ if (i2c_dev->slave[i] == slave) {
+ *id = i;
+ return 0;
+ }
+ }
+
+ dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr);
+
+ return -ENODEV;
+}
+
+static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
+ struct i2c_client *slave, int *id)
+{
+ struct device *dev = i2c_dev->dev;
+ int i;
+
+ /*
+ * slave[0] supports 7-bit and 10-bit slave address
+ * slave[1] supports 7-bit slave address only
+ */
+ for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) {
+ if (i == 1 && (slave->flags & I2C_CLIENT_TEN))
+ continue;
+ if (!i2c_dev->slave[i]) {
+ *id = i;
+ return 0;
+ }
+ }
+
+ dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr);
+
+ return -EINVAL;
+}
+
+static bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev)
+{
+ int i;
+
+ for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+ if (i2c_dev->slave[i])
+ return true;
+ }
+
+ return false;
+}
+
+static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev)
+{
+ int i, busy;
+
+ busy = 0;
+ for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+ if (i2c_dev->slave[i])
+ busy++;
+ }
+
+ return i == busy;
+}
+
+static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
+{
+ void __iomem *base = i2c_dev->base;
+ u32 cr2, status, mask;
+ u8 val;
+ int ret;
+
+ status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+
+ /* Slave transmitter mode */
+ if (status & STM32F7_I2C_ISR_TXIS) {
+ i2c_slave_event(i2c_dev->slave_running,
+ I2C_SLAVE_READ_PROCESSED,
+ &val);
+
+ /* Write data byte */
+ writel_relaxed(val, base + STM32F7_I2C_TXDR);
+ }
+
+ /* Transfer Complete Reload for Slave receiver mode */
+ if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) {
+ /*
+ * Read data byte then set NBYTES to receive next byte or NACK
+ * the current received byte
+ */
+ val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR);
+ ret = i2c_slave_event(i2c_dev->slave_running,
+ I2C_SLAVE_WRITE_RECEIVED,
+ &val);
+ if (!ret) {
+ cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
+ cr2 |= STM32F7_I2C_CR2_NBYTES(1);
+ writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
+ } else {
+ mask = STM32F7_I2C_CR2_NACK;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
+ }
+ }
+
+ /* NACK received */
+ if (status & STM32F7_I2C_ISR_NACKF) {
+ dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
+ }
+
+ /* STOP received */
+ if (status & STM32F7_I2C_ISR_STOPF) {
+ /* Disable interrupts */
+ stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK);
+
+ if (i2c_dev->slave_dir) {
+ /*
+ * Flush TX buffer in order to not used the byte in
+ * TXDR for the next transfer
+ */
+ mask = STM32F7_I2C_ISR_TXE;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask);
+ }
+
+ /* Clear STOP flag */
+ writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
+
+ /* Notify i2c slave that a STOP flag has been detected */
+ i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val);
+
+ i2c_dev->slave_running = NULL;
+ }
+
+ /* Address match received */
+ if (status & STM32F7_I2C_ISR_ADDR)
+ stm32f7_i2c_slave_addr(i2c_dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
+{
+ struct stm32f7_i2c_dev *i2c_dev = data;
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
+ void __iomem *base = i2c_dev->base;
+ u32 status, mask;
+ int ret = IRQ_HANDLED;
+
+ /* Check if the interrupt if for a slave device */
+ if (!i2c_dev->master_mode) {
+ ret = stm32f7_i2c_slave_isr_event(i2c_dev);
+ return ret;
+ }
+
+ status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+
+ /* Tx empty */
+ if (status & STM32F7_I2C_ISR_TXIS)
+ stm32f7_i2c_write_tx_data(i2c_dev);
+
+ /* RX not empty */
+ if (status & STM32F7_I2C_ISR_RXNE)
+ stm32f7_i2c_read_rx_data(i2c_dev);
+
+ /* NACK received */
+ if (status & STM32F7_I2C_ISR_NACKF) {
+ dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
+ if (i2c_dev->use_dma) {
+ stm32f7_i2c_disable_dma_req(i2c_dev);
+ dmaengine_terminate_all(dma->chan_using);
+ }
+ f7_msg->result = -ENXIO;
+ }
+
+ /* STOP detection flag */
+ if (status & STM32F7_I2C_ISR_STOPF) {
+ /* Disable interrupts */
+ if (stm32f7_i2c_is_slave_registered(i2c_dev))
+ mask = STM32F7_I2C_XFER_IRQ_MASK;
+ else
+ mask = STM32F7_I2C_ALL_IRQ_MASK;
+ stm32f7_i2c_disable_irq(i2c_dev, mask);
+
+ /* Clear STOP flag */
+ writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
+
+ if (i2c_dev->use_dma && !f7_msg->result) {
+ ret = IRQ_WAKE_THREAD;
+ } else {
+ i2c_dev->master_mode = false;
+ complete(&i2c_dev->complete);
+ }
+ }
+
+ /* Transfer complete */
+ if (status & STM32F7_I2C_ISR_TC) {
+ if (f7_msg->stop) {
+ mask = STM32F7_I2C_CR2_STOP;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
+ } else if (i2c_dev->use_dma && !f7_msg->result) {
+ ret = IRQ_WAKE_THREAD;
+ } else if (f7_msg->smbus) {
+ stm32f7_i2c_smbus_rep_start(i2c_dev);
+ } else {
+ i2c_dev->msg_id++;
+ i2c_dev->msg++;
+ stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
+ }
+ }
+
+ if (status & STM32F7_I2C_ISR_TCR) {
+ if (f7_msg->smbus)
+ stm32f7_i2c_smbus_reload(i2c_dev);
+ else
+ stm32f7_i2c_reload(i2c_dev);
+ }
+
+ return ret;
+}
+
+static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data)
+{
+ struct stm32f7_i2c_dev *i2c_dev = data;
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
+ u32 status;
+ int ret;
+
+ /*
+ * Wait for dma transfer completion before sending next message or
+ * notity the end of xfer to the client
+ */
+ ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ);
+ if (!ret) {
+ dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__);
+ stm32f7_i2c_disable_dma_req(i2c_dev);
+ dmaengine_terminate_all(dma->chan_using);
+ f7_msg->result = -ETIMEDOUT;
+ }
+
+ status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+
+ if (status & STM32F7_I2C_ISR_TC) {
+ if (f7_msg->smbus) {
+ stm32f7_i2c_smbus_rep_start(i2c_dev);
+ } else {
+ i2c_dev->msg_id++;
+ i2c_dev->msg++;
+ stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
+ }
+ } else {
+ i2c_dev->master_mode = false;
+ complete(&i2c_dev->complete);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
+{
+ struct stm32f7_i2c_dev *i2c_dev = data;
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ void __iomem *base = i2c_dev->base;
+ struct device *dev = i2c_dev->dev;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
+ u32 status;
+
+ status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+
+ /* Bus error */
+ if (status & STM32F7_I2C_ISR_BERR) {
+ dev_err(dev, "<%s>: Bus error\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);
+ stm32f7_i2c_release_bus(&i2c_dev->adap);
+ f7_msg->result = -EIO;
+ }
+
+ /* Arbitration loss */
+ if (status & STM32F7_I2C_ISR_ARLO) {
+ dev_dbg(dev, "<%s>: Arbitration loss\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR);
+ f7_msg->result = -EAGAIN;
+ }
+
+ if (status & STM32F7_I2C_ISR_PECERR) {
+ dev_err(dev, "<%s>: PEC error in reception\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR);
+ f7_msg->result = -EINVAL;
+ }
+
+ if (!i2c_dev->slave_running) {
+ u32 mask;
+ /* Disable interrupts */
+ if (stm32f7_i2c_is_slave_registered(i2c_dev))
+ mask = STM32F7_I2C_XFER_IRQ_MASK;
+ else
+ mask = STM32F7_I2C_ALL_IRQ_MASK;
+ stm32f7_i2c_disable_irq(i2c_dev, mask);
+ }
+
+ /* Disable dma */
+ if (i2c_dev->use_dma) {
+ stm32f7_i2c_disable_dma_req(i2c_dev);
+ dmaengine_terminate_all(dma->chan_using);
+ }
+
+ i2c_dev->master_mode = false;
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
+ unsigned long time_left;
+ int ret;
+
+ i2c_dev->msg = msgs;
+ i2c_dev->msg_num = num;
+ i2c_dev->msg_id = 0;
+ f7_msg->smbus = false;
+
+ ret = clk_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ ret = stm32f7_i2c_wait_free_bus(i2c_dev);
+ if (ret)
+ goto clk_free;
+
+ stm32f7_i2c_xfer_msg(i2c_dev, msgs);
+
+ time_left = wait_for_completion_timeout(&i2c_dev->complete,
+ i2c_dev->adap.timeout);
+ ret = f7_msg->result;
+
+ if (!time_left) {
+ dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n",
+ i2c_dev->msg->addr);
+ if (i2c_dev->use_dma)
+ dmaengine_terminate_all(dma->chan_using);
+ stm32f7_i2c_wait_free_bus(i2c_dev);
+ ret = -ETIMEDOUT;
+ }
+
+clk_free:
+ clk_disable(i2c_dev->clk);
+
+ return (ret < 0) ? ret : num;
+}
+
+static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter);
+ struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
+ struct device *dev = i2c_dev->dev;
+ unsigned long timeout;
+ int i, ret;
+
+ f7_msg->addr = addr;
+ f7_msg->size = size;
+ f7_msg->read_write = read_write;
+ f7_msg->smbus = true;
+
+ ret = clk_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ ret = stm32f7_i2c_wait_free_bus(i2c_dev);
+ if (ret)
+ goto clk_free;
+
+ ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
+ if (ret)
+ goto clk_free;
+
+ timeout = wait_for_completion_timeout(&i2c_dev->complete,
+ i2c_dev->adap.timeout);
+ ret = f7_msg->result;
+ if (ret)
+ goto clk_free;
+
+ if (!timeout) {
+ dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
+ if (i2c_dev->use_dma)
+ dmaengine_terminate_all(dma->chan_using);
+ stm32f7_i2c_wait_free_bus(i2c_dev);
+ ret = -ETIMEDOUT;
+ goto clk_free;
+ }
+
+ /* Check PEC */
+ if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
+ ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
+ if (ret)
+ goto clk_free;
+ }
+
+ if (read_write && size != I2C_SMBUS_QUICK) {
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = f7_msg->smbus_buf[0];
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = f7_msg->smbus_buf[0] |
+ (f7_msg->smbus_buf[1] << 8);
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ for (i = 0; i <= f7_msg->smbus_buf[0]; i++)
+ data->block[i] = f7_msg->smbus_buf[i];
+ break;
+ default:
+ dev_err(dev, "Unsupported smbus transaction\n");
+ ret = -EINVAL;
+ }
+ }
+
+clk_free:
+ clk_disable(i2c_dev->clk);
+ return ret;
+}
+
+static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
+{
+ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
+ void __iomem *base = i2c_dev->base;
+ struct device *dev = i2c_dev->dev;
+ u32 oar1, oar2, mask;
+ int id, ret;
+
+ if (slave->flags & I2C_CLIENT_PEC) {
+ dev_err(dev, "SMBus PEC not supported in slave mode\n");
+ return -EINVAL;
+ }
+
+ if (stm32f7_i2c_is_slave_busy(i2c_dev)) {
+ dev_err(dev, "Too much slave registered\n");
+ return -EBUSY;
+ }
+
+ ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id);
+ if (ret)
+ return ret;
+
+ if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
+ ret = clk_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock\n");
+ return ret;
+ }
+ }
+
+ if (id == 0) {
+ /* Configure Own Address 1 */
+ oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
+ oar1 &= ~STM32F7_I2C_OAR1_MASK;
+ if (slave->flags & I2C_CLIENT_TEN) {
+ oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr);
+ oar1 |= STM32F7_I2C_OAR1_OA1MODE;
+ } else {
+ oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr);
+ }
+ oar1 |= STM32F7_I2C_OAR1_OA1EN;
+ i2c_dev->slave[id] = slave;
+ writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1);
+ } else if (id == 1) {
+ /* Configure Own Address 2 */
+ oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
+ oar2 &= ~STM32F7_I2C_OAR2_MASK;
+ if (slave->flags & I2C_CLIENT_TEN) {
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
+ oar2 |= STM32F7_I2C_OAR2_OA2EN;
+ i2c_dev->slave[id] = slave;
+ writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
+ } else {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ /* Enable ACK */
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK);
+
+ /* Enable Address match interrupt, error interrupt and enable I2C */
+ mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE |
+ STM32F7_I2C_CR1_PE;
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+
+ return 0;
+
+exit:
+ if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
+ clk_disable(i2c_dev->clk);
+
+ return ret;
+}
+
+static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
+{
+ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
+ void __iomem *base = i2c_dev->base;
+ u32 mask;
+ int id, ret;
+
+ ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id);
+ if (ret)
+ return ret;
+
+ WARN_ON(!i2c_dev->slave[id]);
+
+ if (id == 0) {
+ mask = STM32F7_I2C_OAR1_OA1EN;
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
+ } else {
+ mask = STM32F7_I2C_OAR2_OA2EN;
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask);
+ }
+
+ i2c_dev->slave[id] = NULL;
+
+ if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
+ stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
+ clk_disable(i2c_dev->clk);
+ }
+
+ return 0;
+}
+
+static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
+ I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC;
+}
+
+static struct i2c_algorithm stm32f7_i2c_algo = {
+ .master_xfer = stm32f7_i2c_xfer,
+ .smbus_xfer = stm32f7_i2c_smbus_xfer,
+ .functionality = stm32f7_i2c_func,
+ .reg_slave = stm32f7_i2c_reg_slave,
+ .unreg_slave = stm32f7_i2c_unreg_slave,
+};
+
+static int stm32f7_i2c_probe(struct platform_device *pdev)
+{
+ struct stm32f7_i2c_dev *i2c_dev;
+ const struct stm32f7_i2c_setup *setup;
+ struct resource *res;
+ u32 clk_rate, rise_time, fall_time;
+ struct i2c_adapter *adap;
+ struct reset_control *rst;
+ dma_addr_t phy_addr;
+ int irq_error, irq_event, 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);
+ phy_addr = (dma_addr_t)res->start;
+
+ irq_event = platform_get_irq(pdev, 0);
+ if (irq_event <= 0) {
+ if (irq_event != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ event: %d\n",
+ irq_event);
+ return irq_event ? : -ENOENT;
+ }
+
+ irq_error = platform_get_irq(pdev, 1);
+ if (irq_error <= 0) {
+ if (irq_error != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ error: %d\n",
+ irq_error);
+ return irq_error ? : -ENOENT;
+ }
+
+ i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_err(&pdev->dev, "Error: Missing controller clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
+ return ret;
+ }
+
+ i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency",
+ &clk_rate);
+ if (!ret && clk_rate >= 1000000)
+ i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;
+ else if (!ret && clk_rate >= 400000)
+ i2c_dev->speed = STM32_I2C_SPEED_FAST;
+ else if (!ret && clk_rate >= 100000)
+ i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
+
+ rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(rst)) {
+ dev_err(&pdev->dev, "Error: Missing controller reset\n");
+ ret = PTR_ERR(rst);
+ goto clk_free;
+ }
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+
+ i2c_dev->dev = &pdev->dev;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq_event,
+ stm32f7_i2c_isr_event,
+ stm32f7_i2c_isr_event_thread,
+ IRQF_ONESHOT,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq event %i\n",
+ irq_event);
+ goto clk_free;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq error %i\n",
+ irq_error);
+ goto clk_free;
+ }
+
+ setup = of_device_get_match_data(&pdev->dev);
+ if (!setup) {
+ dev_err(&pdev->dev, "Can't get device data\n");
+ ret = -ENODEV;
+ goto clk_free;
+ }
+ i2c_dev->setup = *setup;
+
+ ret = device_property_read_u32(i2c_dev->dev, "i2c-scl-rising-time-ns",
+ &rise_time);
+ if (!ret)
+ i2c_dev->setup.rise_time = rise_time;
+
+ ret = device_property_read_u32(i2c_dev->dev, "i2c-scl-falling-time-ns",
+ &fall_time);
+ if (!ret)
+ i2c_dev->setup.fall_time = fall_time;
+
+ ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup);
+ if (ret)
+ goto clk_free;
+
+ stm32f7_i2c_hw_config(i2c_dev);
+
+ adap = &i2c_dev->adap;
+ i2c_set_adapdata(adap, i2c_dev);
+ snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
+ &res->start);
+ adap->owner = THIS_MODULE;
+ adap->timeout = 2 * HZ;
+ adap->retries = 3;
+ adap->algo = &stm32f7_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ init_completion(&i2c_dev->complete);
+
+ /* Init DMA config if supported */
+ i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
+ STM32F7_I2C_TXDR,
+ STM32F7_I2C_RXDR);
+ if (PTR_ERR(i2c_dev->dma) == -ENODEV)
+ i2c_dev->dma = NULL;
+ else if (IS_ERR(i2c_dev->dma)) {
+ ret = PTR_ERR(i2c_dev->dma);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Failed to request dma error %i\n", ret);
+ goto clk_free;
+ }
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ goto clk_free;
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ clk_disable(i2c_dev->clk);
+
+ dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
+
+ return 0;
+
+clk_free:
+ clk_disable_unprepare(i2c_dev->clk);
+
+ return ret;
+}
+
+static int stm32f7_i2c_remove(struct platform_device *pdev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ if (i2c_dev->dma) {
+ stm32_i2c_dma_free(i2c_dev->dma);
+ i2c_dev->dma = NULL;
+ }
+
+ i2c_del_adapter(&i2c_dev->adap);
+
+ clk_unprepare(i2c_dev->clk);
+
+ return 0;
+}
+
+static const struct of_device_id stm32f7_i2c_match[] = {
+ { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32f7_i2c_match);
+
+static struct platform_driver stm32f7_i2c_driver = {
+ .driver = {
+ .name = "stm32f7-i2c",
+ .of_match_table = stm32f7_i2c_match,
+ },
+ .probe = stm32f7_i2c_probe,
+ .remove = stm32f7_i2c_remove,
+};
+
+module_platform_driver(stm32f7_i2c_driver);
+
+MODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32F7 I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
new file mode 100644
index 000000000..5503fa171
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (C) 2007-2012 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * ST DDC I2C master mode driver, used in e.g. U300 series platforms.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/* the name of this kernel module */
+#define NAME "stu300"
+
+/* CR (Control Register) 8bit (R/W) */
+#define I2C_CR (0x00000000)
+#define I2C_CR_RESET_VALUE (0x00)
+#define I2C_CR_RESET_UMASK (0x00)
+#define I2C_CR_DDC1_ENABLE (0x80)
+#define I2C_CR_TRANS_ENABLE (0x40)
+#define I2C_CR_PERIPHERAL_ENABLE (0x20)
+#define I2C_CR_DDC2B_ENABLE (0x10)
+#define I2C_CR_START_ENABLE (0x08)
+#define I2C_CR_ACK_ENABLE (0x04)
+#define I2C_CR_STOP_ENABLE (0x02)
+#define I2C_CR_INTERRUPT_ENABLE (0x01)
+/* SR1 (Status Register 1) 8bit (R/-) */
+#define I2C_SR1 (0x00000004)
+#define I2C_SR1_RESET_VALUE (0x00)
+#define I2C_SR1_RESET_UMASK (0x00)
+#define I2C_SR1_EVF_IND (0x80)
+#define I2C_SR1_ADD10_IND (0x40)
+#define I2C_SR1_TRA_IND (0x20)
+#define I2C_SR1_BUSY_IND (0x10)
+#define I2C_SR1_BTF_IND (0x08)
+#define I2C_SR1_ADSL_IND (0x04)
+#define I2C_SR1_MSL_IND (0x02)
+#define I2C_SR1_SB_IND (0x01)
+/* SR2 (Status Register 2) 8bit (R/-) */
+#define I2C_SR2 (0x00000008)
+#define I2C_SR2_RESET_VALUE (0x00)
+#define I2C_SR2_RESET_UMASK (0x40)
+#define I2C_SR2_MASK (0xBF)
+#define I2C_SR2_SCLFAL_IND (0x80)
+#define I2C_SR2_ENDAD_IND (0x20)
+#define I2C_SR2_AF_IND (0x10)
+#define I2C_SR2_STOPF_IND (0x08)
+#define I2C_SR2_ARLO_IND (0x04)
+#define I2C_SR2_BERR_IND (0x02)
+#define I2C_SR2_DDC2BF_IND (0x01)
+/* CCR (Clock Control Register) 8bit (R/W) */
+#define I2C_CCR (0x0000000C)
+#define I2C_CCR_RESET_VALUE (0x00)
+#define I2C_CCR_RESET_UMASK (0x00)
+#define I2C_CCR_MASK (0xFF)
+#define I2C_CCR_FMSM (0x80)
+#define I2C_CCR_CC_MASK (0x7F)
+/* OAR1 (Own Address Register 1) 8bit (R/W) */
+#define I2C_OAR1 (0x00000010)
+#define I2C_OAR1_RESET_VALUE (0x00)
+#define I2C_OAR1_RESET_UMASK (0x00)
+#define I2C_OAR1_ADD_MASK (0xFF)
+/* OAR2 (Own Address Register 2) 8bit (R/W) */
+#define I2C_OAR2 (0x00000014)
+#define I2C_OAR2_RESET_VALUE (0x40)
+#define I2C_OAR2_RESET_UMASK (0x19)
+#define I2C_OAR2_MASK (0xE6)
+#define I2C_OAR2_FR_25_10MHZ (0x00)
+#define I2C_OAR2_FR_10_1667MHZ (0x20)
+#define I2C_OAR2_FR_1667_2667MHZ (0x40)
+#define I2C_OAR2_FR_2667_40MHZ (0x60)
+#define I2C_OAR2_FR_40_5333MHZ (0x80)
+#define I2C_OAR2_FR_5333_66MHZ (0xA0)
+#define I2C_OAR2_FR_66_80MHZ (0xC0)
+#define I2C_OAR2_FR_80_100MHZ (0xE0)
+#define I2C_OAR2_FR_MASK (0xE0)
+#define I2C_OAR2_ADD_MASK (0x06)
+/* DR (Data Register) 8bit (R/W) */
+#define I2C_DR (0x00000018)
+#define I2C_DR_RESET_VALUE (0x00)
+#define I2C_DR_RESET_UMASK (0xFF)
+#define I2C_DR_D_MASK (0xFF)
+/* ECCR (Extended Clock Control Register) 8bit (R/W) */
+#define I2C_ECCR (0x0000001C)
+#define I2C_ECCR_RESET_VALUE (0x00)
+#define I2C_ECCR_RESET_UMASK (0xE0)
+#define I2C_ECCR_MASK (0x1F)
+#define I2C_ECCR_CC_MASK (0x1F)
+
+/*
+ * These events are more or less responses to commands
+ * sent into the hardware, presumably reflecting the state
+ * of an internal state machine.
+ */
+enum stu300_event {
+ STU300_EVENT_NONE = 0,
+ STU300_EVENT_1,
+ STU300_EVENT_2,
+ STU300_EVENT_3,
+ STU300_EVENT_4,
+ STU300_EVENT_5,
+ STU300_EVENT_6,
+ STU300_EVENT_7,
+ STU300_EVENT_8,
+ STU300_EVENT_9
+};
+
+enum stu300_error {
+ STU300_ERROR_NONE = 0,
+ STU300_ERROR_ACKNOWLEDGE_FAILURE,
+ STU300_ERROR_BUS_ERROR,
+ STU300_ERROR_ARBITRATION_LOST,
+ STU300_ERROR_UNKNOWN
+};
+
+/* timeout waiting for the controller to respond */
+#define STU300_TIMEOUT (msecs_to_jiffies(1000))
+
+/*
+ * The number of address send athemps tried before giving up.
+ * If the first one fails it seems like 5 to 8 attempts are required.
+ */
+#define NUM_ADDR_RESEND_ATTEMPTS 12
+
+/* I2C clock speed, in Hz 0-400kHz*/
+static unsigned int scl_frequency = 100000;
+module_param(scl_frequency, uint, 0644);
+
+/**
+ * struct stu300_dev - the stu300 driver state holder
+ * @pdev: parent platform device
+ * @adapter: corresponding I2C adapter
+ * @clk: hardware block clock
+ * @irq: assigned interrupt line
+ * @cmd_issue_lock: this locks the following cmd_ variables
+ * @cmd_complete: acknowledge completion for an I2C command
+ * @cmd_event: expected event coming in as a response to a command
+ * @cmd_err: error code as response to a command
+ * @speed: current bus speed in Hz
+ * @msg_index: index of current message
+ * @msg_len: length of current message
+ */
+
+struct stu300_dev {
+ struct platform_device *pdev;
+ struct i2c_adapter adapter;
+ void __iomem *virtbase;
+ struct clk *clk;
+ int irq;
+ spinlock_t cmd_issue_lock;
+ struct completion cmd_complete;
+ enum stu300_event cmd_event;
+ enum stu300_error cmd_err;
+ unsigned int speed;
+ int msg_index;
+ int msg_len;
+};
+
+/* Local forward function declarations */
+static int stu300_init_hw(struct stu300_dev *dev);
+
+/*
+ * The block needs writes in both MSW and LSW in order
+ * for all data lines to reach their destination.
+ */
+static inline void stu300_wr8(u32 value, void __iomem *address)
+{
+ writel((value << 16) | value, address);
+}
+
+/*
+ * This merely masks off the duplicates which appear
+ * in bytes 1-3. You _MUST_ use 32-bit bus access on this
+ * device, else it will not work.
+ */
+static inline u32 stu300_r8(void __iomem *address)
+{
+ return readl(address) & 0x000000FFU;
+}
+
+static void stu300_irq_enable(struct stu300_dev *dev)
+{
+ u32 val;
+ val = stu300_r8(dev->virtbase + I2C_CR);
+ val |= I2C_CR_INTERRUPT_ENABLE;
+ /* Twice paranoia (possible HW glitch) */
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+}
+
+static void stu300_irq_disable(struct stu300_dev *dev)
+{
+ u32 val;
+ val = stu300_r8(dev->virtbase + I2C_CR);
+ val &= ~I2C_CR_INTERRUPT_ENABLE;
+ /* Twice paranoia (possible HW glitch) */
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+}
+
+
+/*
+ * Tells whether a certain event or events occurred in
+ * response to a command. The events represent states in
+ * the internal state machine of the hardware. The events
+ * are not very well described in the hardware
+ * documentation and can only be treated as abstract state
+ * machine states.
+ *
+ * @ret 0 = event has not occurred or unknown error, any
+ * other value means the correct event occurred or an error.
+ */
+
+static int stu300_event_occurred(struct stu300_dev *dev,
+ enum stu300_event mr_event) {
+ u32 status1;
+ u32 status2;
+
+ /* What event happened? */
+ status1 = stu300_r8(dev->virtbase + I2C_SR1);
+
+ if (!(status1 & I2C_SR1_EVF_IND))
+ /* No event at all */
+ return 0;
+
+ status2 = stu300_r8(dev->virtbase + I2C_SR2);
+
+ /* Block any multiple interrupts */
+ stu300_irq_disable(dev);
+
+ /* Check for errors first */
+ if (status2 & I2C_SR2_AF_IND) {
+ dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
+ return 1;
+ } else if (status2 & I2C_SR2_BERR_IND) {
+ dev->cmd_err = STU300_ERROR_BUS_ERROR;
+ return 1;
+ } else if (status2 & I2C_SR2_ARLO_IND) {
+ dev->cmd_err = STU300_ERROR_ARBITRATION_LOST;
+ return 1;
+ }
+
+ switch (mr_event) {
+ case STU300_EVENT_1:
+ if (status1 & I2C_SR1_ADSL_IND)
+ return 1;
+ break;
+ case STU300_EVENT_2:
+ case STU300_EVENT_3:
+ case STU300_EVENT_7:
+ case STU300_EVENT_8:
+ if (status1 & I2C_SR1_BTF_IND) {
+ return 1;
+ }
+ break;
+ case STU300_EVENT_4:
+ if (status2 & I2C_SR2_STOPF_IND)
+ return 1;
+ break;
+ case STU300_EVENT_5:
+ if (status1 & I2C_SR1_SB_IND)
+ /* Clear start bit */
+ return 1;
+ break;
+ case STU300_EVENT_6:
+ if (status2 & I2C_SR2_ENDAD_IND) {
+ /* First check for any errors */
+ return 1;
+ }
+ break;
+ case STU300_EVENT_9:
+ if (status1 & I2C_SR1_ADD10_IND)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ /* If we get here, we're on thin ice.
+ * Here we are in a status where we have
+ * gotten a response that does not match
+ * what we requested.
+ */
+ dev->cmd_err = STU300_ERROR_UNKNOWN;
+ dev_err(&dev->pdev->dev,
+ "Unhandled interrupt! %d sr1: 0x%x sr2: 0x%x\n",
+ mr_event, status1, status2);
+ return 0;
+}
+
+static irqreturn_t stu300_irh(int irq, void *data)
+{
+ struct stu300_dev *dev = data;
+ int res;
+
+ /* Just make sure that the block is clocked */
+ clk_enable(dev->clk);
+
+ /* See if this was what we were waiting for */
+ spin_lock(&dev->cmd_issue_lock);
+
+ res = stu300_event_occurred(dev, dev->cmd_event);
+ if (res || dev->cmd_err != STU300_ERROR_NONE)
+ complete(&dev->cmd_complete);
+
+ spin_unlock(&dev->cmd_issue_lock);
+
+ clk_disable(dev->clk);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Sends a command and then waits for the bits masked by *flagmask*
+ * to go high or low by IRQ awaiting.
+ */
+static int stu300_start_and_await_event(struct stu300_dev *dev,
+ u8 cr_value,
+ enum stu300_event mr_event)
+{
+ int ret;
+
+ if (unlikely(irqs_disabled())) {
+ /* TODO: implement polling for this case if need be. */
+ WARN(1, "irqs are disabled, cannot poll for event\n");
+ return -EIO;
+ }
+
+ /* Lock command issue, fill in an event we wait for */
+ spin_lock_irq(&dev->cmd_issue_lock);
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = STU300_ERROR_NONE;
+ dev->cmd_event = mr_event;
+ spin_unlock_irq(&dev->cmd_issue_lock);
+
+ /* Turn on interrupt, send command and wait. */
+ cr_value |= I2C_CR_INTERRUPT_ENABLE;
+ stu300_wr8(cr_value, dev->virtbase + I2C_CR);
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ STU300_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout() "
+ "returned %d waiting for event %04x\n", ret, mr_event);
+ return ret;
+ }
+
+ if (ret == 0) {
+ dev_err(&dev->pdev->dev, "controller timed out "
+ "waiting for event %d, reinit hardware\n", mr_event);
+ (void) stu300_init_hw(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (dev->cmd_err != STU300_ERROR_NONE) {
+ dev_err(&dev->pdev->dev, "controller (start) "
+ "error %d waiting for event %d, reinit hardware\n",
+ dev->cmd_err, mr_event);
+ (void) stu300_init_hw(dev);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * This waits for a flag to be set, if it is not set on entry, an interrupt is
+ * configured to wait for the flag using a completion.
+ */
+static int stu300_await_event(struct stu300_dev *dev,
+ enum stu300_event mr_event)
+{
+ int ret;
+
+ if (unlikely(irqs_disabled())) {
+ /* TODO: implement polling for this case if need be. */
+ dev_err(&dev->pdev->dev, "irqs are disabled on this "
+ "system!\n");
+ return -EIO;
+ }
+
+ /* Is it already here? */
+ spin_lock_irq(&dev->cmd_issue_lock);
+ dev->cmd_err = STU300_ERROR_NONE;
+ dev->cmd_event = mr_event;
+
+ init_completion(&dev->cmd_complete);
+
+ /* Turn on the I2C interrupt for current operation */
+ stu300_irq_enable(dev);
+
+ /* Unlock the command block and wait for the event to occur */
+ spin_unlock_irq(&dev->cmd_issue_lock);
+
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ STU300_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait_for_completion_interruptible_timeout()"
+ "returned %d waiting for event %04x\n", ret, mr_event);
+ return ret;
+ }
+
+ if (ret == 0) {
+ if (mr_event != STU300_EVENT_6) {
+ dev_err(&dev->pdev->dev, "controller "
+ "timed out waiting for event %d, reinit "
+ "hardware\n", mr_event);
+ (void) stu300_init_hw(dev);
+ }
+ return -ETIMEDOUT;
+ }
+
+ if (dev->cmd_err != STU300_ERROR_NONE) {
+ if (mr_event != STU300_EVENT_6) {
+ dev_err(&dev->pdev->dev, "controller "
+ "error (await_event) %d waiting for event %d, "
+ "reinit hardware\n", dev->cmd_err, mr_event);
+ (void) stu300_init_hw(dev);
+ }
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Waits for the busy bit to go low by repeated polling.
+ */
+#define BUSY_RELEASE_ATTEMPTS 10
+static int stu300_wait_while_busy(struct stu300_dev *dev)
+{
+ unsigned long timeout;
+ int i;
+
+ for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) {
+ timeout = jiffies + STU300_TIMEOUT;
+
+ while (!time_after(jiffies, timeout)) {
+ /* Is not busy? */
+ if ((stu300_r8(dev->virtbase + I2C_SR1) &
+ I2C_SR1_BUSY_IND) == 0)
+ return 0;
+ msleep(1);
+ }
+
+ dev_err(&dev->pdev->dev, "transaction timed out "
+ "waiting for device to be free (not busy). "
+ "Attempt: %d\n", i+1);
+
+ dev_err(&dev->pdev->dev, "base address = "
+ "0x%08x, reinit hardware\n", (u32) dev->virtbase);
+
+ (void) stu300_init_hw(dev);
+ }
+
+ dev_err(&dev->pdev->dev, "giving up after %d attempts "
+ "to reset the bus.\n", BUSY_RELEASE_ATTEMPTS);
+
+ return -ETIMEDOUT;
+}
+
+struct stu300_clkset {
+ unsigned long rate;
+ u32 setting;
+};
+
+static const struct stu300_clkset stu300_clktable[] = {
+ { 0, 0xFFU },
+ { 2500000, I2C_OAR2_FR_25_10MHZ },
+ { 10000000, I2C_OAR2_FR_10_1667MHZ },
+ { 16670000, I2C_OAR2_FR_1667_2667MHZ },
+ { 26670000, I2C_OAR2_FR_2667_40MHZ },
+ { 40000000, I2C_OAR2_FR_40_5333MHZ },
+ { 53330000, I2C_OAR2_FR_5333_66MHZ },
+ { 66000000, I2C_OAR2_FR_66_80MHZ },
+ { 80000000, I2C_OAR2_FR_80_100MHZ },
+ { 100000000, 0xFFU },
+};
+
+
+static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate)
+{
+
+ u32 val;
+ int i = 0;
+
+ /* Locate the appropriate clock setting */
+ while (i < ARRAY_SIZE(stu300_clktable) - 1 &&
+ stu300_clktable[i].rate < clkrate)
+ i++;
+
+ if (stu300_clktable[i].setting == 0xFFU) {
+ dev_err(&dev->pdev->dev, "too %s clock rate requested "
+ "(%lu Hz).\n", i ? "high" : "low", clkrate);
+ return -EINVAL;
+ }
+
+ stu300_wr8(stu300_clktable[i].setting,
+ dev->virtbase + I2C_OAR2);
+
+ dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz "
+ "virtbase %p\n", clkrate, dev->speed, dev->virtbase);
+
+ if (dev->speed > 100000)
+ /* Fast Mode I2C */
+ val = ((clkrate/dev->speed) - 9)/3 + 1;
+ else
+ /* Standard Mode I2C */
+ val = ((clkrate/dev->speed) - 7)/2 + 1;
+
+ /* According to spec the divider must be > 2 */
+ if (val < 0x002) {
+ dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n",
+ clkrate);
+ return -EINVAL;
+ }
+
+ /* We have 12 bits clock divider only! */
+ if (val & 0xFFFFF000U) {
+ dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n",
+ clkrate);
+ return -EINVAL;
+ }
+
+ if (dev->speed > 100000) {
+ /* CC6..CC0 */
+ stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM,
+ dev->virtbase + I2C_CCR);
+ dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, "
+ "Fast Mode I2C\n", val);
+ } else {
+ /* CC6..CC0 */
+ stu300_wr8((val & I2C_CCR_CC_MASK),
+ dev->virtbase + I2C_CCR);
+ dev_dbg(&dev->pdev->dev, "set clock divider to "
+ "0x%08x, Standard Mode I2C\n", val);
+ }
+
+ /* CC11..CC7 */
+ stu300_wr8(((val >> 7) & 0x1F),
+ dev->virtbase + I2C_ECCR);
+
+ return 0;
+}
+
+
+static int stu300_init_hw(struct stu300_dev *dev)
+{
+ u32 dummy;
+ unsigned long clkrate;
+ int ret;
+
+ /* Disable controller */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ /*
+ * Set own address to some default value (0x00).
+ * We do not support slave mode anyway.
+ */
+ stu300_wr8(0x00, dev->virtbase + I2C_OAR1);
+ /*
+ * The I2C controller only operates properly in 26 MHz but we
+ * program this driver as if we didn't know. This will also set the two
+ * high bits of the own address to zero as well.
+ * There is no known hardware issue with running in 13 MHz
+ * However, speeds over 200 kHz are not used.
+ */
+ clkrate = clk_get_rate(dev->clk);
+ ret = stu300_set_clk(dev, clkrate);
+
+ if (ret)
+ return ret;
+ /*
+ * Enable block, do it TWICE (hardware glitch)
+ * Setting bit 7 can enable DDC mode. (Not used currently.)
+ */
+ stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+ dev->virtbase + I2C_CR);
+ stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+ dev->virtbase + I2C_CR);
+ /* Make a dummy read of the status register SR1 & SR2 */
+ dummy = stu300_r8(dev->virtbase + I2C_SR2);
+ dummy = stu300_r8(dev->virtbase + I2C_SR1);
+
+ return 0;
+}
+
+
+
+/* Send slave address. */
+static int stu300_send_address(struct stu300_dev *dev,
+ struct i2c_msg *msg, int resend)
+{
+ u32 val;
+ int ret;
+
+ if (msg->flags & I2C_M_TEN) {
+ /* This is probably how 10 bit addresses look */
+ val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) &
+ I2C_DR_D_MASK;
+ if (msg->flags & I2C_M_RD)
+ /* This is the direction bit */
+ val |= 0x01;
+ } else {
+ val = i2c_8bit_addr_from_msg(msg);
+ }
+
+ if (resend) {
+ if (msg->flags & I2C_M_RD)
+ dev_dbg(&dev->pdev->dev, "read resend\n");
+ else
+ dev_dbg(&dev->pdev->dev, "write resend\n");
+ }
+
+ stu300_wr8(val, dev->virtbase + I2C_DR);
+
+ /* For 10bit addressing, await 10bit request (EVENT 9) */
+ if (msg->flags & I2C_M_TEN) {
+ ret = stu300_await_event(dev, STU300_EVENT_9);
+ /*
+ * The slave device wants a 10bit address, send the rest
+ * of the bits (the LSBits)
+ */
+ val = msg->addr & I2C_DR_D_MASK;
+ /* This clears "event 9" */
+ stu300_wr8(val, dev->virtbase + I2C_DR);
+ if (ret != 0)
+ return ret;
+ }
+ /* FIXME: Why no else here? two events for 10bit?
+ * Await event 6 (normal) or event 9 (10bit)
+ */
+
+ if (resend)
+ dev_dbg(&dev->pdev->dev, "await event 6\n");
+ ret = stu300_await_event(dev, STU300_EVENT_6);
+
+ /*
+ * Clear any pending EVENT 6 no matter what happened during
+ * await_event.
+ */
+ val = stu300_r8(dev->virtbase + I2C_CR);
+ val |= I2C_CR_PERIPHERAL_ENABLE;
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+
+ return ret;
+}
+
+static int stu300_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ u32 cr;
+ u32 val;
+ u32 i;
+ int ret;
+ int attempts = 0;
+ struct stu300_dev *dev = i2c_get_adapdata(adap);
+
+ clk_enable(dev->clk);
+
+ /* Remove this if (0) to trace each and every message. */
+ if (0) {
+ dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, "
+ "flags: 0x%04x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+ }
+
+ /*
+ * For some reason, sending the address sometimes fails when running
+ * on the 13 MHz clock. No interrupt arrives. This is a work around,
+ * which tries to restart and send the address up to 10 times before
+ * really giving up. Usually 5 to 8 attempts are enough.
+ */
+ do {
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "wait while busy\n");
+ /* Check that the bus is free, or wait until some timeout */
+ ret = stu300_wait_while_busy(dev);
+ if (ret != 0)
+ goto exit_disable;
+
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "re-int hw\n");
+ /*
+ * According to ST, there is no problem if the clock is
+ * changed between 13 and 26 MHz during a transfer.
+ */
+ ret = stu300_init_hw(dev);
+ if (ret)
+ goto exit_disable;
+
+ /* Send a start condition */
+ cr = I2C_CR_PERIPHERAL_ENABLE;
+ /* Setting the START bit puts the block in master mode */
+ if (!(msg->flags & I2C_M_NOSTART))
+ cr |= I2C_CR_START_ENABLE;
+ if ((msg->flags & I2C_M_RD) && (msg->len > 1))
+ /* On read more than 1 byte, we need ack. */
+ cr |= I2C_CR_ACK_ENABLE;
+ /* Check that it gets through */
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "send start event\n");
+ ret = stu300_start_and_await_event(dev, cr,
+ STU300_EVENT_5);
+ }
+
+ if (attempts)
+ dev_dbg(&dev->pdev->dev, "send address\n");
+
+ if (ret == 0)
+ /* Send address */
+ ret = stu300_send_address(dev, msg, attempts != 0);
+
+ if (ret != 0) {
+ attempts++;
+ dev_dbg(&dev->pdev->dev, "failed sending address, "
+ "retrying. Attempt: %d msg_index: %d/%d\n",
+ attempts, dev->msg_index, dev->msg_len);
+ }
+
+ } while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS);
+
+ if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) {
+ dev_dbg(&dev->pdev->dev, "managed to get address "
+ "through after %d attempts\n", attempts);
+ } else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) {
+ dev_dbg(&dev->pdev->dev, "I give up, tried %d times "
+ "to resend address.\n",
+ NUM_ADDR_RESEND_ATTEMPTS);
+ goto exit_disable;
+ }
+
+
+ if (msg->flags & I2C_M_RD) {
+ /* READ: we read the actual bytes one at a time */
+ for (i = 0; i < msg->len; i++) {
+ if (i == msg->len-1) {
+ /*
+ * Disable ACK and set STOP condition before
+ * reading last byte
+ */
+ val = I2C_CR_PERIPHERAL_ENABLE;
+
+ if (stop)
+ val |= I2C_CR_STOP_ENABLE;
+
+ stu300_wr8(val,
+ dev->virtbase + I2C_CR);
+ }
+ /* Wait for this byte... */
+ ret = stu300_await_event(dev, STU300_EVENT_7);
+ if (ret != 0)
+ goto exit_disable;
+ /* This clears event 7 */
+ msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR);
+ }
+ } else {
+ /* WRITE: we send the actual bytes one at a time */
+ for (i = 0; i < msg->len; i++) {
+ /* Write the byte */
+ stu300_wr8(msg->buf[i],
+ dev->virtbase + I2C_DR);
+ /* Check status */
+ ret = stu300_await_event(dev, STU300_EVENT_8);
+ /* Next write to DR will clear event 8 */
+ if (ret != 0) {
+ dev_err(&dev->pdev->dev, "error awaiting "
+ "event 8 (%d)\n", ret);
+ goto exit_disable;
+ }
+ }
+ /* Check NAK */
+ if (!(msg->flags & I2C_M_IGNORE_NAK)) {
+ if (stu300_r8(dev->virtbase + I2C_SR2) &
+ I2C_SR2_AF_IND) {
+ dev_err(&dev->pdev->dev, "I2C payload "
+ "send returned NAK!\n");
+ ret = -EIO;
+ goto exit_disable;
+ }
+ }
+ if (stop) {
+ /* Send stop condition */
+ val = I2C_CR_PERIPHERAL_ENABLE;
+ val |= I2C_CR_STOP_ENABLE;
+ stu300_wr8(val, dev->virtbase + I2C_CR);
+ }
+ }
+
+ /* Check that the bus is free, or wait until some timeout occurs */
+ ret = stu300_wait_while_busy(dev);
+ if (ret != 0) {
+ dev_err(&dev->pdev->dev, "timeout waiting for transfer "
+ "to commence.\n");
+ goto exit_disable;
+ }
+
+ /* Dummy read status registers */
+ val = stu300_r8(dev->virtbase + I2C_SR2);
+ val = stu300_r8(dev->virtbase + I2C_SR1);
+ ret = 0;
+
+ exit_disable:
+ /* Disable controller */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ clk_disable(dev->clk);
+ return ret;
+}
+
+static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int ret = -1;
+ int i;
+
+ struct stu300_dev *dev = i2c_get_adapdata(adap);
+ dev->msg_len = num;
+
+ for (i = 0; i < num; i++) {
+ /*
+ * Another driver appears to send stop for each message,
+ * here we only do that for the last message. Possibly some
+ * peripherals require this behaviour, then their drivers
+ * have to send single messages in order to get "stop" for
+ * each message.
+ */
+ dev->msg_index = i;
+
+ ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+
+ if (ret != 0) {
+ num = ret;
+ break;
+ }
+ }
+
+ return num;
+}
+
+static u32 stu300_func(struct i2c_adapter *adap)
+{
+ /* This is the simplest thing you can think of... */
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm stu300_algo = {
+ .master_xfer = stu300_xfer,
+ .functionality = stu300_func,
+};
+
+static const struct i2c_adapter_quirks stu300_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static int stu300_probe(struct platform_device *pdev)
+{
+ struct stu300_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int bus_nr;
+ int ret = 0;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ bus_nr = pdev->id;
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
+ return PTR_ERR(dev->clk);
+ }
+
+ dev->pdev = pdev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->virtbase = devm_ioremap_resource(&pdev->dev, res);
+ dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
+ "base %p\n", bus_nr, dev->virtbase);
+ if (IS_ERR(dev->virtbase))
+ return PTR_ERR(dev->virtbase);
+
+ dev->irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev);
+ if (ret < 0)
+ return ret;
+
+ dev->speed = scl_frequency;
+
+ clk_prepare_enable(dev->clk);
+ ret = stu300_init_hw(dev);
+ clk_disable(dev->clk);
+ if (ret != 0) {
+ dev_err(&dev->pdev->dev, "error initializing hardware.\n");
+ return -EIO;
+ }
+
+ /* IRQ event handling initialization */
+ spin_lock_init(&dev->cmd_issue_lock);
+ dev->cmd_event = STU300_EVENT_NONE;
+ dev->cmd_err = STU300_ERROR_NONE;
+
+ adap = &dev->adapter;
+ adap->owner = THIS_MODULE;
+ /* DDC class but actually often used for more generic I2C */
+ adap->class = I2C_CLASS_DEPRECATED;
+ strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
+ sizeof(adap->name));
+ adap->nr = bus_nr;
+ adap->algo = &stu300_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+ adap->quirks = &stu300_quirks;
+
+ i2c_set_adapdata(adap, dev);
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, dev);
+ dev_info(&pdev->dev, "ST DDC I2C @ %p, irq %d\n",
+ dev->virtbase, dev->irq);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stu300_suspend(struct device *device)
+{
+ struct stu300_dev *dev = dev_get_drvdata(device);
+
+ /* Turn off everything */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ return 0;
+}
+
+static int stu300_resume(struct device *device)
+{
+ int ret = 0;
+ struct stu300_dev *dev = dev_get_drvdata(device);
+
+ clk_enable(dev->clk);
+ ret = stu300_init_hw(dev);
+ clk_disable(dev->clk);
+
+ if (ret != 0)
+ dev_err(device, "error re-initializing hardware.\n");
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume);
+#define STU300_I2C_PM (&stu300_pm)
+#else
+#define STU300_I2C_PM NULL
+#endif
+
+static int stu300_remove(struct platform_device *pdev)
+{
+ struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+ /* Turn off everything */
+ stu300_wr8(0x00, dev->virtbase + I2C_CR);
+ return 0;
+}
+
+static const struct of_device_id stu300_dt_match[] = {
+ { .compatible = "st,ddci2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stu300_dt_match);
+
+static struct platform_driver stu300_i2c_driver = {
+ .driver = {
+ .name = NAME,
+ .pm = STU300_I2C_PM,
+ .of_match_table = stu300_dt_match,
+ },
+ .probe = stu300_probe,
+ .remove = stu300_remove,
+
+};
+
+static int __init stu300_init(void)
+{
+ return platform_driver_register(&stu300_i2c_driver);
+}
+
+static void __exit stu300_exit(void)
+{
+ platform_driver_unregister(&stu300_i2c_driver);
+}
+
+/*
+ * The systems using this bus often have very basic devices such
+ * as regulators on the I2C bus, so this needs to be loaded early.
+ * Therefore it is registered in the subsys_initcall().
+ */
+subsys_initcall(stu300_init);
+module_exit(stu300_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" NAME);
diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c
new file mode 100644
index 000000000..7c07ce116
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c
@@ -0,0 +1,343 @@
+/*
+ * P2WI (Push-Pull Two Wire Interface) bus driver.
+ *
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * The P2WI controller looks like an SMBus controller which only supports byte
+ * data transfers. But, it differs from standard SMBus protocol on several
+ * aspects:
+ * - it supports only one slave device, and thus drop the address field
+ * - it adds a parity bit every 8bits of data
+ * - only one read access is required to read a byte (instead of a write
+ * followed by a read access in standard SMBus protocol)
+ * - there's no Ack bit after each byte transfer
+ *
+ * This means this bus cannot be used to interface with standard SMBus
+ * devices (the only known device to support this interface is the AXP221
+ * PMIC).
+ *
+ */
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+
+/* P2WI registers */
+#define P2WI_CTRL 0x0
+#define P2WI_CCR 0x4
+#define P2WI_INTE 0x8
+#define P2WI_INTS 0xc
+#define P2WI_DADDR0 0x10
+#define P2WI_DADDR1 0x14
+#define P2WI_DLEN 0x18
+#define P2WI_DATA0 0x1c
+#define P2WI_DATA1 0x20
+#define P2WI_LCR 0x24
+#define P2WI_PMCR 0x28
+
+/* CTRL fields */
+#define P2WI_CTRL_START_TRANS BIT(7)
+#define P2WI_CTRL_ABORT_TRANS BIT(6)
+#define P2WI_CTRL_GLOBAL_INT_ENB BIT(1)
+#define P2WI_CTRL_SOFT_RST BIT(0)
+
+/* CLK CTRL fields */
+#define P2WI_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8)
+#define P2WI_CCR_MAX_CLK_DIV 0xff
+#define P2WI_CCR_CLK_DIV(v) ((v) & P2WI_CCR_MAX_CLK_DIV)
+
+/* STATUS fields */
+#define P2WI_INTS_TRANS_ERR_ID(v) (((v) >> 8) & 0xff)
+#define P2WI_INTS_LOAD_BSY BIT(2)
+#define P2WI_INTS_TRANS_ERR BIT(1)
+#define P2WI_INTS_TRANS_OVER BIT(0)
+
+/* DATA LENGTH fields*/
+#define P2WI_DLEN_READ BIT(4)
+#define P2WI_DLEN_DATA_LENGTH(v) ((v - 1) & 0x7)
+
+/* LINE CTRL fields*/
+#define P2WI_LCR_SCL_STATE BIT(5)
+#define P2WI_LCR_SDA_STATE BIT(4)
+#define P2WI_LCR_SCL_CTL BIT(3)
+#define P2WI_LCR_SCL_CTL_EN BIT(2)
+#define P2WI_LCR_SDA_CTL BIT(1)
+#define P2WI_LCR_SDA_CTL_EN BIT(0)
+
+/* PMU MODE CTRL fields */
+#define P2WI_PMCR_PMU_INIT_SEND BIT(31)
+#define P2WI_PMCR_PMU_INIT_DATA(v) (((v) & 0xff) << 16)
+#define P2WI_PMCR_PMU_MODE_REG(v) (((v) & 0xff) << 8)
+#define P2WI_PMCR_PMU_DEV_ADDR(v) ((v) & 0xff)
+
+#define P2WI_MAX_FREQ 6000000
+
+struct p2wi {
+ struct i2c_adapter adapter;
+ struct completion complete;
+ unsigned int status;
+ void __iomem *regs;
+ struct clk *clk;
+ struct reset_control *rstc;
+ int slave_addr;
+};
+
+static irqreturn_t p2wi_interrupt(int irq, void *dev_id)
+{
+ struct p2wi *p2wi = dev_id;
+ unsigned long status;
+
+ status = readl(p2wi->regs + P2WI_INTS);
+ p2wi->status = status;
+
+ /* Clear interrupts */
+ status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR |
+ P2WI_INTS_TRANS_OVER);
+ writel(status, p2wi->regs + P2WI_INTS);
+
+ complete(&p2wi->complete);
+
+ return IRQ_HANDLED;
+}
+
+static u32 p2wi_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct p2wi *p2wi = i2c_get_adapdata(adap);
+ unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1);
+
+ if (p2wi->slave_addr >= 0 && addr != p2wi->slave_addr) {
+ dev_err(&adap->dev, "invalid P2WI address\n");
+ return -EINVAL;
+ }
+
+ if (!data)
+ return -EINVAL;
+
+ writel(command, p2wi->regs + P2WI_DADDR0);
+
+ if (read_write == I2C_SMBUS_READ)
+ dlen |= P2WI_DLEN_READ;
+ else
+ writel(data->byte, p2wi->regs + P2WI_DATA0);
+
+ writel(dlen, p2wi->regs + P2WI_DLEN);
+
+ if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) {
+ dev_err(&adap->dev, "P2WI bus busy\n");
+ return -EBUSY;
+ }
+
+ reinit_completion(&p2wi->complete);
+
+ writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER,
+ p2wi->regs + P2WI_INTE);
+
+ writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB,
+ p2wi->regs + P2WI_CTRL);
+
+ wait_for_completion(&p2wi->complete);
+
+ if (p2wi->status & P2WI_INTS_LOAD_BSY) {
+ dev_err(&adap->dev, "P2WI bus busy\n");
+ return -EBUSY;
+ }
+
+ if (p2wi->status & P2WI_INTS_TRANS_ERR) {
+ dev_err(&adap->dev, "P2WI bus xfer error\n");
+ return -ENXIO;
+ }
+
+ if (read_write == I2C_SMBUS_READ)
+ data->byte = readl(p2wi->regs + P2WI_DATA0);
+
+ return 0;
+}
+
+static const struct i2c_algorithm p2wi_algo = {
+ .smbus_xfer = p2wi_smbus_xfer,
+ .functionality = p2wi_functionality,
+};
+
+static const struct of_device_id p2wi_of_match_table[] = {
+ { .compatible = "allwinner,sun6i-a31-p2wi" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, p2wi_of_match_table);
+
+static int p2wi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *childnp;
+ unsigned long parent_clk_freq;
+ u32 clk_freq = 100000;
+ struct resource *r;
+ struct p2wi *p2wi;
+ u32 slave_addr;
+ int clk_div;
+ int irq;
+ int ret;
+
+ of_property_read_u32(np, "clock-frequency", &clk_freq);
+ if (clk_freq > P2WI_MAX_FREQ) {
+ dev_err(dev,
+ "required clock-frequency (%u Hz) is too high (max = 6MHz)",
+ clk_freq);
+ return -EINVAL;
+ }
+
+ if (of_get_child_count(np) > 1) {
+ dev_err(dev, "P2WI only supports one slave device\n");
+ return -EINVAL;
+ }
+
+ p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL);
+ if (!p2wi)
+ return -ENOMEM;
+
+ p2wi->slave_addr = -1;
+
+ /*
+ * Authorize a p2wi node without any children to be able to use an
+ * i2c-dev from userpace.
+ * In this case the slave_addr is set to -1 and won't be checked when
+ * launching a P2WI transfer.
+ */
+ childnp = of_get_next_available_child(np, NULL);
+ if (childnp) {
+ ret = of_property_read_u32(childnp, "reg", &slave_addr);
+ if (ret) {
+ dev_err(dev, "invalid slave address on node %pOF\n",
+ childnp);
+ return -EINVAL;
+ }
+
+ p2wi->slave_addr = slave_addr;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ p2wi->regs = devm_ioremap_resource(dev, r);
+ if (IS_ERR(p2wi->regs))
+ return PTR_ERR(p2wi->regs);
+
+ strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to retrieve irq: %d\n", irq);
+ return irq;
+ }
+
+ p2wi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(p2wi->clk)) {
+ ret = PTR_ERR(p2wi->clk);
+ dev_err(dev, "failed to retrieve clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(p2wi->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clk: %d\n", ret);
+ return ret;
+ }
+
+ parent_clk_freq = clk_get_rate(p2wi->clk);
+
+ p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(p2wi->rstc)) {
+ ret = PTR_ERR(p2wi->rstc);
+ dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ ret = reset_control_deassert(p2wi->rstc);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset line: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ init_completion(&p2wi->complete);
+ p2wi->adapter.dev.parent = dev;
+ p2wi->adapter.algo = &p2wi_algo;
+ p2wi->adapter.owner = THIS_MODULE;
+ p2wi->adapter.dev.of_node = pdev->dev.of_node;
+ platform_set_drvdata(pdev, p2wi);
+ i2c_set_adapdata(&p2wi->adapter, p2wi);
+
+ ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi);
+ if (ret) {
+ dev_err(dev, "can't register interrupt handler irq%d: %d\n",
+ irq, ret);
+ goto err_reset_assert;
+ }
+
+ writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL);
+
+ clk_div = parent_clk_freq / clk_freq;
+ if (!clk_div) {
+ dev_warn(dev,
+ "clock-frequency is too high, setting it to %lu Hz\n",
+ parent_clk_freq);
+ clk_div = 1;
+ } else if (clk_div > P2WI_CCR_MAX_CLK_DIV) {
+ dev_warn(dev,
+ "clock-frequency is too low, setting it to %lu Hz\n",
+ parent_clk_freq / P2WI_CCR_MAX_CLK_DIV);
+ clk_div = P2WI_CCR_MAX_CLK_DIV;
+ }
+
+ writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div),
+ p2wi->regs + P2WI_CCR);
+
+ ret = i2c_add_adapter(&p2wi->adapter);
+ if (!ret)
+ return 0;
+
+err_reset_assert:
+ reset_control_assert(p2wi->rstc);
+
+err_clk_disable:
+ clk_disable_unprepare(p2wi->clk);
+
+ return ret;
+}
+
+static int p2wi_remove(struct platform_device *dev)
+{
+ struct p2wi *p2wi = platform_get_drvdata(dev);
+
+ reset_control_assert(p2wi->rstc);
+ clk_disable_unprepare(p2wi->clk);
+ i2c_del_adapter(&p2wi->adapter);
+
+ return 0;
+}
+
+static struct platform_driver p2wi_driver = {
+ .probe = p2wi_probe,
+ .remove = p2wi_remove,
+ .driver = {
+ .name = "i2c-sunxi-p2wi",
+ .of_match_table = p2wi_of_match_table,
+ },
+};
+module_platform_driver(p2wi_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner P2WI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c
new file mode 100644
index 000000000..e47380b96
--- /dev/null
+++ b/drivers/i2c/busses/i2c-synquacer.c
@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012 FUJITSU SEMICONDUCTOR LIMITED
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define WAIT_PCLK(n, rate) \
+ ndelay(DIV_ROUND_UP(DIV_ROUND_UP(1000000000, rate), n) + 10)
+
+/* I2C register address definitions */
+#define SYNQUACER_I2C_REG_BSR (0x00 << 2) // Bus Status
+#define SYNQUACER_I2C_REG_BCR (0x01 << 2) // Bus Control
+#define SYNQUACER_I2C_REG_CCR (0x02 << 2) // Clock Control
+#define SYNQUACER_I2C_REG_ADR (0x03 << 2) // Address
+#define SYNQUACER_I2C_REG_DAR (0x04 << 2) // Data
+#define SYNQUACER_I2C_REG_CSR (0x05 << 2) // Expansion CS
+#define SYNQUACER_I2C_REG_FSR (0x06 << 2) // Bus Clock Freq
+#define SYNQUACER_I2C_REG_BC2R (0x07 << 2) // Bus Control 2
+
+/* I2C register bit definitions */
+#define SYNQUACER_I2C_BSR_FBT BIT(0) // First Byte Transfer
+#define SYNQUACER_I2C_BSR_GCA BIT(1) // General Call Address
+#define SYNQUACER_I2C_BSR_AAS BIT(2) // Address as Slave
+#define SYNQUACER_I2C_BSR_TRX BIT(3) // Transfer/Receive
+#define SYNQUACER_I2C_BSR_LRB BIT(4) // Last Received Bit
+#define SYNQUACER_I2C_BSR_AL BIT(5) // Arbitration Lost
+#define SYNQUACER_I2C_BSR_RSC BIT(6) // Repeated Start Cond.
+#define SYNQUACER_I2C_BSR_BB BIT(7) // Bus Busy
+
+#define SYNQUACER_I2C_BCR_INT BIT(0) // Interrupt
+#define SYNQUACER_I2C_BCR_INTE BIT(1) // Interrupt Enable
+#define SYNQUACER_I2C_BCR_GCAA BIT(2) // Gen. Call Access Ack.
+#define SYNQUACER_I2C_BCR_ACK BIT(3) // Acknowledge
+#define SYNQUACER_I2C_BCR_MSS BIT(4) // Master Slave Select
+#define SYNQUACER_I2C_BCR_SCC BIT(5) // Start Condition Cont.
+#define SYNQUACER_I2C_BCR_BEIE BIT(6) // Bus Error Int Enable
+#define SYNQUACER_I2C_BCR_BER BIT(7) // Bus Error
+
+#define SYNQUACER_I2C_CCR_CS_MASK (0x1f) // CCR Clock Period Sel.
+#define SYNQUACER_I2C_CCR_EN BIT(5) // Enable
+#define SYNQUACER_I2C_CCR_FM BIT(6) // Speed Mode Select
+
+#define SYNQUACER_I2C_CSR_CS_MASK (0x3f) // CSR Clock Period Sel.
+
+#define SYNQUACER_I2C_BC2R_SCLL BIT(0) // SCL Low Drive
+#define SYNQUACER_I2C_BC2R_SDAL BIT(1) // SDA Low Drive
+#define SYNQUACER_I2C_BC2R_SCLS BIT(4) // SCL Status
+#define SYNQUACER_I2C_BC2R_SDAS BIT(5) // SDA Status
+
+/* PCLK frequency */
+#define SYNQUACER_I2C_BUS_CLK_FR(rate) (((rate) / 20000000) + 1)
+
+/* STANDARD MODE frequency */
+#define SYNQUACER_I2C_CLK_MASTER_STD(rate) \
+ DIV_ROUND_UP(DIV_ROUND_UP((rate), 100000) - 2, 2)
+/* FAST MODE frequency */
+#define SYNQUACER_I2C_CLK_MASTER_FAST(rate) \
+ DIV_ROUND_UP((DIV_ROUND_UP((rate), 400000) - 2) * 2, 3)
+
+/* (clkrate <= 18000000) */
+/* calculate the value of CS bits in CCR register on standard mode */
+#define SYNQUACER_I2C_CCR_CS_STD_MAX_18M(rate) \
+ ((SYNQUACER_I2C_CLK_MASTER_STD(rate) - 65) \
+ & SYNQUACER_I2C_CCR_CS_MASK)
+
+/* calculate the value of CS bits in CSR register on standard mode */
+#define SYNQUACER_I2C_CSR_CS_STD_MAX_18M(rate) 0x00
+
+/* calculate the value of CS bits in CCR register on fast mode */
+#define SYNQUACER_I2C_CCR_CS_FAST_MAX_18M(rate) \
+ ((SYNQUACER_I2C_CLK_MASTER_FAST(rate) - 1) \
+ & SYNQUACER_I2C_CCR_CS_MASK)
+
+/* calculate the value of CS bits in CSR register on fast mode */
+#define SYNQUACER_I2C_CSR_CS_FAST_MAX_18M(rate) 0x00
+
+/* (clkrate > 18000000) */
+/* calculate the value of CS bits in CCR register on standard mode */
+#define SYNQUACER_I2C_CCR_CS_STD_MIN_18M(rate) \
+ ((SYNQUACER_I2C_CLK_MASTER_STD(rate) - 1) \
+ & SYNQUACER_I2C_CCR_CS_MASK)
+
+/* calculate the value of CS bits in CSR register on standard mode */
+#define SYNQUACER_I2C_CSR_CS_STD_MIN_18M(rate) \
+ (((SYNQUACER_I2C_CLK_MASTER_STD(rate) - 1) >> 5) \
+ & SYNQUACER_I2C_CSR_CS_MASK)
+
+/* calculate the value of CS bits in CCR register on fast mode */
+#define SYNQUACER_I2C_CCR_CS_FAST_MIN_18M(rate) \
+ ((SYNQUACER_I2C_CLK_MASTER_FAST(rate) - 1) \
+ & SYNQUACER_I2C_CCR_CS_MASK)
+
+/* calculate the value of CS bits in CSR register on fast mode */
+#define SYNQUACER_I2C_CSR_CS_FAST_MIN_18M(rate) \
+ (((SYNQUACER_I2C_CLK_MASTER_FAST(rate) - 1) >> 5) \
+ & SYNQUACER_I2C_CSR_CS_MASK)
+
+/* min I2C clock frequency 14M */
+#define SYNQUACER_I2C_MIN_CLK_RATE (14 * 1000000)
+/* max I2C clock frequency 200M */
+#define SYNQUACER_I2C_MAX_CLK_RATE (200 * 1000000)
+/* I2C clock frequency 18M */
+#define SYNQUACER_I2C_CLK_RATE_18M (18 * 1000000)
+
+#define SYNQUACER_I2C_SPEED_FM 400 // Fast Mode
+#define SYNQUACER_I2C_SPEED_SM 100 // Standard Mode
+
+enum i2c_state {
+ STATE_IDLE,
+ STATE_START,
+ STATE_READ,
+ STATE_WRITE
+};
+
+struct synquacer_i2c {
+ struct completion completion;
+
+ struct i2c_msg *msg;
+ u32 msg_num;
+ u32 msg_idx;
+ u32 msg_ptr;
+
+ int irq;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *pclk;
+ u32 pclkrate;
+ u32 speed_khz;
+ u32 timeout_ms;
+ enum i2c_state state;
+ struct i2c_adapter adapter;
+
+ bool is_suspended;
+};
+
+static inline int is_lastmsg(struct synquacer_i2c *i2c)
+{
+ return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+static inline int is_msglast(struct synquacer_i2c *i2c)
+{
+ return i2c->msg_ptr == (i2c->msg->len - 1);
+}
+
+static inline int is_msgend(struct synquacer_i2c *i2c)
+{
+ return i2c->msg_ptr >= i2c->msg->len;
+}
+
+static inline unsigned long calc_timeout_ms(struct synquacer_i2c *i2c,
+ struct i2c_msg *msgs,
+ int num)
+{
+ unsigned long bit_count = 0;
+ int i;
+
+ for (i = 0; i < num; i++, msgs++)
+ bit_count += msgs->len;
+
+ return DIV_ROUND_UP((bit_count * 9 + num * 10) * 3, 200) + 10;
+}
+
+static void synquacer_i2c_stop(struct synquacer_i2c *i2c, int ret)
+{
+ /*
+ * clear IRQ (INT=0, BER=0)
+ * set Stop Condition (MSS=0)
+ * Interrupt Disable
+ */
+ writeb(0, i2c->base + SYNQUACER_I2C_REG_BCR);
+
+ i2c->state = STATE_IDLE;
+
+ i2c->msg_ptr = 0;
+ i2c->msg = NULL;
+ i2c->msg_idx++;
+ i2c->msg_num = 0;
+ if (ret)
+ i2c->msg_idx = ret;
+
+ complete(&i2c->completion);
+}
+
+static void synquacer_i2c_hw_init(struct synquacer_i2c *i2c)
+{
+ unsigned char ccr_cs, csr_cs;
+ u32 rt = i2c->pclkrate;
+
+ /* Set own Address */
+ writeb(0, i2c->base + SYNQUACER_I2C_REG_ADR);
+
+ /* Set PCLK frequency */
+ writeb(SYNQUACER_I2C_BUS_CLK_FR(i2c->pclkrate),
+ i2c->base + SYNQUACER_I2C_REG_FSR);
+
+ switch (i2c->speed_khz) {
+ case SYNQUACER_I2C_SPEED_FM:
+ if (i2c->pclkrate <= SYNQUACER_I2C_CLK_RATE_18M) {
+ ccr_cs = SYNQUACER_I2C_CCR_CS_FAST_MAX_18M(rt);
+ csr_cs = SYNQUACER_I2C_CSR_CS_FAST_MAX_18M(rt);
+ } else {
+ ccr_cs = SYNQUACER_I2C_CCR_CS_FAST_MIN_18M(rt);
+ csr_cs = SYNQUACER_I2C_CSR_CS_FAST_MIN_18M(rt);
+ }
+
+ /* Set Clock and enable, Set fast mode */
+ writeb(ccr_cs | SYNQUACER_I2C_CCR_FM |
+ SYNQUACER_I2C_CCR_EN,
+ i2c->base + SYNQUACER_I2C_REG_CCR);
+ writeb(csr_cs, i2c->base + SYNQUACER_I2C_REG_CSR);
+ break;
+ case SYNQUACER_I2C_SPEED_SM:
+ if (i2c->pclkrate <= SYNQUACER_I2C_CLK_RATE_18M) {
+ ccr_cs = SYNQUACER_I2C_CCR_CS_STD_MAX_18M(rt);
+ csr_cs = SYNQUACER_I2C_CSR_CS_STD_MAX_18M(rt);
+ } else {
+ ccr_cs = SYNQUACER_I2C_CCR_CS_STD_MIN_18M(rt);
+ csr_cs = SYNQUACER_I2C_CSR_CS_STD_MIN_18M(rt);
+ }
+
+ /* Set Clock and enable, Set standard mode */
+ writeb(ccr_cs | SYNQUACER_I2C_CCR_EN,
+ i2c->base + SYNQUACER_I2C_REG_CCR);
+ writeb(csr_cs, i2c->base + SYNQUACER_I2C_REG_CSR);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ /* clear IRQ (INT=0, BER=0), Interrupt Disable */
+ writeb(0, i2c->base + SYNQUACER_I2C_REG_BCR);
+ writeb(0, i2c->base + SYNQUACER_I2C_REG_BC2R);
+}
+
+static void synquacer_i2c_hw_reset(struct synquacer_i2c *i2c)
+{
+ /* Disable clock */
+ writeb(0, i2c->base + SYNQUACER_I2C_REG_CCR);
+ writeb(0, i2c->base + SYNQUACER_I2C_REG_CSR);
+
+ WAIT_PCLK(100, i2c->pclkrate);
+}
+
+static int synquacer_i2c_master_start(struct synquacer_i2c *i2c,
+ struct i2c_msg *pmsg)
+{
+ unsigned char bsr, bcr;
+
+ writeb(i2c_8bit_addr_from_msg(pmsg), i2c->base + SYNQUACER_I2C_REG_DAR);
+
+ dev_dbg(i2c->dev, "slave:0x%02x\n", pmsg->addr);
+
+ /* Generate Start Condition */
+ bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR);
+ bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR);
+ dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr);
+
+ if ((bsr & SYNQUACER_I2C_BSR_BB) &&
+ !(bcr & SYNQUACER_I2C_BCR_MSS)) {
+ dev_dbg(i2c->dev, "bus is busy");
+ return -EBUSY;
+ }
+
+ if (bsr & SYNQUACER_I2C_BSR_BB) { /* Bus is busy */
+ dev_dbg(i2c->dev, "Continuous Start");
+ writeb(bcr | SYNQUACER_I2C_BCR_SCC,
+ i2c->base + SYNQUACER_I2C_REG_BCR);
+ } else {
+ if (bcr & SYNQUACER_I2C_BCR_MSS) {
+ dev_dbg(i2c->dev, "not in master mode");
+ return -EAGAIN;
+ }
+ dev_dbg(i2c->dev, "Start Condition");
+ /* Start Condition + Enable Interrupts */
+ writeb(bcr | SYNQUACER_I2C_BCR_MSS |
+ SYNQUACER_I2C_BCR_INTE | SYNQUACER_I2C_BCR_BEIE,
+ i2c->base + SYNQUACER_I2C_REG_BCR);
+ }
+
+ WAIT_PCLK(10, i2c->pclkrate);
+
+ /* get BSR & BCR registers */
+ bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR);
+ bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR);
+ dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr);
+
+ if ((bsr & SYNQUACER_I2C_BSR_AL) ||
+ !(bcr & SYNQUACER_I2C_BCR_MSS)) {
+ dev_dbg(i2c->dev, "arbitration lost\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c,
+ struct i2c_msg *msgs, int num)
+{
+ unsigned char bsr;
+ unsigned long timeout;
+ int ret;
+
+ if (i2c->is_suspended)
+ return -EBUSY;
+
+ synquacer_i2c_hw_init(i2c);
+ bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR);
+ if (bsr & SYNQUACER_I2C_BSR_BB) {
+ dev_err(i2c->dev, "cannot get bus (bus busy)\n");
+ return -EBUSY;
+ }
+
+ reinit_completion(&i2c->completion);
+
+ i2c->msg = msgs;
+ i2c->msg_num = num;
+ i2c->msg_ptr = 0;
+ i2c->msg_idx = 0;
+ i2c->state = STATE_START;
+
+ ret = synquacer_i2c_master_start(i2c, i2c->msg);
+ if (ret < 0) {
+ dev_dbg(i2c->dev, "Address failed: (%d)\n", ret);
+ return ret;
+ }
+
+ timeout = wait_for_completion_timeout(&i2c->completion,
+ msecs_to_jiffies(i2c->timeout_ms));
+ if (timeout == 0) {
+ dev_dbg(i2c->dev, "timeout\n");
+ return -EAGAIN;
+ }
+
+ ret = i2c->msg_idx;
+ if (ret != num) {
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+ return -EAGAIN;
+ }
+
+ /* wait 2 clock periods to ensure the stop has been through the bus */
+ udelay(DIV_ROUND_UP(2 * 1000, i2c->speed_khz));
+
+ return ret;
+}
+
+static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
+{
+ struct synquacer_i2c *i2c = dev_id;
+
+ unsigned char byte;
+ unsigned char bsr, bcr;
+ int ret;
+
+ bcr = readb(i2c->base + SYNQUACER_I2C_REG_BCR);
+ bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR);
+ dev_dbg(i2c->dev, "bsr:0x%02x, bcr:0x%02x\n", bsr, bcr);
+
+ if (bcr & SYNQUACER_I2C_BCR_BER) {
+ dev_err(i2c->dev, "bus error\n");
+ synquacer_i2c_stop(i2c, -EAGAIN);
+ goto out;
+ }
+ if ((bsr & SYNQUACER_I2C_BSR_AL) ||
+ !(bcr & SYNQUACER_I2C_BCR_MSS)) {
+ dev_dbg(i2c->dev, "arbitration lost\n");
+ synquacer_i2c_stop(i2c, -EAGAIN);
+ goto out;
+ }
+
+ switch (i2c->state) {
+ case STATE_START:
+ if (bsr & SYNQUACER_I2C_BSR_LRB) {
+ dev_dbg(i2c->dev, "ack was not received\n");
+ synquacer_i2c_stop(i2c, -EAGAIN);
+ goto out;
+ }
+
+ if (i2c->msg->flags & I2C_M_RD)
+ i2c->state = STATE_READ;
+ else
+ i2c->state = STATE_WRITE;
+
+ if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+ synquacer_i2c_stop(i2c, 0);
+ goto out;
+ }
+
+ if (i2c->state == STATE_READ)
+ goto prepare_read;
+
+ /* fallthru */
+
+ case STATE_WRITE:
+ if (bsr & SYNQUACER_I2C_BSR_LRB) {
+ dev_dbg(i2c->dev, "WRITE: No Ack\n");
+ synquacer_i2c_stop(i2c, -EAGAIN);
+ goto out;
+ }
+
+ if (!is_msgend(i2c)) {
+ writeb(i2c->msg->buf[i2c->msg_ptr++],
+ i2c->base + SYNQUACER_I2C_REG_DAR);
+
+ /* clear IRQ, and continue */
+ writeb(SYNQUACER_I2C_BCR_BEIE |
+ SYNQUACER_I2C_BCR_MSS |
+ SYNQUACER_I2C_BCR_INTE,
+ i2c->base + SYNQUACER_I2C_REG_BCR);
+ break;
+ }
+ if (is_lastmsg(i2c)) {
+ synquacer_i2c_stop(i2c, 0);
+ break;
+ }
+ dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+
+ /* send the new start */
+ ret = synquacer_i2c_master_start(i2c, i2c->msg);
+ if (ret < 0) {
+ dev_dbg(i2c->dev, "restart error (%d)\n", ret);
+ synquacer_i2c_stop(i2c, -EAGAIN);
+ break;
+ }
+ i2c->state = STATE_START;
+ break;
+
+ case STATE_READ:
+ byte = readb(i2c->base + SYNQUACER_I2C_REG_DAR);
+ if (!(bsr & SYNQUACER_I2C_BSR_FBT)) /* data */
+ i2c->msg->buf[i2c->msg_ptr++] = byte;
+ else /* address */
+ dev_dbg(i2c->dev, "address:0x%02x. ignore it.\n", byte);
+
+prepare_read:
+ if (is_msglast(i2c)) {
+ writeb(SYNQUACER_I2C_BCR_MSS |
+ SYNQUACER_I2C_BCR_BEIE |
+ SYNQUACER_I2C_BCR_INTE,
+ i2c->base + SYNQUACER_I2C_REG_BCR);
+ break;
+ }
+ if (!is_msgend(i2c)) {
+ writeb(SYNQUACER_I2C_BCR_MSS |
+ SYNQUACER_I2C_BCR_BEIE |
+ SYNQUACER_I2C_BCR_INTE |
+ SYNQUACER_I2C_BCR_ACK,
+ i2c->base + SYNQUACER_I2C_REG_BCR);
+ break;
+ }
+ if (is_lastmsg(i2c)) {
+ /* last message, send stop and complete */
+ dev_dbg(i2c->dev, "READ: Send Stop\n");
+ synquacer_i2c_stop(i2c, 0);
+ break;
+ }
+ dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+ i2c->msg_ptr = 0;
+ i2c->msg_idx++;
+ i2c->msg++;
+
+ ret = synquacer_i2c_master_start(i2c, i2c->msg);
+ if (ret < 0) {
+ dev_dbg(i2c->dev, "restart error (%d)\n", ret);
+ synquacer_i2c_stop(i2c, -EAGAIN);
+ } else {
+ i2c->state = STATE_START;
+ }
+ break;
+ default:
+ dev_err(i2c->dev, "called in err STATE (%d)\n", i2c->state);
+ break;
+ }
+
+out:
+ WAIT_PCLK(10, i2c->pclkrate);
+ return IRQ_HANDLED;
+}
+
+static int synquacer_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct synquacer_i2c *i2c;
+ int retry;
+ int ret;
+
+ i2c = i2c_get_adapdata(adap);
+ i2c->timeout_ms = calc_timeout_ms(i2c, msgs, num);
+
+ dev_dbg(i2c->dev, "calculated timeout %d ms\n", i2c->timeout_ms);
+
+ for (retry = 0; retry <= adap->retries; retry++) {
+ ret = synquacer_i2c_doxfer(i2c, msgs, num);
+ if (ret != -EAGAIN)
+ return ret;
+
+ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+ synquacer_i2c_hw_reset(i2c);
+ }
+ return -EIO;
+}
+
+static u32 synquacer_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm synquacer_i2c_algo = {
+ .master_xfer = synquacer_i2c_xfer,
+ .functionality = synquacer_i2c_functionality,
+};
+
+static struct i2c_adapter synquacer_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "synquacer_i2c-adapter",
+ .algo = &synquacer_i2c_algo,
+ .retries = 5,
+};
+
+static int synquacer_i2c_probe(struct platform_device *pdev)
+{
+ struct synquacer_i2c *i2c;
+ struct resource *r;
+ u32 bus_speed;
+ int ret;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ bus_speed = i2c_acpi_find_bus_speed(&pdev->dev);
+ if (!bus_speed)
+ device_property_read_u32(&pdev->dev, "clock-frequency",
+ &bus_speed);
+
+ device_property_read_u32(&pdev->dev, "socionext,pclk-rate",
+ &i2c->pclkrate);
+
+ i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(i2c->pclk) && PTR_ERR(i2c->pclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR_OR_NULL(i2c->pclk)) {
+ dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk);
+
+ ret = clk_prepare_enable(i2c->pclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock (%d)\n",
+ ret);
+ return ret;
+ }
+ i2c->pclkrate = clk_get_rate(i2c->pclk);
+ }
+
+ if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE ||
+ i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) {
+ dev_err(&pdev->dev, "PCLK missing or out of range (%d)\n",
+ i2c->pclkrate);
+ return -EINVAL;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ i2c->irq = platform_get_irq(pdev, 0);
+ if (i2c->irq < 0) {
+ dev_err(&pdev->dev, "no IRQ resource found\n");
+ return -ENODEV;
+ }
+
+ ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr,
+ 0, dev_name(&pdev->dev), i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ return ret;
+ }
+
+ i2c->state = STATE_IDLE;
+ i2c->dev = &pdev->dev;
+ i2c->adapter = synquacer_i2c_ops;
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ i2c->adapter.dev.parent = &pdev->dev;
+ i2c->adapter.dev.of_node = pdev->dev.of_node;
+ ACPI_COMPANION_SET(&i2c->adapter.dev, ACPI_COMPANION(&pdev->dev));
+ i2c->adapter.nr = pdev->id;
+ init_completion(&i2c->completion);
+
+ if (bus_speed < 400000)
+ i2c->speed_khz = SYNQUACER_I2C_SPEED_SM;
+ else
+ i2c->speed_khz = SYNQUACER_I2C_SPEED_FM;
+
+ synquacer_i2c_hw_init(i2c);
+
+ ret = i2c_add_numbered_adapter(&i2c->adapter);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ dev_info(&pdev->dev, "%s: synquacer_i2c adapter\n",
+ dev_name(&i2c->adapter.dev));
+
+ return 0;
+}
+
+static int synquacer_i2c_remove(struct platform_device *pdev)
+{
+ struct synquacer_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adapter);
+ if (!IS_ERR(i2c->pclk))
+ clk_disable_unprepare(i2c->pclk);
+
+ return 0;
+};
+
+static const struct of_device_id synquacer_i2c_dt_ids[] = {
+ { .compatible = "socionext,synquacer-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, synquacer_i2c_dt_ids);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id synquacer_i2c_acpi_ids[] = {
+ { "SCX0003" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, synquacer_i2c_acpi_ids);
+#endif
+
+static struct platform_driver synquacer_i2c_driver = {
+ .probe = synquacer_i2c_probe,
+ .remove = synquacer_i2c_remove,
+ .driver = {
+ .name = "synquacer_i2c",
+ .of_match_table = of_match_ptr(synquacer_i2c_dt_ids),
+ .acpi_match_table = ACPI_PTR(synquacer_i2c_acpi_ids),
+ },
+};
+module_platform_driver(synquacer_i2c_driver);
+
+MODULE_AUTHOR("Fujitsu Semiconductor Ltd");
+MODULE_DESCRIPTION("Socionext SynQuacer I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
new file mode 100644
index 000000000..7c7fc0111
--- /dev/null
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -0,0 +1,319 @@
+/*
+ * Driver for the TAOS evaluation modules
+ * These devices include an I2C master which can be controlled over the
+ * serial port.
+ *
+ * Copyright (C) 2007 Jean Delvare <jdelvare@suse.de>
+ *
+ * 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 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#define TAOS_BUFFER_SIZE 63
+
+#define TAOS_STATE_INIT 0
+#define TAOS_STATE_IDLE 1
+#define TAOS_STATE_EOFF 2
+#define TAOS_STATE_RECV 3
+
+#define TAOS_CMD_RESET 0x12
+#define TAOS_CMD_ECHO_ON '+'
+#define TAOS_CMD_ECHO_OFF '-'
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+struct taos_data {
+ struct i2c_adapter adapter;
+ struct i2c_client *client;
+ int state;
+ u8 addr; /* last used address */
+ unsigned char buffer[TAOS_BUFFER_SIZE];
+ unsigned int pos; /* position inside the buffer */
+};
+
+/* TAOS TSL2550 EVM */
+static struct i2c_board_info tsl2550_info = {
+ I2C_BOARD_INFO("tsl2550", 0x39),
+};
+
+/* Instantiate i2c devices based on the adapter name */
+static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
+{
+ if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
+ dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
+ tsl2550_info.type, tsl2550_info.addr);
+ return i2c_new_device(adapter, &tsl2550_info);
+ }
+
+ return NULL;
+}
+
+static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct serio *serio = adapter->algo_data;
+ struct taos_data *taos = serio_get_drvdata(serio);
+ char *p;
+
+ /* Encode our transaction. "@" is for the device address, "$" for the
+ SMBus command and "#" for the data. */
+ p = taos->buffer;
+
+ /* The device remembers the last used address, no need to send it
+ again if it's the same */
+ if (addr != taos->addr)
+ p += sprintf(p, "@%02X", addr);
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ sprintf(p, "$#%02X", command);
+ else
+ sprintf(p, "$");
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_WRITE)
+ sprintf(p, "$%02X#%02X", command, data->byte);
+ else
+ sprintf(p, "$%02X", command);
+ break;
+ default:
+ dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ /* Send the transaction to the TAOS EVM */
+ dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
+ for (p = taos->buffer; *p; p++)
+ serio_write(serio, *p);
+
+ taos->addr = addr;
+
+ /* Start the transaction and read the answer */
+ taos->pos = 0;
+ taos->state = TAOS_STATE_RECV;
+ serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(150));
+ if (taos->state != TAOS_STATE_IDLE
+ || taos->pos != 5) {
+ dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
+ taos->pos);
+ return -EIO;
+ }
+ dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
+
+ /* Interpret the returned string */
+ p = taos->buffer + 1;
+ p[3] = '\0';
+ if (!strcmp(p, "NAK"))
+ return -ENODEV;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ if (!strcmp(p, "ACK"))
+ return 0;
+ } else {
+ if (p[0] == 'x') {
+ /*
+ * Voluntarily dropping error code of kstrtou8 since all
+ * error code that it could return are invalid according
+ * to Documentation/i2c/fault-codes.
+ */
+ if (kstrtou8(p + 1, 16, &data->byte))
+ return -EPROTO;
+ return 0;
+ }
+ }
+
+ return -EIO;
+}
+
+static u32 taos_smbus_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm taos_algorithm = {
+ .smbus_xfer = taos_smbus_xfer,
+ .functionality = taos_smbus_func,
+};
+
+static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
+ unsigned int flags)
+{
+ struct taos_data *taos = serio_get_drvdata(serio);
+
+ switch (taos->state) {
+ case TAOS_STATE_INIT:
+ taos->buffer[taos->pos++] = data;
+ if (data == ':'
+ || taos->pos == TAOS_BUFFER_SIZE - 1) {
+ taos->buffer[taos->pos] = '\0';
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ case TAOS_STATE_EOFF:
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ break;
+ case TAOS_STATE_RECV:
+ taos->buffer[taos->pos++] = data;
+ if (data == ']') {
+ taos->buffer[taos->pos] = '\0';
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Extract the adapter name from the buffer received after reset.
+ The buffer is modified and a pointer inside the buffer is returned. */
+static char *taos_adapter_name(char *buffer)
+{
+ char *start, *end;
+
+ start = strstr(buffer, "TAOS ");
+ if (!start)
+ return NULL;
+
+ end = strchr(start, '\r');
+ if (!end)
+ return NULL;
+ *end = '\0';
+
+ return start;
+}
+
+static int taos_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct taos_data *taos;
+ struct i2c_adapter *adapter;
+ char *name;
+ int err;
+
+ taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
+ if (!taos) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ taos->state = TAOS_STATE_INIT;
+ serio_set_drvdata(serio, taos);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto exit_kfree;
+
+ adapter = &taos->adapter;
+ adapter->owner = THIS_MODULE;
+ adapter->algo = &taos_algorithm;
+ adapter->algo_data = serio;
+ adapter->dev.parent = &serio->dev;
+
+ /* Reset the TAOS evaluation module to identify it */
+ serio_write(serio, TAOS_CMD_RESET);
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(2000));
+
+ if (taos->state != TAOS_STATE_IDLE) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, "
+ "pos=%d)\n", taos->state, taos->pos);
+ goto exit_close;
+ }
+
+ name = taos_adapter_name(taos->buffer);
+ if (!name) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM identification failed\n");
+ goto exit_close;
+ }
+ strlcpy(adapter->name, name, sizeof(adapter->name));
+
+ /* Turn echo off for better performance */
+ taos->state = TAOS_STATE_EOFF;
+ serio_write(serio, TAOS_CMD_ECHO_OFF);
+
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(250));
+ if (taos->state != TAOS_STATE_IDLE) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM echo off failed "
+ "(state=%d)\n", taos->state);
+ goto exit_close;
+ }
+
+ err = i2c_add_adapter(adapter);
+ if (err)
+ goto exit_close;
+ dev_info(&serio->dev, "Connected to TAOS EVM\n");
+
+ taos->client = taos_instantiate_device(adapter);
+ return 0;
+
+ exit_close:
+ serio_close(serio);
+ exit_kfree:
+ kfree(taos);
+ exit:
+ return err;
+}
+
+static void taos_disconnect(struct serio *serio)
+{
+ struct taos_data *taos = serio_get_drvdata(serio);
+
+ i2c_unregister_device(taos->client);
+ i2c_del_adapter(&taos->adapter);
+ serio_close(serio);
+ kfree(taos);
+
+ dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
+}
+
+static const struct serio_device_id taos_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_TAOSEVM,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(serio, taos_serio_ids);
+
+static struct serio_driver taos_drv = {
+ .driver = {
+ .name = "taos-evm",
+ },
+ .description = "TAOS evaluation module driver",
+ .id_table = taos_serio_ids,
+ .connect = taos_connect,
+ .disconnect = taos_disconnect,
+ .interrupt = taos_interrupt,
+};
+
+module_serio_driver(taos_drv);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("TAOS evaluation module driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c
new file mode 100644
index 000000000..240bd1e90
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tegra-bpmp.c
@@ -0,0 +1,346 @@
+/*
+ * drivers/i2c/busses/i2c-tegra-bpmp.c
+ *
+ * Copyright (c) 2016 NVIDIA Corporation. All rights reserved.
+ *
+ * Author: Shardar Shariff Md <smohammed@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.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 <soc/tegra/bpmp-abi.h>
+#include <soc/tegra/bpmp.h>
+
+/*
+ * Serialized I2C message header size is 6 bytes and includes address, flags
+ * and length
+ */
+#define SERIALI2C_HDR_SIZE 6
+
+struct tegra_bpmp_i2c {
+ struct i2c_adapter adapter;
+ struct device *dev;
+
+ struct tegra_bpmp *bpmp;
+ unsigned int bus;
+};
+
+/*
+ * Linux flags are translated to BPMP defined I2C flags that are used in BPMP
+ * firmware I2C driver to avoid any issues in future if Linux I2C flags are
+ * changed.
+ */
+static int tegra_bpmp_xlate_flags(u16 flags, u16 *out)
+{
+ if (flags & I2C_M_TEN) {
+ *out |= SERIALI2C_TEN;
+ flags &= ~I2C_M_TEN;
+ }
+
+ if (flags & I2C_M_RD) {
+ *out |= SERIALI2C_RD;
+ flags &= ~I2C_M_RD;
+ }
+
+ if (flags & I2C_M_STOP) {
+ *out |= SERIALI2C_STOP;
+ flags &= ~I2C_M_STOP;
+ }
+
+ if (flags & I2C_M_NOSTART) {
+ *out |= SERIALI2C_NOSTART;
+ flags &= ~I2C_M_NOSTART;
+ }
+
+ if (flags & I2C_M_REV_DIR_ADDR) {
+ *out |= SERIALI2C_REV_DIR_ADDR;
+ flags &= ~I2C_M_REV_DIR_ADDR;
+ }
+
+ if (flags & I2C_M_IGNORE_NAK) {
+ *out |= SERIALI2C_IGNORE_NAK;
+ flags &= ~I2C_M_IGNORE_NAK;
+ }
+
+ if (flags & I2C_M_NO_RD_ACK) {
+ *out |= SERIALI2C_NO_RD_ACK;
+ flags &= ~I2C_M_NO_RD_ACK;
+ }
+
+ if (flags & I2C_M_RECV_LEN) {
+ *out |= SERIALI2C_RECV_LEN;
+ flags &= ~I2C_M_RECV_LEN;
+ }
+
+ return 0;
+}
+
+/**
+ * The serialized I2C format is simply the following:
+ * [addr little-endian][flags little-endian][len little-endian][data if write]
+ * [addr little-endian][flags little-endian][len little-endian][data if write]
+ * ...
+ *
+ * The flags are translated from Linux kernel representation to seriali2c
+ * representation. Any undefined flag being set causes an error.
+ *
+ * The data is there only for writes. Reads have the data transferred in the
+ * other direction, and thus data is not present.
+ *
+ * See deserialize_i2c documentation for the data format in the other direction.
+ */
+static int tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
+ struct mrq_i2c_request *request,
+ struct i2c_msg *msgs,
+ unsigned int num)
+{
+ char *buf = request->xfer.data_buf;
+ unsigned int i, j, pos = 0;
+ int err;
+
+ for (i = 0; i < num; i++) {
+ struct i2c_msg *msg = &msgs[i];
+ u16 flags = 0;
+
+ err = tegra_bpmp_xlate_flags(msg->flags, &flags);
+ if (err < 0)
+ return err;
+
+ buf[pos++] = msg->addr & 0xff;
+ buf[pos++] = (msg->addr & 0xff00) >> 8;
+ buf[pos++] = flags & 0xff;
+ buf[pos++] = (flags & 0xff00) >> 8;
+ buf[pos++] = msg->len & 0xff;
+ buf[pos++] = (msg->len & 0xff00) >> 8;
+
+ if ((flags & SERIALI2C_RD) == 0) {
+ for (j = 0; j < msg->len; j++)
+ buf[pos++] = msg->buf[j];
+ }
+ }
+
+ request->xfer.data_size = pos;
+
+ return 0;
+}
+
+/**
+ * The data in the BPMP -> CPU direction is composed of sequential blocks for
+ * those messages that have I2C_M_RD. So, for example, if you have:
+ *
+ * - !I2C_M_RD, len == 5, data == a0 01 02 03 04
+ * - !I2C_M_RD, len == 1, data == a0
+ * - I2C_M_RD, len == 2, data == [uninitialized buffer 1]
+ * - !I2C_M_RD, len == 1, data == a2
+ * - I2C_M_RD, len == 2, data == [uninitialized buffer 2]
+ *
+ * ...then the data in the BPMP -> CPU direction would be 4 bytes total, and
+ * would contain 2 bytes that will go to uninitialized buffer 1, and 2 bytes
+ * that will go to uninitialized buffer 2.
+ */
+static int tegra_bpmp_i2c_deserialize(struct tegra_bpmp_i2c *i2c,
+ struct mrq_i2c_response *response,
+ struct i2c_msg *msgs,
+ unsigned int num)
+{
+ size_t size = response->xfer.data_size, len = 0, pos = 0;
+ char *buf = response->xfer.data_buf;
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (msgs[i].flags & I2C_M_RD)
+ len += msgs[i].len;
+
+ if (len != size)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ if (msgs[i].flags & I2C_M_RD) {
+ memcpy(msgs[i].buf, buf + pos, msgs[i].len);
+ pos += msgs[i].len;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra_bpmp_i2c_msg_len_check(struct i2c_msg *msgs, unsigned int num)
+{
+ size_t tx_len = 0, rx_len = 0;
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (!(msgs[i].flags & I2C_M_RD))
+ tx_len += SERIALI2C_HDR_SIZE + msgs[i].len;
+
+ if (tx_len > TEGRA_I2C_IPC_MAX_IN_BUF_SIZE)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++)
+ if ((msgs[i].flags & I2C_M_RD))
+ rx_len += msgs[i].len;
+
+ if (rx_len > TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
+ struct mrq_i2c_request *request,
+ struct mrq_i2c_response *response)
+{
+ struct tegra_bpmp_message msg;
+ int err;
+
+ request->cmd = CMD_I2C_XFER;
+ request->xfer.bus_id = i2c->bus;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_I2C;
+ msg.tx.data = request;
+ msg.tx.size = sizeof(*request);
+ msg.rx.data = response;
+ msg.rx.size = sizeof(*response);
+
+ if (irqs_disabled())
+ err = tegra_bpmp_transfer_atomic(i2c->bpmp, &msg);
+ else
+ err = tegra_bpmp_transfer(i2c->bpmp, &msg);
+
+ return err;
+}
+
+static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct tegra_bpmp_i2c *i2c = i2c_get_adapdata(adapter);
+ struct mrq_i2c_response response;
+ struct mrq_i2c_request request;
+ int err;
+
+ err = tegra_bpmp_i2c_msg_len_check(msgs, num);
+ if (err < 0) {
+ dev_err(i2c->dev, "unsupported message length\n");
+ return err;
+ }
+
+ memset(&request, 0, sizeof(request));
+ memset(&response, 0, sizeof(response));
+
+ err = tegra_bpmp_serialize_i2c_msg(i2c, &request, msgs, num);
+ if (err < 0) {
+ dev_err(i2c->dev, "failed to serialize message: %d\n", err);
+ return err;
+ }
+
+ err = tegra_bpmp_i2c_msg_xfer(i2c, &request, &response);
+ if (err < 0) {
+ dev_err(i2c->dev, "failed to transfer message: %d\n", err);
+ return err;
+ }
+
+ err = tegra_bpmp_i2c_deserialize(i2c, &response, msgs, num);
+ if (err < 0) {
+ dev_err(i2c->dev, "failed to deserialize message: %d\n", err);
+ return err;
+ }
+
+ return num;
+}
+
+static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm tegra_bpmp_i2c_algo = {
+ .master_xfer = tegra_bpmp_i2c_xfer,
+ .functionality = tegra_bpmp_i2c_func,
+};
+
+static int tegra_bpmp_i2c_probe(struct platform_device *pdev)
+{
+ struct tegra_bpmp_i2c *i2c;
+ u32 value;
+ int err;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->dev = &pdev->dev;
+
+ i2c->bpmp = dev_get_drvdata(pdev->dev.parent);
+ if (!i2c->bpmp)
+ return -ENODEV;
+
+ err = of_property_read_u32(pdev->dev.of_node, "nvidia,bpmp-bus-id",
+ &value);
+ if (err < 0)
+ return err;
+
+ i2c->bus = value;
+
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ i2c->adapter.owner = THIS_MODULE;
+ strlcpy(i2c->adapter.name, "Tegra BPMP I2C adapter",
+ sizeof(i2c->adapter.name));
+ i2c->adapter.algo = &tegra_bpmp_i2c_algo;
+ i2c->adapter.dev.parent = &pdev->dev;
+ i2c->adapter.dev.of_node = pdev->dev.of_node;
+
+ platform_set_drvdata(pdev, i2c);
+
+ return i2c_add_adapter(&i2c->adapter);
+}
+
+static int tegra_bpmp_i2c_remove(struct platform_device *pdev)
+{
+ struct tegra_bpmp_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id tegra_bpmp_i2c_of_match[] = {
+ { .compatible = "nvidia,tegra186-bpmp-i2c", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tegra_bpmp_i2c_of_match);
+
+static struct platform_driver tegra_bpmp_i2c_driver = {
+ .driver = {
+ .name = "tegra-bpmp-i2c",
+ .of_match_table = tegra_bpmp_i2c_of_match,
+ },
+ .probe = tegra_bpmp_i2c_probe,
+ .remove = tegra_bpmp_i2c_remove,
+};
+module_platform_driver(tegra_bpmp_i2c_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus controller driver");
+MODULE_AUTHOR("Shardar Shariff Md <smohammed@nvidia.com>");
+MODULE_AUTHOR("Juha-Matti Tilli");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
new file mode 100644
index 000000000..af0619885
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -0,0 +1,1169 @@
+/*
+ * drivers/i2c/busses/i2c-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
+
+#include <asm/unaligned.h>
+
+#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
+#define BYTES_PER_FIFO_WORD 4
+
+#define I2C_CNFG 0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
+#define I2C_CNFG_PACKET_MODE_EN BIT(10)
+#define I2C_CNFG_NEW_MASTER_FSM BIT(11)
+#define I2C_CNFG_MULTI_MASTER_MODE BIT(17)
+#define I2C_STATUS 0x01C
+#define I2C_SL_CNFG 0x020
+#define I2C_SL_CNFG_NACK BIT(1)
+#define I2C_SL_CNFG_NEWSL BIT(2)
+#define I2C_SL_ADDR1 0x02c
+#define I2C_SL_ADDR2 0x030
+#define I2C_TX_FIFO 0x050
+#define I2C_RX_FIFO 0x054
+#define I2C_PACKET_TRANSFER_STATUS 0x058
+#define I2C_FIFO_CONTROL 0x05c
+#define I2C_FIFO_CONTROL_TX_FLUSH BIT(1)
+#define I2C_FIFO_CONTROL_RX_FLUSH BIT(0)
+#define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5
+#define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2
+#define I2C_FIFO_STATUS 0x060
+#define I2C_FIFO_STATUS_TX_MASK 0xF0
+#define I2C_FIFO_STATUS_TX_SHIFT 4
+#define I2C_FIFO_STATUS_RX_MASK 0x0F
+#define I2C_FIFO_STATUS_RX_SHIFT 0
+#define I2C_INT_MASK 0x064
+#define I2C_INT_STATUS 0x068
+#define I2C_INT_PACKET_XFER_COMPLETE BIT(7)
+#define I2C_INT_ALL_PACKETS_XFER_COMPLETE BIT(6)
+#define I2C_INT_TX_FIFO_OVERFLOW BIT(5)
+#define I2C_INT_RX_FIFO_UNDERFLOW BIT(4)
+#define I2C_INT_NO_ACK BIT(3)
+#define I2C_INT_ARBITRATION_LOST BIT(2)
+#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
+#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
+#define I2C_CLK_DIVISOR 0x06c
+#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
+#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8
+
+#define DVC_CTRL_REG1 0x000
+#define DVC_CTRL_REG1_INTR_EN BIT(10)
+#define DVC_CTRL_REG2 0x004
+#define DVC_CTRL_REG3 0x008
+#define DVC_CTRL_REG3_SW_PROG BIT(26)
+#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30)
+#define DVC_STATUS 0x00c
+#define DVC_STATUS_I2C_DONE_INTR BIT(30)
+
+#define I2C_ERR_NONE 0x00
+#define I2C_ERR_NO_ACK 0x01
+#define I2C_ERR_ARBITRATION_LOST 0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT 0x04
+
+#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
+#define PACKET_HEADER0_PACKET_ID_SHIFT 16
+#define PACKET_HEADER0_CONT_ID_SHIFT 12
+#define PACKET_HEADER0_PROTOCOL_I2C BIT(4)
+
+#define I2C_HEADER_HIGHSPEED_MODE BIT(22)
+#define I2C_HEADER_CONT_ON_NAK BIT(21)
+#define I2C_HEADER_SEND_START_BYTE BIT(20)
+#define I2C_HEADER_READ BIT(19)
+#define I2C_HEADER_10BIT_ADDR BIT(18)
+#define I2C_HEADER_IE_ENABLE BIT(17)
+#define I2C_HEADER_REPEAT_START BIT(16)
+#define I2C_HEADER_CONTINUE_XFER BIT(15)
+#define I2C_HEADER_MASTER_ADDR_SHIFT 12
+#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
+
+#define I2C_CONFIG_LOAD 0x08C
+#define I2C_MSTR_CONFIG_LOAD BIT(0)
+#define I2C_SLV_CONFIG_LOAD BIT(1)
+#define I2C_TIMEOUT_CONFIG_LOAD BIT(2)
+
+#define I2C_CLKEN_OVERRIDE 0x090
+#define I2C_MST_CORE_CLKEN_OVR BIT(0)
+
+#define I2C_CONFIG_LOAD_TIMEOUT 1000000
+
+#define I2C_MST_FIFO_CONTROL 0x0b4
+#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
+#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1)
+#define I2C_MST_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 4)
+#define I2C_MST_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 16)
+
+#define I2C_MST_FIFO_STATUS 0x0b8
+#define I2C_MST_FIFO_STATUS_RX_MASK 0xff
+#define I2C_MST_FIFO_STATUS_RX_SHIFT 0
+#define I2C_MST_FIFO_STATUS_TX_MASK 0xff0000
+#define I2C_MST_FIFO_STATUS_TX_SHIFT 16
+
+/*
+ * msg_end_type: The bus control which need to be send at end of transfer.
+ * @MSG_END_STOP: Send stop pulse at end of transfer.
+ * @MSG_END_REPEAT_START: Send repeat start at end of transfer.
+ * @MSG_END_CONTINUE: The following on message is coming and so do not send
+ * stop or repeat start.
+ */
+enum msg_end_type {
+ MSG_END_STOP,
+ MSG_END_REPEAT_START,
+ MSG_END_CONTINUE,
+};
+
+/**
+ * struct tegra_i2c_hw_feature : Different HW support on Tegra
+ * @has_continue_xfer_support: Continue transfer supports.
+ * @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
+ * complete interrupt per packet basis.
+ * @has_single_clk_source: The I2C controller has single clock source. Tegra30
+ * and earlier SoCs have two clock sources i.e. div-clk and
+ * fast-clk.
+ * @has_config_load_reg: Has the config load register to load the new
+ * configuration.
+ * @clk_divisor_hs_mode: Clock divisor in HS mode.
+ * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is
+ * applicable if there is no fast clock source i.e. single clock
+ * source.
+ * @clk_divisor_fast_plus_mode: Clock divisor in fast mode plus. It is
+ * applicable if there is no fast clock source (i.e. single
+ * clock source).
+ * @has_multi_master_mode: The I2C controller supports running in single-master
+ * or multi-master mode.
+ * @has_slcg_override_reg: The I2C controller supports a register that
+ * overrides the second level clock gating.
+ * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that
+ * provides additional features and allows for longer messages to
+ * be transferred in one go.
+ * @quirks: i2c adapter quirks for limiting write/read transfer size and not
+ * allowing 0 length transfers.
+ */
+struct tegra_i2c_hw_feature {
+ bool has_continue_xfer_support;
+ bool has_per_pkt_xfer_complete_irq;
+ bool has_single_clk_source;
+ bool has_config_load_reg;
+ int clk_divisor_hs_mode;
+ int clk_divisor_std_fast_mode;
+ u16 clk_divisor_fast_plus_mode;
+ bool has_multi_master_mode;
+ bool has_slcg_override_reg;
+ bool has_mst_fifo;
+ const struct i2c_adapter_quirks *quirks;
+};
+
+/**
+ * struct tegra_i2c_dev - per device I2C context
+ * @dev: device reference for power management
+ * @hw: Tegra I2C HW feature
+ * @adapter: core I2C layer adapter information
+ * @div_clk: clock reference for div clock of I2C controller
+ * @fast_clk: clock reference for fast clock of I2C controller
+ * @rst: reset control for the I2C controller
+ * @base: ioremapped registers cookie
+ * @cont_id: I2C controller ID, used for packet header
+ * @irq: IRQ number of transfer complete interrupt
+ * @irq_disabled: used to track whether or not the interrupt is enabled
+ * @is_dvc: identifies the DVC I2C controller, has a different register layout
+ * @msg_complete: transfer completion notifier
+ * @msg_err: error code for completed message
+ * @msg_buf: pointer to current message data
+ * @msg_buf_remaining: size of unsent data in the message buffer
+ * @msg_read: identifies read transfers
+ * @bus_clk_rate: current I2C bus clock rate
+ * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
+ * @is_multimaster_mode: track if I2C controller is in multi-master mode
+ * @xfer_lock: lock to serialize transfer submission and processing
+ */
+struct tegra_i2c_dev {
+ struct device *dev;
+ const struct tegra_i2c_hw_feature *hw;
+ struct i2c_adapter adapter;
+ struct clk *div_clk;
+ struct clk *fast_clk;
+ struct reset_control *rst;
+ void __iomem *base;
+ int cont_id;
+ int irq;
+ bool irq_disabled;
+ int is_dvc;
+ struct completion msg_complete;
+ int msg_err;
+ u8 *msg_buf;
+ size_t msg_buf_remaining;
+ int msg_read;
+ u32 bus_clk_rate;
+ u16 clk_divisor_non_hs_mode;
+ bool is_multimaster_mode;
+ spinlock_t xfer_lock;
+};
+
+static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
+ unsigned long reg)
+{
+ writel(val, i2c_dev->base + reg);
+}
+
+static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+ return readl(i2c_dev->base + reg);
+}
+
+/*
+ * i2c_writel and i2c_readl will offset the register if necessary to talk
+ * to the I2C block inside the DVC block
+ */
+static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
+ unsigned long reg)
+{
+ if (i2c_dev->is_dvc)
+ reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
+ return reg;
+}
+
+static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
+ unsigned long reg)
+{
+ writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+
+ /* Read back register to make sure that register writes completed */
+ if (reg != I2C_TX_FIFO)
+ readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+ return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
+ unsigned long reg, int len)
+{
+ writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
+ unsigned long reg, int len)
+{
+ readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+ u32 int_mask;
+
+ int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) & ~mask;
+ i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+ u32 int_mask;
+
+ int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask;
+ i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
+{
+ unsigned long timeout = jiffies + HZ;
+ unsigned int offset;
+ u32 mask, val;
+
+ if (i2c_dev->hw->has_mst_fifo) {
+ mask = I2C_MST_FIFO_CONTROL_TX_FLUSH |
+ I2C_MST_FIFO_CONTROL_RX_FLUSH;
+ offset = I2C_MST_FIFO_CONTROL;
+ } else {
+ mask = I2C_FIFO_CONTROL_TX_FLUSH |
+ I2C_FIFO_CONTROL_RX_FLUSH;
+ offset = I2C_FIFO_CONTROL;
+ }
+
+ val = i2c_readl(i2c_dev, offset);
+ val |= mask;
+ i2c_writel(i2c_dev, val, offset);
+
+ while (i2c_readl(i2c_dev, offset) & mask) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int rx_fifo_avail;
+ u8 *buf = i2c_dev->msg_buf;
+ size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ int words_to_transfer;
+
+ if (i2c_dev->hw->has_mst_fifo) {
+ val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
+ rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >>
+ I2C_MST_FIFO_STATUS_RX_SHIFT;
+ } else {
+ val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
+ I2C_FIFO_STATUS_RX_SHIFT;
+ }
+
+ /* Rounds down to not include partial word at the end of buf */
+ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+ if (words_to_transfer > rx_fifo_avail)
+ words_to_transfer = rx_fifo_avail;
+
+ i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ rx_fifo_avail -= words_to_transfer;
+
+ /*
+ * If there is a partial word at the end of buf, handle it manually to
+ * prevent overwriting past the end of buf
+ */
+ if (rx_fifo_avail > 0 && buf_remaining > 0) {
+ BUG_ON(buf_remaining > 3);
+ val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+ val = cpu_to_le32(val);
+ memcpy(buf, &val, buf_remaining);
+ buf_remaining = 0;
+ rx_fifo_avail--;
+ }
+
+ BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf;
+
+ return 0;
+}
+
+static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int tx_fifo_avail;
+ u8 *buf = i2c_dev->msg_buf;
+ size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ int words_to_transfer;
+
+ if (i2c_dev->hw->has_mst_fifo) {
+ val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
+ tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >>
+ I2C_MST_FIFO_STATUS_TX_SHIFT;
+ } else {
+ val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
+ I2C_FIFO_STATUS_TX_SHIFT;
+ }
+
+ /* Rounds down to not include partial word at the end of buf */
+ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+
+ /* It's very common to have < 4 bytes, so optimize that case. */
+ if (words_to_transfer) {
+ if (words_to_transfer > tx_fifo_avail)
+ words_to_transfer = tx_fifo_avail;
+
+ /*
+ * Update state before writing to FIFO. If this casues us
+ * to finish writing all bytes (AKA buf_remaining goes to 0) we
+ * have a potential for an interrupt (PACKET_XFER_COMPLETE is
+ * not maskable). We need to make sure that the isr sees
+ * buf_remaining as 0 and doesn't call us back re-entrantly.
+ */
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ tx_fifo_avail -= words_to_transfer;
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf +
+ words_to_transfer * BYTES_PER_FIFO_WORD;
+ barrier();
+
+ i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ }
+
+ /*
+ * If there is a partial word at the end of buf, handle it manually to
+ * prevent reading past the end of buf, which could cross a page
+ * boundary and fault.
+ */
+ if (tx_fifo_avail > 0 && buf_remaining > 0) {
+ BUG_ON(buf_remaining > 3);
+ memcpy(&val, buf, buf_remaining);
+ val = le32_to_cpu(val);
+
+ /* Again update before writing to FIFO to make sure isr sees. */
+ i2c_dev->msg_buf_remaining = 0;
+ i2c_dev->msg_buf = NULL;
+ barrier();
+
+ i2c_writel(i2c_dev, val, I2C_TX_FIFO);
+ }
+
+ return 0;
+}
+
+/*
+ * One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
+ * block. This block is identical to the rest of the I2C blocks, except that
+ * it only supports master mode, it has registers moved around, and it needs
+ * some extra init to get it into I2C mode. The register moves are handled
+ * by i2c_readl and i2c_writel
+ */
+static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+
+ val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
+ val |= DVC_CTRL_REG3_SW_PROG;
+ val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
+ dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
+
+ val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
+ val |= DVC_CTRL_REG1_INTR_EN;
+ dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
+}
+
+static int tegra_i2c_runtime_resume(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pinctrl_pm_select_default_state(i2c_dev->dev);
+ if (ret)
+ return ret;
+
+ if (!i2c_dev->hw->has_single_clk_source) {
+ ret = clk_enable(i2c_dev->fast_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev,
+ "Enabling fast clk failed, err %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = clk_enable(i2c_dev->div_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev,
+ "Enabling div clk failed, err %d\n", ret);
+ clk_disable(i2c_dev->fast_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra_i2c_runtime_suspend(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ clk_disable(i2c_dev->div_clk);
+ if (!i2c_dev->hw->has_single_clk_source)
+ clk_disable(i2c_dev->fast_clk);
+
+ return pinctrl_pm_select_idle_state(i2c_dev->dev);
+}
+
+static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
+{
+ unsigned long reg_offset;
+ void __iomem *addr;
+ u32 val;
+ int err;
+
+ if (i2c_dev->hw->has_config_load_reg) {
+ reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
+ addr = i2c_dev->base + reg_offset;
+ i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
+ if (in_interrupt())
+ err = readl_poll_timeout_atomic(addr, val, val == 0,
+ 1000, I2C_CONFIG_LOAD_TIMEOUT);
+ else
+ err = readl_poll_timeout(addr, val, val == 0,
+ 1000, I2C_CONFIG_LOAD_TIMEOUT);
+
+ if (err) {
+ dev_warn(i2c_dev->dev,
+ "timeout waiting for config load\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int err;
+ u32 clk_divisor;
+
+ err = pm_runtime_get_sync(i2c_dev->dev);
+ if (err < 0) {
+ dev_err(i2c_dev->dev, "runtime resume failed %d\n", err);
+ return err;
+ }
+
+ reset_control_assert(i2c_dev->rst);
+ udelay(2);
+ reset_control_deassert(i2c_dev->rst);
+
+ if (i2c_dev->is_dvc)
+ tegra_dvc_init(i2c_dev);
+
+ val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+ (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
+
+ if (i2c_dev->hw->has_multi_master_mode)
+ val |= I2C_CNFG_MULTI_MASTER_MODE;
+
+ i2c_writel(i2c_dev, val, I2C_CNFG);
+ i2c_writel(i2c_dev, 0, I2C_INT_MASK);
+
+ /* Make sure clock divisor programmed correctly */
+ clk_divisor = i2c_dev->hw->clk_divisor_hs_mode;
+ clk_divisor |= i2c_dev->clk_divisor_non_hs_mode <<
+ I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT;
+ i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
+
+ if (!i2c_dev->is_dvc) {
+ u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+
+ sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
+ i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
+ i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
+ i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
+ }
+
+ if (i2c_dev->hw->has_mst_fifo) {
+ val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) |
+ I2C_MST_FIFO_CONTROL_RX_TRIG(1);
+ i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL);
+ } else {
+ val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
+ 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
+ i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+ }
+
+ err = tegra_i2c_flush_fifos(i2c_dev);
+ if (err)
+ goto err;
+
+ if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
+ i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
+
+ err = tegra_i2c_wait_for_config_load(i2c_dev);
+ if (err)
+ goto err;
+
+ if (i2c_dev->irq_disabled) {
+ i2c_dev->irq_disabled = false;
+ enable_irq(i2c_dev->irq);
+ }
+
+err:
+ pm_runtime_put(i2c_dev->dev);
+ return err;
+}
+
+static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 cnfg;
+
+ /*
+ * NACK interrupt is generated before the I2C controller generates
+ * the STOP condition on the bus. So wait for 2 clock periods
+ * before disabling the controller so that the STOP condition has
+ * been delivered properly.
+ */
+ udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate));
+
+ cnfg = i2c_readl(i2c_dev, I2C_CNFG);
+ if (cnfg & I2C_CNFG_PACKET_MODE_EN)
+ i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
+
+ return tegra_i2c_wait_for_config_load(i2c_dev);
+}
+
+static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
+{
+ u32 status;
+ const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ struct tegra_i2c_dev *i2c_dev = dev_id;
+ unsigned long flags;
+
+ status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+
+ spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
+ if (status == 0) {
+ dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+ i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+ i2c_readl(i2c_dev, I2C_STATUS),
+ i2c_readl(i2c_dev, I2C_CNFG));
+ i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+ if (!i2c_dev->irq_disabled) {
+ disable_irq_nosync(i2c_dev->irq);
+ i2c_dev->irq_disabled = true;
+ }
+ goto err;
+ }
+
+ if (unlikely(status & status_err)) {
+ tegra_i2c_disable_packet_mode(i2c_dev);
+ if (status & I2C_INT_NO_ACK)
+ i2c_dev->msg_err |= I2C_ERR_NO_ACK;
+ if (status & I2C_INT_ARBITRATION_LOST)
+ i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
+ goto err;
+ }
+
+ if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
+ if (i2c_dev->msg_buf_remaining)
+ tegra_i2c_empty_rx_fifo(i2c_dev);
+ else
+ BUG();
+ }
+
+ if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
+ if (i2c_dev->msg_buf_remaining)
+ tegra_i2c_fill_tx_fifo(i2c_dev);
+ else
+ tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
+ }
+
+ i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ if (i2c_dev->is_dvc)
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+ if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+ BUG_ON(i2c_dev->msg_buf_remaining);
+ complete(&i2c_dev->msg_complete);
+ }
+ goto done;
+err:
+ /* An error occurred, mask all interrupts */
+ tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
+ I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
+ I2C_INT_RX_FIFO_DATA_REQ);
+ i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ if (i2c_dev->is_dvc)
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+ complete(&i2c_dev->msg_complete);
+done:
+ spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, enum msg_end_type end_state)
+{
+ u32 packet_header;
+ u32 int_mask;
+ unsigned long time_left;
+ unsigned long flags;
+
+ tegra_i2c_flush_fifos(i2c_dev);
+
+ i2c_dev->msg_buf = msg->buf;
+ i2c_dev->msg_buf_remaining = msg->len;
+ i2c_dev->msg_err = I2C_ERR_NONE;
+ i2c_dev->msg_read = (msg->flags & I2C_M_RD);
+ reinit_completion(&i2c_dev->msg_complete);
+
+ spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
+
+ int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ tegra_i2c_unmask_irq(i2c_dev, int_mask);
+
+ packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
+ PACKET_HEADER0_PROTOCOL_I2C |
+ (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
+ (1 << PACKET_HEADER0_PACKET_ID_SHIFT);
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ packet_header = msg->len - 1;
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ packet_header = I2C_HEADER_IE_ENABLE;
+ if (end_state == MSG_END_CONTINUE)
+ packet_header |= I2C_HEADER_CONTINUE_XFER;
+ else if (end_state == MSG_END_REPEAT_START)
+ packet_header |= I2C_HEADER_REPEAT_START;
+ if (msg->flags & I2C_M_TEN) {
+ packet_header |= msg->addr;
+ packet_header |= I2C_HEADER_10BIT_ADDR;
+ } else {
+ packet_header |= msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
+ }
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ packet_header |= I2C_HEADER_CONT_ON_NAK;
+ if (msg->flags & I2C_M_RD)
+ packet_header |= I2C_HEADER_READ;
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ if (!(msg->flags & I2C_M_RD))
+ tegra_i2c_fill_tx_fifo(i2c_dev);
+
+ if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
+ int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
+ if (msg->flags & I2C_M_RD)
+ int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
+ else if (i2c_dev->msg_buf_remaining)
+ int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+
+ tegra_i2c_unmask_irq(i2c_dev, int_mask);
+ spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
+ dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
+ i2c_readl(i2c_dev, I2C_INT_MASK));
+
+ time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+ TEGRA_I2C_TIMEOUT);
+ tegra_i2c_mask_irq(i2c_dev, int_mask);
+
+ if (time_left == 0) {
+ dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+
+ tegra_i2c_init(i2c_dev);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(i2c_dev->dev, "transfer complete: %lu %d %d\n",
+ time_left, completion_done(&i2c_dev->msg_complete),
+ i2c_dev->msg_err);
+
+ if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
+ return 0;
+
+ tegra_i2c_init(i2c_dev);
+ if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ return -EREMOTEIO;
+ }
+
+ return -EIO;
+}
+
+static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ int i;
+ int ret = 0;
+
+ ret = pm_runtime_get_sync(i2c_dev->dev);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ enum msg_end_type end_type = MSG_END_STOP;
+
+ if (i < (num - 1)) {
+ if (msgs[i + 1].flags & I2C_M_NOSTART)
+ end_type = MSG_END_CONTINUE;
+ else
+ end_type = MSG_END_REPEAT_START;
+ }
+ ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type);
+ if (ret)
+ break;
+ }
+
+ pm_runtime_put(i2c_dev->dev);
+
+ return ret ?: i;
+}
+
+static u32 tegra_i2c_func(struct i2c_adapter *adap)
+{
+ struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ u32 ret = I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+
+ if (i2c_dev->hw->has_continue_xfer_support)
+ ret |= I2C_FUNC_NOSTART;
+ return ret;
+}
+
+static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
+{
+ struct device_node *np = i2c_dev->dev->of_node;
+ int ret;
+
+ ret = of_property_read_u32(np, "clock-frequency",
+ &i2c_dev->bus_clk_rate);
+ if (ret)
+ i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+
+ i2c_dev->is_multimaster_mode = of_property_read_bool(np,
+ "multi-master");
+}
+
+static const struct i2c_algorithm tegra_i2c_algo = {
+ .master_xfer = tegra_i2c_xfer,
+ .functionality = tegra_i2c_func,
+};
+
+/* payload size is only 12 bit */
+static const struct i2c_adapter_quirks tegra_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+ .max_read_len = 4096,
+ .max_write_len = 4096 - 12,
+};
+
+static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
+ .has_continue_xfer_support = false,
+ .has_per_pkt_xfer_complete_irq = false,
+ .has_single_clk_source = false,
+ .clk_divisor_hs_mode = 3,
+ .clk_divisor_std_fast_mode = 0,
+ .clk_divisor_fast_plus_mode = 0,
+ .has_config_load_reg = false,
+ .has_multi_master_mode = false,
+ .has_slcg_override_reg = false,
+ .has_mst_fifo = false,
+ .quirks = &tegra_i2c_quirks,
+};
+
+static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = false,
+ .has_single_clk_source = false,
+ .clk_divisor_hs_mode = 3,
+ .clk_divisor_std_fast_mode = 0,
+ .clk_divisor_fast_plus_mode = 0,
+ .has_config_load_reg = false,
+ .has_multi_master_mode = false,
+ .has_slcg_override_reg = false,
+ .has_mst_fifo = false,
+ .quirks = &tegra_i2c_quirks,
+};
+
+static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .has_single_clk_source = true,
+ .clk_divisor_hs_mode = 1,
+ .clk_divisor_std_fast_mode = 0x19,
+ .clk_divisor_fast_plus_mode = 0x10,
+ .has_config_load_reg = false,
+ .has_multi_master_mode = false,
+ .has_slcg_override_reg = false,
+ .has_mst_fifo = false,
+ .quirks = &tegra_i2c_quirks,
+};
+
+static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .has_single_clk_source = true,
+ .clk_divisor_hs_mode = 1,
+ .clk_divisor_std_fast_mode = 0x19,
+ .clk_divisor_fast_plus_mode = 0x10,
+ .has_config_load_reg = true,
+ .has_multi_master_mode = false,
+ .has_slcg_override_reg = true,
+ .has_mst_fifo = false,
+ .quirks = &tegra_i2c_quirks,
+};
+
+static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .has_single_clk_source = true,
+ .clk_divisor_hs_mode = 1,
+ .clk_divisor_std_fast_mode = 0x19,
+ .clk_divisor_fast_plus_mode = 0x10,
+ .has_config_load_reg = true,
+ .has_multi_master_mode = true,
+ .has_slcg_override_reg = true,
+ .has_mst_fifo = false,
+ .quirks = &tegra_i2c_quirks,
+};
+
+static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
+ .has_continue_xfer_support = true,
+ .has_per_pkt_xfer_complete_irq = true,
+ .has_single_clk_source = true,
+ .clk_divisor_hs_mode = 1,
+ .clk_divisor_std_fast_mode = 0x19,
+ .clk_divisor_fast_plus_mode = 0x10,
+ .has_config_load_reg = true,
+ .has_multi_master_mode = true,
+ .has_slcg_override_reg = true,
+ .has_mst_fifo = true,
+ .quirks = &tegra194_i2c_quirks,
+};
+
+/* Match table for of_platform binding */
+static const struct of_device_id tegra_i2c_of_match[] = {
+ { .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
+ { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
+ { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
+ { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
+ { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
+ { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
+ { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+
+static int tegra_i2c_probe(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev;
+ struct resource *res;
+ struct clk *div_clk;
+ struct clk *fast_clk;
+ void __iomem *base;
+ int irq;
+ int ret = 0;
+ int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no irq resource\n");
+ return -EINVAL;
+ }
+ irq = res->start;
+
+ div_clk = devm_clk_get(&pdev->dev, "div-clk");
+ if (IS_ERR(div_clk)) {
+ dev_err(&pdev->dev, "missing controller clock\n");
+ return PTR_ERR(div_clk);
+ }
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+ return -ENOMEM;
+
+ i2c_dev->base = base;
+ i2c_dev->div_clk = div_clk;
+ i2c_dev->adapter.algo = &tegra_i2c_algo;
+ i2c_dev->irq = irq;
+ i2c_dev->cont_id = pdev->id;
+ i2c_dev->dev = &pdev->dev;
+
+ i2c_dev->rst = devm_reset_control_get_exclusive(&pdev->dev, "i2c");
+ if (IS_ERR(i2c_dev->rst)) {
+ dev_err(&pdev->dev, "missing controller reset\n");
+ return PTR_ERR(i2c_dev->rst);
+ }
+
+ tegra_i2c_parse_dt(i2c_dev);
+
+ i2c_dev->hw = of_device_get_match_data(&pdev->dev);
+ i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
+ "nvidia,tegra20-i2c-dvc");
+ i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
+ init_completion(&i2c_dev->msg_complete);
+ spin_lock_init(&i2c_dev->xfer_lock);
+
+ if (!i2c_dev->hw->has_single_clk_source) {
+ fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
+ if (IS_ERR(fast_clk)) {
+ dev_err(&pdev->dev, "missing fast clock\n");
+ return PTR_ERR(fast_clk);
+ }
+ i2c_dev->fast_clk = fast_clk;
+ }
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ if (!i2c_dev->hw->has_single_clk_source) {
+ ret = clk_prepare(i2c_dev->fast_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
+ return ret;
+ }
+ }
+
+ i2c_dev->clk_divisor_non_hs_mode =
+ i2c_dev->hw->clk_divisor_std_fast_mode;
+ if (i2c_dev->hw->clk_divisor_fast_plus_mode &&
+ (i2c_dev->bus_clk_rate == 1000000))
+ i2c_dev->clk_divisor_non_hs_mode =
+ i2c_dev->hw->clk_divisor_fast_plus_mode;
+
+ clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
+ ret = clk_set_rate(i2c_dev->div_clk,
+ i2c_dev->bus_clk_rate * clk_multiplier);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Clock rate change failed %d\n", ret);
+ goto unprepare_fast_clk;
+ }
+
+ ret = clk_prepare(i2c_dev->div_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
+ goto unprepare_fast_clk;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra_i2c_runtime_resume(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "runtime resume failed\n");
+ goto unprepare_div_clk;
+ }
+ }
+
+ if (i2c_dev->is_multimaster_mode) {
+ ret = clk_enable(i2c_dev->div_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
+ ret);
+ goto disable_rpm;
+ }
+ }
+
+ ret = tegra_i2c_init(i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
+ goto disable_div_clk;
+ }
+
+ ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
+ tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
+ goto disable_div_clk;
+ }
+
+ i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
+ i2c_dev->adapter.owner = THIS_MODULE;
+ i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
+ strlcpy(i2c_dev->adapter.name, dev_name(&pdev->dev),
+ sizeof(i2c_dev->adapter.name));
+ i2c_dev->adapter.dev.parent = &pdev->dev;
+ i2c_dev->adapter.nr = pdev->id;
+ i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
+ if (ret)
+ goto disable_div_clk;
+
+ return 0;
+
+disable_div_clk:
+ if (i2c_dev->is_multimaster_mode)
+ clk_disable(i2c_dev->div_clk);
+
+disable_rpm:
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_i2c_runtime_suspend(&pdev->dev);
+
+unprepare_div_clk:
+ clk_unprepare(i2c_dev->div_clk);
+
+unprepare_fast_clk:
+ if (!i2c_dev->hw->has_single_clk_source)
+ clk_unprepare(i2c_dev->fast_clk);
+
+ return ret;
+}
+
+static int tegra_i2c_remove(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c_dev->adapter);
+
+ if (i2c_dev->is_multimaster_mode)
+ clk_disable(i2c_dev->div_clk);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_i2c_runtime_suspend(&pdev->dev);
+
+ clk_unprepare(i2c_dev->div_clk);
+ if (!i2c_dev->hw->has_single_clk_source)
+ clk_unprepare(i2c_dev->fast_clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops tegra_i2c_pm = {
+ SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
+ NULL)
+};
+#define TEGRA_I2C_PM (&tegra_i2c_pm)
+#else
+#define TEGRA_I2C_PM NULL
+#endif
+
+static struct platform_driver tegra_i2c_driver = {
+ .probe = tegra_i2c_probe,
+ .remove = tegra_i2c_remove,
+ .driver = {
+ .name = "tegra-i2c",
+ .of_match_table = tegra_i2c_of_match,
+ .pm = TEGRA_I2C_PM,
+ },
+};
+
+static int __init tegra_i2c_init_driver(void)
+{
+ return platform_driver_register(&tegra_i2c_driver);
+}
+
+static void __exit tegra_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&tegra_i2c_driver);
+}
+
+subsys_initcall(tegra_i2c_init_driver);
+module_exit(tegra_i2c_exit_driver);
+
+MODULE_DESCRIPTION("nVidia Tegra2 I2C Bus Controller driver");
+MODULE_AUTHOR("Colin Cross");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
new file mode 100644
index 000000000..107aeb8b5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -0,0 +1,260 @@
+/*
+ * Cavium ThunderX i2c driver.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Authors: Fred Martin <fmartin@caviumnetworks.com>
+ * Jan Glauber <jglauber@cavium.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+
+#include "i2c-octeon-core.h"
+
+#define DRV_NAME "i2c-thunderx"
+
+#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012
+
+#define SYS_FREQ_DEFAULT 700000000
+
+#define TWSI_INT_ENA_W1C 0x1028
+#define TWSI_INT_ENA_W1S 0x1030
+
+/*
+ * Enable the CORE interrupt.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+/*
+ * Disable the CORE interrupt.
+ */
+static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+static void thunder_i2c_hlc_int_disable(struct octeon_i2c *i2c)
+{
+ octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+ i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static u32 thunderx_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm thunderx_i2c_algo = {
+ .master_xfer = octeon_i2c_xfer,
+ .functionality = thunderx_i2c_functionality,
+};
+
+static const struct i2c_adapter thunderx_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "ThunderX adapter",
+ .algo = &thunderx_i2c_algo,
+};
+
+static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
+{
+ int ret;
+
+ if (acpi_disabled) {
+ /* DT */
+ i2c->clk = clk_get(dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ i2c->clk = NULL;
+ goto skip;
+ }
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret)
+ goto skip;
+ i2c->sys_freq = clk_get_rate(i2c->clk);
+ } else {
+ /* ACPI */
+ device_property_read_u32(dev, "sclk", &i2c->sys_freq);
+ }
+
+skip:
+ if (!i2c->sys_freq)
+ i2c->sys_freq = SYS_FREQ_DEFAULT;
+}
+
+static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
+{
+ if (!clk)
+ return;
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+}
+
+static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
+ struct device_node *node)
+{
+ if (!node)
+ return -EINVAL;
+
+ i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+ if (!i2c->alert_data.irq)
+ return -EINVAL;
+
+ i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
+ if (!i2c->ara)
+ return -ENODEV;
+ return 0;
+}
+
+static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+ struct device_node *node)
+{
+ /* TODO: ACPI support */
+ if (!acpi_disabled)
+ return -EOPNOTSUPP;
+
+ return thunder_i2c_smbus_setup_of(i2c, node);
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+ i2c_unregister_device(i2c->ara);
+}
+
+static int thunder_i2c_probe_pci(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct octeon_i2c *i2c;
+ int ret;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->roff.sw_twsi = 0x1000;
+ i2c->roff.twsi_int = 0x1010;
+ i2c->roff.sw_twsi_ext = 0x1018;
+
+ i2c->dev = dev;
+ pci_set_drvdata(pdev, i2c);
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = pci_request_regions(pdev, DRV_NAME);
+ if (ret)
+ return ret;
+
+ i2c->twsi_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!i2c->twsi_base)
+ return -EINVAL;
+
+ thunder_i2c_clock_enable(dev, i2c);
+ ret = device_property_read_u32(dev, "clock-frequency", &i2c->twsi_freq);
+ if (ret)
+ i2c->twsi_freq = 100000;
+
+ init_waitqueue_head(&i2c->queue);
+
+ i2c->int_enable = thunder_i2c_int_enable;
+ i2c->int_disable = thunder_i2c_int_disable;
+ i2c->hlc_int_enable = thunder_i2c_hlc_int_enable;
+ i2c->hlc_int_disable = thunder_i2c_hlc_int_disable;
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
+ if (ret < 0)
+ goto error;
+
+ ret = devm_request_irq(dev, pci_irq_vector(pdev, 0), octeon_i2c_isr, 0,
+ DRV_NAME, i2c);
+ if (ret)
+ goto error;
+
+ ret = octeon_i2c_init_lowlevel(i2c);
+ if (ret)
+ goto error;
+
+ octeon_i2c_set_clock(i2c);
+
+ i2c->adap = thunderx_i2c_ops;
+ i2c->adap.retries = 5;
+ i2c->adap.class = I2C_CLASS_HWMON;
+ i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
+ i2c->adap.dev.parent = dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+ i2c->adap.dev.fwnode = dev->fwnode;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "Cavium ThunderX i2c adapter at %s", dev_name(dev));
+ i2c_set_adapdata(&i2c->adap, i2c);
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret)
+ goto error;
+
+ dev_info(i2c->dev, "Probed. Set system clock to %u\n", i2c->sys_freq);
+
+ ret = thunder_i2c_smbus_setup(i2c, pdev->dev.of_node);
+ if (ret)
+ dev_info(dev, "SMBUS alert not active on this bus\n");
+
+ return 0;
+
+error:
+ thunder_i2c_clock_disable(dev, i2c->clk);
+ return ret;
+}
+
+static void thunder_i2c_remove_pci(struct pci_dev *pdev)
+{
+ struct octeon_i2c *i2c = pci_get_drvdata(pdev);
+
+ thunder_i2c_smbus_remove(i2c);
+ thunder_i2c_clock_disable(&pdev->dev, i2c->clk);
+ i2c_del_adapter(&i2c->adap);
+}
+
+static const struct pci_device_id thunder_i2c_pci_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_TWSI) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, thunder_i2c_pci_id_table);
+
+static struct pci_driver thunder_i2c_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = thunder_i2c_pci_id_table,
+ .probe = thunder_i2c_probe_pci,
+ .remove = thunder_i2c_remove_pci,
+};
+
+module_pci_driver(thunder_i2c_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fred Martin <fmartin@caviumnetworks.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC");
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 000000000..a2e3dd715
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,307 @@
+/*
+ * driver for the i2c-tiny-usb adapter - 1.0
+ * http://www.harbaum.org/till/i2c_tiny_usb
+ *
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/* include interfaces to usb layer */
+#include <linux/usb.h>
+
+/* include interface to i2c layer */
+#include <linux/i2c.h>
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_ECHO 0
+#define CMD_GET_FUNC 1
+#define CMD_SET_DELAY 2
+#define CMD_GET_STATUS 3
+
+#define CMD_I2C_IO 4
+#define CMD_I2C_IO_BEGIN (1<<0)
+#define CMD_I2C_IO_END (1<<1)
+
+/* i2c bit delay, default is 10us -> 100kHz max
+ (in practice, due to additional delays in the i2c bitbanging
+ code this results in a i2c clock of about 50kHz) */
+static unsigned short delay = 10;
+module_param(delay, ushort, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds "
+ "(default is 10us for 100kHz max)");
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+/* ----- begin of i2c layer ---------------------------------------------- */
+
+#define STATUS_IDLE 0
+#define STATUS_ADDRESS_ACK 1
+#define STATUS_ADDRESS_NAK 2
+
+static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ unsigned char *pstatus;
+ struct i2c_msg *pmsg;
+ int i, ret;
+
+ dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+
+ pstatus = kmalloc(sizeof(*pstatus), GFP_KERNEL);
+ if (!pstatus)
+ return -ENOMEM;
+
+ for (i = 0 ; i < num ; i++) {
+ int cmd = CMD_I2C_IO;
+
+ if (i == 0)
+ cmd |= CMD_I2C_IO_BEGIN;
+
+ if (i == num-1)
+ cmd |= CMD_I2C_IO_END;
+
+ pmsg = &msgs[i];
+
+ dev_dbg(&adapter->dev,
+ " %d: %s (flags %d) %d bytes to 0x%02x\n",
+ i, pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->flags, pmsg->len, pmsg->addr);
+
+ /* and directly send the message */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read data */
+ if (usb_read(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure reading data\n");
+ ret = -EREMOTEIO;
+ goto out;
+ }
+ } else {
+ /* write data */
+ if (usb_write(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure writing data\n");
+ ret = -EREMOTEIO;
+ goto out;
+ }
+ }
+
+ /* read status */
+ if (usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1) != 1) {
+ dev_err(&adapter->dev, "failure reading status\n");
+ ret = -EREMOTEIO;
+ goto out;
+ }
+
+ dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
+ if (*pstatus == STATUS_ADDRESS_NAK) {
+ ret = -EREMOTEIO;
+ goto out;
+ }
+ }
+
+ ret = i;
+out:
+ kfree(pstatus);
+ return ret;
+}
+
+static u32 usb_func(struct i2c_adapter *adapter)
+{
+ __le32 *pfunc;
+ u32 ret;
+
+ pfunc = kmalloc(sizeof(*pfunc), GFP_KERNEL);
+
+ /* get functionality from adapter */
+ if (!pfunc || usb_read(adapter, CMD_GET_FUNC, 0, 0, pfunc,
+ sizeof(*pfunc)) != sizeof(*pfunc)) {
+ dev_err(&adapter->dev, "failure reading functionality\n");
+ ret = 0;
+ goto out;
+ }
+
+ ret = le32_to_cpup(pfunc);
+out:
+ kfree(pfunc);
+ return ret;
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm usb_algorithm = {
+ .master_xfer = usb_xfer,
+ .functionality = usb_func,
+};
+
+/* ----- end of i2c layer ------------------------------------------------ */
+
+/* ----- begin of usb layer ---------------------------------------------- */
+
+/*
+ * Initially the usb i2c interface uses a vid/pid pair donated by
+ * Future Technology Devices International Ltd., later a pair was
+ * bought from EZPrototypes
+ */
+static const struct usb_device_id i2c_tiny_usb_table[] = {
+ { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
+ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_tiny_usb {
+ struct usb_device *usb_dev; /* the usb device for this device */
+ struct usb_interface *interface; /* the interface for this device */
+ struct i2c_adapter adapter; /* i2c related things */
+};
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+ void *dmadata = kmalloc(len, GFP_KERNEL);
+ int ret;
+
+ if (!dmadata)
+ return -ENOMEM;
+
+ /* do control transfer */
+ ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+ USB_DIR_IN, value, index, dmadata, len, 2000);
+
+ memcpy(data, dmadata, len);
+ kfree(dmadata);
+ return ret;
+}
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+ void *dmadata = kmemdup(data, len, GFP_KERNEL);
+ int ret;
+
+ if (!dmadata)
+ return -ENOMEM;
+
+ /* do control transfer */
+ ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, dmadata, len, 2000);
+
+ kfree(dmadata);
+ return ret;
+}
+
+static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
+{
+ usb_put_dev(dev->usb_dev);
+ kfree(dev);
+}
+
+static int i2c_tiny_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct i2c_tiny_usb *dev;
+ int retval = -ENOMEM;
+ u16 version;
+
+ dev_dbg(&interface->dev, "probing usb device\n");
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ goto error;
+ }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
+ dev_info(&interface->dev,
+ "version %x.%02x found at bus %03d address %03d\n",
+ version >> 8, version & 0xff,
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ /* setup i2c adapter description */
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &usb_algorithm;
+ dev->adapter.algo_data = dev;
+ snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+ "i2c-tiny-usb at bus %03d device %03d",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
+ dev_err(&dev->adapter.dev,
+ "failure setting delay to %dus\n", delay);
+ retval = -EIO;
+ goto error;
+ }
+
+ dev->adapter.dev.parent = &dev->interface->dev;
+
+ /* and finally attach to i2c layer */
+ i2c_add_adapter(&dev->adapter);
+
+ /* inform user about successful attachment to i2c layer */
+ dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
+
+ return 0;
+
+ error:
+ if (dev)
+ i2c_tiny_usb_free(dev);
+
+ return retval;
+}
+
+static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
+{
+ struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&dev->adapter);
+ usb_set_intfdata(interface, NULL);
+ i2c_tiny_usb_free(dev);
+
+ dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver i2c_tiny_usb_driver = {
+ .name = "i2c-tiny-usb",
+ .probe = i2c_tiny_usb_probe,
+ .disconnect = i2c_tiny_usb_disconnect,
+ .id_table = i2c_tiny_usb_table,
+};
+
+module_usb_driver(i2c_tiny_usb_driver);
+
+/* ----- end of usb layer ------------------------------------------------ */
+
+MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
+MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
new file mode 100644
index 000000000..dd0687e36
--- /dev/null
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define UNIPHIER_FI2C_CR 0x00 /* control register */
+#define UNIPHIER_FI2C_CR_MST BIT(3) /* master mode */
+#define UNIPHIER_FI2C_CR_STA BIT(2) /* start condition */
+#define UNIPHIER_FI2C_CR_STO BIT(1) /* stop condition */
+#define UNIPHIER_FI2C_CR_NACK BIT(0) /* do not return ACK */
+#define UNIPHIER_FI2C_DTTX 0x04 /* TX FIFO */
+#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (slave addr) */
+#define UNIPHIER_FI2C_DTTX_RD BIT(0) /* read transaction */
+#define UNIPHIER_FI2C_DTRX 0x04 /* RX FIFO */
+#define UNIPHIER_FI2C_SLAD 0x0c /* slave address */
+#define UNIPHIER_FI2C_CYC 0x10 /* clock cycle control */
+#define UNIPHIER_FI2C_LCTL 0x14 /* clock low period control */
+#define UNIPHIER_FI2C_SSUT 0x18 /* restart/stop setup time control */
+#define UNIPHIER_FI2C_DSUT 0x1c /* data setup time control */
+#define UNIPHIER_FI2C_INT 0x20 /* interrupt status */
+#define UNIPHIER_FI2C_IE 0x24 /* interrupt enable */
+#define UNIPHIER_FI2C_IC 0x28 /* interrupt clear */
+#define UNIPHIER_FI2C_INT_TE BIT(9) /* TX FIFO empty */
+#define UNIPHIER_FI2C_INT_RF BIT(8) /* RX FIFO full */
+#define UNIPHIER_FI2C_INT_TC BIT(7) /* send complete (STOP) */
+#define UNIPHIER_FI2C_INT_RC BIT(6) /* receive complete (STOP) */
+#define UNIPHIER_FI2C_INT_TB BIT(5) /* sent specified bytes */
+#define UNIPHIER_FI2C_INT_RB BIT(4) /* received specified bytes */
+#define UNIPHIER_FI2C_INT_NA BIT(2) /* no ACK */
+#define UNIPHIER_FI2C_INT_AL BIT(1) /* arbitration lost */
+#define UNIPHIER_FI2C_SR 0x2c /* status register */
+#define UNIPHIER_FI2C_SR_DB BIT(12) /* device busy */
+#define UNIPHIER_FI2C_SR_STS BIT(11) /* stop condition detected */
+#define UNIPHIER_FI2C_SR_BB BIT(8) /* bus busy */
+#define UNIPHIER_FI2C_SR_RFF BIT(3) /* RX FIFO full */
+#define UNIPHIER_FI2C_SR_RNE BIT(2) /* RX FIFO not empty */
+#define UNIPHIER_FI2C_SR_TNF BIT(1) /* TX FIFO not full */
+#define UNIPHIER_FI2C_SR_TFE BIT(0) /* TX FIFO empty */
+#define UNIPHIER_FI2C_RST 0x34 /* reset control */
+#define UNIPHIER_FI2C_RST_TBRST BIT(2) /* clear TX FIFO */
+#define UNIPHIER_FI2C_RST_RBRST BIT(1) /* clear RX FIFO */
+#define UNIPHIER_FI2C_RST_RST BIT(0) /* forcible bus reset */
+#define UNIPHIER_FI2C_BM 0x38 /* bus monitor */
+#define UNIPHIER_FI2C_BM_SDAO BIT(3) /* output for SDA line */
+#define UNIPHIER_FI2C_BM_SDAS BIT(2) /* readback of SDA line */
+#define UNIPHIER_FI2C_BM_SCLO BIT(1) /* output for SCL line */
+#define UNIPHIER_FI2C_BM_SCLS BIT(0) /* readback of SCL line */
+#define UNIPHIER_FI2C_NOISE 0x3c /* noise filter control */
+#define UNIPHIER_FI2C_TBC 0x40 /* TX byte count setting */
+#define UNIPHIER_FI2C_RBC 0x44 /* RX byte count setting */
+#define UNIPHIER_FI2C_TBCM 0x48 /* TX byte count monitor */
+#define UNIPHIER_FI2C_RBCM 0x4c /* RX byte count monitor */
+#define UNIPHIER_FI2C_BRST 0x50 /* bus reset */
+#define UNIPHIER_FI2C_BRST_FOEN BIT(1) /* normal operation */
+#define UNIPHIER_FI2C_BRST_RSCL BIT(0) /* release SCL */
+
+#define UNIPHIER_FI2C_INT_FAULTS \
+ (UNIPHIER_FI2C_INT_NA | UNIPHIER_FI2C_INT_AL)
+#define UNIPHIER_FI2C_INT_STOP \
+ (UNIPHIER_FI2C_INT_TC | UNIPHIER_FI2C_INT_RC)
+
+#define UNIPHIER_FI2C_RD BIT(0)
+#define UNIPHIER_FI2C_STOP BIT(1)
+#define UNIPHIER_FI2C_MANUAL_NACK BIT(2)
+#define UNIPHIER_FI2C_BYTE_WISE BIT(3)
+#define UNIPHIER_FI2C_DEFER_STOP_COMP BIT(4)
+
+#define UNIPHIER_FI2C_DEFAULT_SPEED 100000
+#define UNIPHIER_FI2C_MAX_SPEED 400000
+#define UNIPHIER_FI2C_FIFO_SIZE 8
+
+struct uniphier_fi2c_priv {
+ struct completion comp;
+ struct i2c_adapter adap;
+ void __iomem *membase;
+ struct clk *clk;
+ unsigned int len;
+ u8 *buf;
+ u32 enabled_irqs;
+ int error;
+ unsigned int flags;
+ unsigned int busy_cnt;
+ unsigned int clk_cycle;
+ spinlock_t lock; /* IRQ synchronization */
+};
+
+static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
+ bool first)
+{
+ int fifo_space = UNIPHIER_FI2C_FIFO_SIZE;
+
+ /*
+ * TX-FIFO stores slave address in it for the first access.
+ * Decrement the counter.
+ */
+ if (first)
+ fifo_space--;
+
+ while (priv->len) {
+ if (fifo_space-- <= 0)
+ break;
+
+ dev_dbg(&priv->adap.dev, "write data: %02x\n", *priv->buf);
+ writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX);
+ priv->len--;
+ }
+}
+
+static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv)
+{
+ int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ?
+ 1 : UNIPHIER_FI2C_FIFO_SIZE;
+
+ while (priv->len) {
+ if (fifo_left-- <= 0)
+ break;
+
+ *priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX);
+ dev_dbg(&priv->adap.dev, "read data: %02x\n", priv->buf[-1]);
+ priv->len--;
+ }
+}
+
+static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
+{
+ writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
+}
+
+static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv,
+ u32 mask)
+{
+ writel(mask, priv->membase + UNIPHIER_FI2C_IC);
+}
+
+static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
+{
+ dev_dbg(&priv->adap.dev, "stop condition\n");
+
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP;
+ uniphier_fi2c_set_irqs(priv);
+ writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO,
+ priv->membase + UNIPHIER_FI2C_CR);
+}
+
+static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
+{
+ struct uniphier_fi2c_priv *priv = dev_id;
+ u32 irq_status;
+
+ spin_lock(&priv->lock);
+
+ irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
+ irq_status &= priv->enabled_irqs;
+
+ dev_dbg(&priv->adap.dev,
+ "interrupt: enabled_irqs=%04x, irq_status=%04x\n",
+ priv->enabled_irqs, irq_status);
+
+ if (irq_status & UNIPHIER_FI2C_INT_STOP)
+ goto complete;
+
+ if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) {
+ dev_dbg(&priv->adap.dev, "arbitration lost\n");
+ priv->error = -EAGAIN;
+ goto complete;
+ }
+
+ if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) {
+ dev_dbg(&priv->adap.dev, "could not get ACK\n");
+ priv->error = -ENXIO;
+ if (priv->flags & UNIPHIER_FI2C_RD) {
+ /*
+ * work around a hardware bug:
+ * The receive-completed interrupt is never set even if
+ * STOP condition is detected after the address phase
+ * of read transaction fails to get ACK.
+ * To avoid time-out error, we issue STOP here,
+ * but do not wait for its completion.
+ * It should be checked after exiting this handler.
+ */
+ uniphier_fi2c_stop(priv);
+ priv->flags |= UNIPHIER_FI2C_DEFER_STOP_COMP;
+ goto complete;
+ }
+ goto stop;
+ }
+
+ if (irq_status & UNIPHIER_FI2C_INT_TE) {
+ if (!priv->len)
+ goto data_done;
+
+ uniphier_fi2c_fill_txfifo(priv, false);
+ goto handled;
+ }
+
+ if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) {
+ uniphier_fi2c_drain_rxfifo(priv);
+ /*
+ * If the number of bytes to read is multiple of the FIFO size
+ * (msg->len == 8, 16, 24, ...), the INT_RF bit is set a little
+ * earlier than INT_RB. We wait for INT_RB to confirm the
+ * completion of the current message.
+ */
+ if (!priv->len && (irq_status & UNIPHIER_FI2C_INT_RB))
+ goto data_done;
+
+ if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
+ if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE &&
+ !(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) {
+ dev_dbg(&priv->adap.dev,
+ "enable read byte count IRQ\n");
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB;
+ uniphier_fi2c_set_irqs(priv);
+ priv->flags |= UNIPHIER_FI2C_BYTE_WISE;
+ }
+ if (priv->len <= 1) {
+ dev_dbg(&priv->adap.dev, "set NACK\n");
+ writel(UNIPHIER_FI2C_CR_MST |
+ UNIPHIER_FI2C_CR_NACK,
+ priv->membase + UNIPHIER_FI2C_CR);
+ }
+ }
+
+ goto handled;
+ }
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_NONE;
+
+data_done:
+ if (priv->flags & UNIPHIER_FI2C_STOP) {
+stop:
+ uniphier_fi2c_stop(priv);
+ } else {
+complete:
+ priv->enabled_irqs = 0;
+ uniphier_fi2c_set_irqs(priv);
+ complete(&priv->comp);
+ }
+
+handled:
+ /*
+ * This controller makes a pause while any bit of the IRQ status is
+ * asserted. Clear the asserted bit to kick the controller just before
+ * exiting the handler.
+ */
+ uniphier_fi2c_clear_irqs(priv, irq_status);
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
+{
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
+ uniphier_fi2c_set_irqs(priv);
+
+ /* do not use TX byte counter */
+ writel(0, priv->membase + UNIPHIER_FI2C_TBC);
+ /* set slave address */
+ writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1,
+ priv->membase + UNIPHIER_FI2C_DTTX);
+ /* first chunk of data */
+ uniphier_fi2c_fill_txfifo(priv, true);
+}
+
+static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
+{
+ priv->flags |= UNIPHIER_FI2C_RD;
+
+ if (likely(priv->len < 256)) {
+ /*
+ * If possible, use RX byte counter.
+ * It can automatically handle NACK for the last byte.
+ */
+ writel(priv->len, priv->membase + UNIPHIER_FI2C_RBC);
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF |
+ UNIPHIER_FI2C_INT_RB;
+ } else {
+ /*
+ * The byte counter can not count over 256. In this case,
+ * do not use it at all. Drain data when FIFO gets full,
+ * but treat the last portion as a special case.
+ */
+ writel(0, priv->membase + UNIPHIER_FI2C_RBC);
+ priv->flags |= UNIPHIER_FI2C_MANUAL_NACK;
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
+ }
+
+ uniphier_fi2c_set_irqs(priv);
+
+ /* set slave address with RD bit */
+ writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
+ priv->membase + UNIPHIER_FI2C_DTTX);
+}
+
+static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv)
+{
+ writel(UNIPHIER_FI2C_RST_RST, priv->membase + UNIPHIER_FI2C_RST);
+}
+
+static void uniphier_fi2c_prepare_operation(struct uniphier_fi2c_priv *priv)
+{
+ writel(UNIPHIER_FI2C_BRST_FOEN | UNIPHIER_FI2C_BRST_RSCL,
+ priv->membase + UNIPHIER_FI2C_BRST);
+}
+
+static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
+{
+ uniphier_fi2c_reset(priv);
+ i2c_recover_bus(&priv->adap);
+}
+
+static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
+ struct i2c_msg *msg, bool repeat,
+ bool stop)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+ bool is_read = msg->flags & I2C_M_RD;
+ unsigned long time_left, flags;
+
+ dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, repeat=%d, stop=%d\n",
+ is_read ? "receive" : "transmit", msg->addr, msg->len,
+ repeat, stop);
+
+ priv->len = msg->len;
+ priv->buf = msg->buf;
+ priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS;
+ priv->error = 0;
+ priv->flags = 0;
+
+ if (stop)
+ priv->flags |= UNIPHIER_FI2C_STOP;
+
+ reinit_completion(&priv->comp);
+ uniphier_fi2c_clear_irqs(priv, U32_MAX);
+ writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
+ priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (is_read)
+ uniphier_fi2c_rx_init(priv, msg->addr);
+ else
+ uniphier_fi2c_tx_init(priv, msg->addr);
+
+ dev_dbg(&adap->dev, "start condition\n");
+ /*
+ * For a repeated START condition, writing a slave address to the FIFO
+ * kicks the controller. So, the UNIPHIER_FI2C_CR register should be
+ * written only for a non-repeated START condition.
+ */
+ if (!repeat)
+ writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
+ priv->membase + UNIPHIER_FI2C_CR);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->enabled_irqs = 0;
+ uniphier_fi2c_set_irqs(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (!time_left) {
+ dev_err(&adap->dev, "transaction timeout.\n");
+ uniphier_fi2c_recover(priv);
+ return -ETIMEDOUT;
+ }
+ dev_dbg(&adap->dev, "complete\n");
+
+ if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) {
+ u32 status;
+ int ret;
+
+ ret = readl_poll_timeout(priv->membase + UNIPHIER_FI2C_SR,
+ status,
+ (status & UNIPHIER_FI2C_SR_STS) &&
+ !(status & UNIPHIER_FI2C_SR_BB),
+ 1, 20);
+ if (ret) {
+ dev_err(&adap->dev,
+ "stop condition was not completed.\n");
+ uniphier_fi2c_recover(priv);
+ return ret;
+ }
+ }
+
+ return priv->error;
+}
+
+static int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (readl(priv->membase + UNIPHIER_FI2C_SR) & UNIPHIER_FI2C_SR_DB) {
+ if (priv->busy_cnt++ > 3) {
+ /*
+ * If bus busy continues too long, it is probably
+ * in a wrong state. Try bus recovery.
+ */
+ uniphier_fi2c_recover(priv);
+ priv->busy_cnt = 0;
+ }
+
+ return -EAGAIN;
+ }
+
+ priv->busy_cnt = 0;
+ return 0;
+}
+
+static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *msg, *emsg = msgs + num;
+ bool repeat = false;
+ int ret;
+
+ ret = uniphier_fi2c_check_bus_busy(adap);
+ if (ret)
+ return ret;
+
+ for (msg = msgs; msg < emsg; msg++) {
+ /* Emit STOP if it is the last message or I2C_M_STOP is set. */
+ bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
+
+ ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop);
+ if (ret)
+ return ret;
+
+ repeat = !stop;
+ }
+
+ return num;
+}
+
+static u32 uniphier_fi2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm uniphier_fi2c_algo = {
+ .master_xfer = uniphier_fi2c_master_xfer,
+ .functionality = uniphier_fi2c_functionality,
+};
+
+static int uniphier_fi2c_get_scl(struct i2c_adapter *adap)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
+ UNIPHIER_FI2C_BM_SCLS);
+}
+
+static void uniphier_fi2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ writel(val ? UNIPHIER_FI2C_BRST_RSCL : 0,
+ priv->membase + UNIPHIER_FI2C_BRST);
+}
+
+static int uniphier_fi2c_get_sda(struct i2c_adapter *adap)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
+ UNIPHIER_FI2C_BM_SDAS);
+}
+
+static void uniphier_fi2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ uniphier_fi2c_prepare_operation(i2c_get_adapdata(adap));
+}
+
+static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = uniphier_fi2c_get_scl,
+ .set_scl = uniphier_fi2c_set_scl,
+ .get_sda = uniphier_fi2c_get_sda,
+ .unprepare_recovery = uniphier_fi2c_unprepare_recovery,
+};
+
+static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv)
+{
+ unsigned int cyc = priv->clk_cycle;
+ u32 tmp;
+
+ tmp = readl(priv->membase + UNIPHIER_FI2C_CR);
+ tmp |= UNIPHIER_FI2C_CR_MST;
+ writel(tmp, priv->membase + UNIPHIER_FI2C_CR);
+
+ uniphier_fi2c_reset(priv);
+
+ /*
+ * Standard-mode: tLOW + tHIGH = 10 us
+ * Fast-mode: tLOW + tHIGH = 2.5 us
+ */
+ writel(cyc, priv->membase + UNIPHIER_FI2C_CYC);
+ /*
+ * Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us, tBUF = 4.7 us
+ * Fast-mode: tLOW = 1.3 us, tHIGH = 0.6 us, tBUF = 1.3 us
+ * "tLow/tHIGH = 5/4" meets both.
+ */
+ writel(cyc * 5 / 9, priv->membase + UNIPHIER_FI2C_LCTL);
+ /*
+ * Standard-mode: tHD;STA = 4.0 us, tSU;STA = 4.7 us, tSU;STO = 4.0 us
+ * Fast-mode: tHD;STA = 0.6 us, tSU;STA = 0.6 us, tSU;STO = 0.6 us
+ */
+ writel(cyc / 2, priv->membase + UNIPHIER_FI2C_SSUT);
+ /*
+ * Standard-mode: tSU;DAT = 250 ns
+ * Fast-mode: tSU;DAT = 100 ns
+ */
+ writel(cyc / 16, priv->membase + UNIPHIER_FI2C_DSUT);
+
+ uniphier_fi2c_prepare_operation(priv);
+}
+
+static int uniphier_fi2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_fi2c_priv *priv;
+ struct resource *regs;
+ u32 bus_speed;
+ unsigned long clk_rate;
+ int irq, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->membase = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number\n");
+ return irq;
+ }
+
+ if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
+ bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
+
+ if (!bus_speed || bus_speed > UNIPHIER_FI2C_MAX_SPEED) {
+ dev_err(dev, "invalid clock-frequency %d\n", bus_speed);
+ return -EINVAL;
+ }
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(priv->clk);
+ if (!clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ ret = -EINVAL;
+ goto disable_clk;
+ }
+
+ priv->clk_cycle = clk_rate / bus_speed;
+ init_completion(&priv->comp);
+ spin_lock_init(&priv->lock);
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo = &uniphier_fi2c_algo;
+ priv->adap.dev.parent = dev;
+ priv->adap.dev.of_node = dev->of_node;
+ strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name));
+ priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info;
+ i2c_set_adapdata(&priv->adap, priv);
+ platform_set_drvdata(pdev, priv);
+
+ uniphier_fi2c_hw_init(priv);
+
+ ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
+ pdev->name, priv);
+ if (ret) {
+ dev_err(dev, "failed to request irq %d\n", irq);
+ goto disable_clk;
+ }
+
+ ret = i2c_add_adapter(&priv->adap);
+disable_clk:
+ if (ret)
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int uniphier_fi2c_remove(struct platform_device *pdev)
+{
+ struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int __maybe_unused uniphier_fi2c_suspend(struct device *dev)
+{
+ struct uniphier_fi2c_priv *priv = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int __maybe_unused uniphier_fi2c_resume(struct device *dev)
+{
+ struct uniphier_fi2c_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ uniphier_fi2c_hw_init(priv);
+
+ return 0;
+}
+
+static const struct dev_pm_ops uniphier_fi2c_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(uniphier_fi2c_suspend, uniphier_fi2c_resume)
+};
+
+static const struct of_device_id uniphier_fi2c_match[] = {
+ { .compatible = "socionext,uniphier-fi2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_fi2c_match);
+
+static struct platform_driver uniphier_fi2c_drv = {
+ .probe = uniphier_fi2c_probe,
+ .remove = uniphier_fi2c_remove,
+ .driver = {
+ .name = "uniphier-fi2c",
+ .of_match_table = uniphier_fi2c_match,
+ .pm = &uniphier_fi2c_pm_ops,
+ },
+};
+module_platform_driver(uniphier_fi2c_drv);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier FIFO-builtin I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
new file mode 100644
index 000000000..c488e558a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define UNIPHIER_I2C_DTRM 0x00 /* TX register */
+#define UNIPHIER_I2C_DTRM_IRQEN BIT(11) /* enable interrupt */
+#define UNIPHIER_I2C_DTRM_STA BIT(10) /* start condition */
+#define UNIPHIER_I2C_DTRM_STO BIT(9) /* stop condition */
+#define UNIPHIER_I2C_DTRM_NACK BIT(8) /* do not return ACK */
+#define UNIPHIER_I2C_DTRM_RD BIT(0) /* read transaction */
+#define UNIPHIER_I2C_DREC 0x04 /* RX register */
+#define UNIPHIER_I2C_DREC_MST BIT(14) /* 1 = master, 0 = slave */
+#define UNIPHIER_I2C_DREC_TX BIT(13) /* 1 = transmit, 0 = receive */
+#define UNIPHIER_I2C_DREC_STS BIT(12) /* stop condition detected */
+#define UNIPHIER_I2C_DREC_LRB BIT(11) /* no ACK */
+#define UNIPHIER_I2C_DREC_LAB BIT(9) /* arbitration lost */
+#define UNIPHIER_I2C_DREC_BBN BIT(8) /* bus not busy */
+#define UNIPHIER_I2C_MYAD 0x08 /* slave address */
+#define UNIPHIER_I2C_CLK 0x0c /* clock frequency control */
+#define UNIPHIER_I2C_BRST 0x10 /* bus reset */
+#define UNIPHIER_I2C_BRST_FOEN BIT(1) /* normal operation */
+#define UNIPHIER_I2C_BRST_RSCL BIT(0) /* release SCL */
+#define UNIPHIER_I2C_HOLD 0x14 /* hold time control */
+#define UNIPHIER_I2C_BSTS 0x18 /* bus status monitor */
+#define UNIPHIER_I2C_BSTS_SDA BIT(1) /* readback of SDA line */
+#define UNIPHIER_I2C_BSTS_SCL BIT(0) /* readback of SCL line */
+#define UNIPHIER_I2C_NOISE 0x1c /* noise filter control */
+#define UNIPHIER_I2C_SETUP 0x20 /* setup time control */
+
+#define UNIPHIER_I2C_DEFAULT_SPEED 100000
+#define UNIPHIER_I2C_MAX_SPEED 400000
+
+struct uniphier_i2c_priv {
+ struct completion comp;
+ struct i2c_adapter adap;
+ void __iomem *membase;
+ struct clk *clk;
+ unsigned int busy_cnt;
+ unsigned int clk_cycle;
+};
+
+static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id)
+{
+ struct uniphier_i2c_priv *priv = dev_id;
+
+ /*
+ * This hardware uses edge triggered interrupt. Do not touch the
+ * hardware registers in this handler to make sure to catch the next
+ * interrupt edge. Just send a complete signal and return.
+ */
+ complete(&priv->comp);
+
+ return IRQ_HANDLED;
+}
+
+static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
+ u32 *rxdatap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+ unsigned long time_left;
+ u32 rxdata;
+
+ reinit_completion(&priv->comp);
+
+ txdata |= UNIPHIER_I2C_DTRM_IRQEN;
+ dev_dbg(&adap->dev, "write data: 0x%04x\n", txdata);
+ writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
+
+ time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+ if (unlikely(!time_left)) {
+ dev_err(&adap->dev, "transaction timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
+ dev_dbg(&adap->dev, "read data: 0x%04x\n", rxdata);
+
+ if (rxdatap)
+ *rxdatap = rxdata;
+
+ return 0;
+}
+
+static int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata)
+{
+ u32 rxdata;
+ int ret;
+
+ ret = uniphier_i2c_xfer_byte(adap, txdata, &rxdata);
+ if (ret)
+ return ret;
+
+ if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB)) {
+ dev_dbg(&adap->dev, "arbitration lost\n");
+ return -EAGAIN;
+ }
+ if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB)) {
+ dev_dbg(&adap->dev, "could not get ACK\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len,
+ const u8 *buf)
+{
+ int ret;
+
+ dev_dbg(&adap->dev, "start condition\n");
+ ret = uniphier_i2c_send_byte(adap, addr << 1 |
+ UNIPHIER_I2C_DTRM_STA |
+ UNIPHIER_I2C_DTRM_NACK);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ ret = uniphier_i2c_send_byte(adap,
+ UNIPHIER_I2C_DTRM_NACK | *buf++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
+ u8 *buf)
+{
+ int ret;
+
+ dev_dbg(&adap->dev, "start condition\n");
+ ret = uniphier_i2c_send_byte(adap, addr << 1 |
+ UNIPHIER_I2C_DTRM_STA |
+ UNIPHIER_I2C_DTRM_NACK |
+ UNIPHIER_I2C_DTRM_RD);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ u32 rxdata;
+
+ ret = uniphier_i2c_xfer_byte(adap,
+ len ? 0 : UNIPHIER_I2C_DTRM_NACK,
+ &rxdata);
+ if (ret)
+ return ret;
+ *buf++ = rxdata;
+ }
+
+ return 0;
+}
+
+static int uniphier_i2c_stop(struct i2c_adapter *adap)
+{
+ dev_dbg(&adap->dev, "stop condition\n");
+ return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO |
+ UNIPHIER_I2C_DTRM_NACK);
+}
+
+static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
+ struct i2c_msg *msg, bool stop)
+{
+ bool is_read = msg->flags & I2C_M_RD;
+ bool recovery = false;
+ int ret;
+
+ dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
+ is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
+
+ if (is_read)
+ ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf);
+ else
+ ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf);
+
+ if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */
+ return ret;
+
+ if (ret == -ETIMEDOUT) {
+ /* This error is fatal. Needs recovery. */
+ stop = false;
+ recovery = true;
+ }
+
+ if (stop) {
+ int ret2 = uniphier_i2c_stop(adap);
+
+ if (ret2) {
+ /* Failed to issue STOP. The bus needs recovery. */
+ recovery = true;
+ ret = ret ?: ret2;
+ }
+ }
+
+ if (recovery)
+ i2c_recover_bus(adap);
+
+ return ret;
+}
+
+static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (!(readl(priv->membase + UNIPHIER_I2C_DREC) &
+ UNIPHIER_I2C_DREC_BBN)) {
+ if (priv->busy_cnt++ > 3) {
+ /*
+ * If bus busy continues too long, it is probably
+ * in a wrong state. Try bus recovery.
+ */
+ i2c_recover_bus(adap);
+ priv->busy_cnt = 0;
+ }
+
+ return -EAGAIN;
+ }
+
+ priv->busy_cnt = 0;
+ return 0;
+}
+
+static int uniphier_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *msg, *emsg = msgs + num;
+ int ret;
+
+ ret = uniphier_i2c_check_bus_busy(adap);
+ if (ret)
+ return ret;
+
+ for (msg = msgs; msg < emsg; msg++) {
+ /* Emit STOP if it is the last message or I2C_M_STOP is set. */
+ bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
+
+ ret = uniphier_i2c_master_xfer_one(adap, msg, stop);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static u32 uniphier_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm uniphier_i2c_algo = {
+ .master_xfer = uniphier_i2c_master_xfer,
+ .functionality = uniphier_i2c_functionality,
+};
+
+static void uniphier_i2c_reset(struct uniphier_i2c_priv *priv, bool reset_on)
+{
+ u32 val = UNIPHIER_I2C_BRST_RSCL;
+
+ val |= reset_on ? 0 : UNIPHIER_I2C_BRST_FOEN;
+ writel(val, priv->membase + UNIPHIER_I2C_BRST);
+}
+
+static int uniphier_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
+ UNIPHIER_I2C_BSTS_SCL);
+}
+
+static void uniphier_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ writel(val ? UNIPHIER_I2C_BRST_RSCL : 0,
+ priv->membase + UNIPHIER_I2C_BRST);
+}
+
+static int uniphier_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
+ UNIPHIER_I2C_BSTS_SDA);
+}
+
+static void uniphier_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ uniphier_i2c_reset(i2c_get_adapdata(adap), false);
+}
+
+static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = uniphier_i2c_get_scl,
+ .set_scl = uniphier_i2c_set_scl,
+ .get_sda = uniphier_i2c_get_sda,
+ .unprepare_recovery = uniphier_i2c_unprepare_recovery,
+};
+
+static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv)
+{
+ unsigned int cyc = priv->clk_cycle;
+
+ uniphier_i2c_reset(priv, true);
+
+ /*
+ * Bit30-16: clock cycles of tLOW.
+ * Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us
+ * Fast-mode: tLOW = 1.3 us, tHIGH = 0.6 us
+ * "tLow/tHIGH = 5/4" meets both.
+ */
+ writel((cyc * 5 / 9 << 16) | cyc, priv->membase + UNIPHIER_I2C_CLK);
+
+ uniphier_i2c_reset(priv, false);
+}
+
+static int uniphier_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_i2c_priv *priv;
+ struct resource *regs;
+ u32 bus_speed;
+ unsigned long clk_rate;
+ int irq, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->membase = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number\n");
+ return irq;
+ }
+
+ if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed))
+ bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
+
+ if (!bus_speed || bus_speed > UNIPHIER_I2C_MAX_SPEED) {
+ dev_err(dev, "invalid clock-frequency %d\n", bus_speed);
+ return -EINVAL;
+ }
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(priv->clk);
+ if (!clk_rate) {
+ dev_err(dev, "input clock rate should not be zero\n");
+ ret = -EINVAL;
+ goto disable_clk;
+ }
+
+ priv->clk_cycle = clk_rate / bus_speed;
+ init_completion(&priv->comp);
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo = &uniphier_i2c_algo;
+ priv->adap.dev.parent = dev;
+ priv->adap.dev.of_node = dev->of_node;
+ strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name));
+ priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info;
+ i2c_set_adapdata(&priv->adap, priv);
+ platform_set_drvdata(pdev, priv);
+
+ uniphier_i2c_hw_init(priv);
+
+ ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
+ priv);
+ if (ret) {
+ dev_err(dev, "failed to request irq %d\n", irq);
+ goto disable_clk;
+ }
+
+ ret = i2c_add_adapter(&priv->adap);
+disable_clk:
+ if (ret)
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int uniphier_i2c_remove(struct platform_device *pdev)
+{
+ struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int __maybe_unused uniphier_i2c_suspend(struct device *dev)
+{
+ struct uniphier_i2c_priv *priv = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int __maybe_unused uniphier_i2c_resume(struct device *dev)
+{
+ struct uniphier_i2c_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ uniphier_i2c_hw_init(priv);
+
+ return 0;
+}
+
+static const struct dev_pm_ops uniphier_i2c_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(uniphier_i2c_suspend, uniphier_i2c_resume)
+};
+
+static const struct of_device_id uniphier_i2c_match[] = {
+ { .compatible = "socionext,uniphier-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_i2c_match);
+
+static struct platform_driver uniphier_i2c_drv = {
+ .probe = uniphier_i2c_probe,
+ .remove = uniphier_i2c_remove,
+ .driver = {
+ .name = "uniphier-i2c",
+ .of_match_table = uniphier_i2c_match,
+ .pm = &uniphier_i2c_pm_ops,
+ },
+};
+module_platform_driver(uniphier_i2c_drv);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
new file mode 100644
index 000000000..f1ab2a637
--- /dev/null
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -0,0 +1,140 @@
+/*
+ * i2c-versatile.c
+ *
+ * Copyright (C) 2006 ARM Ltd.
+ * written by Russell King, Deep Blue Solutions 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/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#define I2C_CONTROL 0x00
+#define I2C_CONTROLS 0x00
+#define I2C_CONTROLC 0x04
+#define SCL (1 << 0)
+#define SDA (1 << 1)
+
+struct i2c_versatile {
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data algo;
+ void __iomem *base;
+};
+
+static void i2c_versatile_setsda(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static void i2c_versatile_setscl(void *data, int state)
+{
+ struct i2c_versatile *i2c = data;
+
+ writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static int i2c_versatile_getsda(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SDA);
+}
+
+static int i2c_versatile_getscl(void *data)
+{
+ struct i2c_versatile *i2c = data;
+ return !!(readl(i2c->base + I2C_CONTROL) & SCL);
+}
+
+static const struct i2c_algo_bit_data i2c_versatile_algo = {
+ .setsda = i2c_versatile_setsda,
+ .setscl = i2c_versatile_setscl,
+ .getsda = i2c_versatile_getsda,
+ .getscl = i2c_versatile_getscl,
+ .udelay = 30,
+ .timeout = HZ,
+};
+
+static int i2c_versatile_probe(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c;
+ struct resource *r;
+ int ret;
+
+ i2c = devm_kzalloc(&dev->dev, sizeof(struct i2c_versatile), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&dev->dev, r);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ writel(SCL | SDA, i2c->base + I2C_CONTROLS);
+
+ i2c->adap.owner = THIS_MODULE;
+ strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
+ i2c->adap.algo_data = &i2c->algo;
+ i2c->adap.dev.parent = &dev->dev;
+ i2c->adap.dev.of_node = dev->dev.of_node;
+ i2c->algo = i2c_versatile_algo;
+ i2c->algo.data = i2c;
+
+ i2c->adap.nr = dev->id;
+ ret = i2c_bit_add_numbered_bus(&i2c->adap);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(dev, i2c);
+
+ return 0;
+}
+
+static int i2c_versatile_remove(struct platform_device *dev)
+{
+ struct i2c_versatile *i2c = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+}
+
+static const struct of_device_id i2c_versatile_match[] = {
+ { .compatible = "arm,versatile-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, i2c_versatile_match);
+
+static struct platform_driver i2c_versatile_driver = {
+ .probe = i2c_versatile_probe,
+ .remove = i2c_versatile_remove,
+ .driver = {
+ .name = "versatile-i2c",
+ .of_match_table = i2c_versatile_match,
+ },
+};
+
+static int __init i2c_versatile_init(void)
+{
+ return platform_driver_register(&i2c_versatile_driver);
+}
+
+static void __exit i2c_versatile_exit(void)
+{
+ platform_driver_unregister(&i2c_versatile_driver);
+}
+
+subsys_initcall(i2c_versatile_init);
+module_exit(i2c_versatile_exit);
+
+MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:versatile-i2c");
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
new file mode 100644
index 000000000..59b1d233c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-via.c
@@ -0,0 +1,163 @@
+/*
+ i2c Support for Via Technologies 82C586B South Bridge
+
+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+/* Power management registers */
+#define PM_CFG_REVID 0x08 /* silicon revision code */
+#define PM_CFG_IOBASE0 0x20
+#define PM_CFG_IOBASE1 0x48
+
+#define I2C_DIR (pm_io_base+0x40)
+#define I2C_OUT (pm_io_base+0x42)
+#define I2C_IN (pm_io_base+0x44)
+#define I2C_SCL 0x02 /* clock bit in DIR/OUT/IN register */
+#define I2C_SDA 0x04
+
+/* io-region reservation */
+#define IOSPACE 0x06
+
+static struct pci_driver vt586b_driver;
+static u16 pm_io_base;
+
+/*
+ It does not appear from the datasheet that the GPIO pins are
+ open drain. So a we set a low value by setting the direction to
+ output and a high value by setting the direction to input and
+ relying on the required I2C pullup. The data value is initialized
+ to 0 in via_init() and never changed.
+*/
+static void bit_via_setscl(void *data, int state)
+{
+ outb(state ? inb(I2C_DIR) & ~I2C_SCL : inb(I2C_DIR) | I2C_SCL, I2C_DIR);
+}
+
+static void bit_via_setsda(void *data, int state)
+{
+ outb(state ? inb(I2C_DIR) & ~I2C_SDA : inb(I2C_DIR) | I2C_SDA, I2C_DIR);
+}
+
+static int bit_via_getscl(void *data)
+{
+ return (0 != (inb(I2C_IN) & I2C_SCL));
+}
+
+static int bit_via_getsda(void *data)
+{
+ return (0 != (inb(I2C_IN) & I2C_SDA));
+}
+
+
+static struct i2c_algo_bit_data bit_data = {
+ .setsda = bit_via_setsda,
+ .setscl = bit_via_setscl,
+ .getsda = bit_via_getsda,
+ .getscl = bit_via_getscl,
+ .udelay = 5,
+ .timeout = HZ
+};
+
+static struct i2c_adapter vt586b_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .name = "VIA i2c",
+ .algo_data = &bit_data,
+};
+
+
+static const struct pci_device_id vt586b_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, vt586b_ids);
+
+static int vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u16 base;
+ u8 rev;
+ int res;
+
+ if (pm_io_base) {
+ dev_err(&dev->dev, "i2c-via: Will only support one host\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(dev, PM_CFG_REVID, &rev);
+
+ switch (rev) {
+ case 0x00:
+ base = PM_CFG_IOBASE0;
+ break;
+ case 0x01:
+ case 0x10:
+ base = PM_CFG_IOBASE1;
+ break;
+
+ default:
+ base = PM_CFG_IOBASE1;
+ /* later revision */
+ }
+
+ pci_read_config_word(dev, base, &pm_io_base);
+ pm_io_base &= (0xff << 8);
+
+ if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) {
+ dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE);
+ return -ENODEV;
+ }
+
+ outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR);
+ outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT);
+
+ /* set up the sysfs linkage to our parent device */
+ vt586b_adapter.dev.parent = &dev->dev;
+
+ res = i2c_bit_add_bus(&vt586b_adapter);
+ if ( res < 0 ) {
+ release_region(I2C_DIR, IOSPACE);
+ pm_io_base = 0;
+ return res;
+ }
+ return 0;
+}
+
+static void vt586b_remove(struct pci_dev *dev)
+{
+ i2c_del_adapter(&vt586b_adapter);
+ release_region(I2C_DIR, IOSPACE);
+ pm_io_base = 0;
+}
+
+
+static struct pci_driver vt586b_driver = {
+ .name = "vt586b_smbus",
+ .id_table = vt586b_ids,
+ .probe = vt586b_probe,
+ .remove = vt586b_remove,
+};
+
+module_pci_driver(vt586b_driver);
+
+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
+MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
new file mode 100644
index 000000000..0dc45e12b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -0,0 +1,507 @@
+/*
+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+ Copyright (C) 2005 - 2008 Jean Delvare <jdelvare@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ Supports the following VIA south bridges:
+
+ Chip name PCI ID REV I2C block
+ VT82C596A 0x3050 no
+ VT82C596B 0x3051 no
+ VT82C686A 0x3057 0x30 no
+ VT82C686B 0x3057 0x40 yes
+ VT8231 0x8235 no?
+ VT8233 0x3074 yes
+ VT8233A 0x3147 yes?
+ VT8235 0x3177 yes
+ VT8237R 0x3227 yes
+ VT8237A 0x3337 yes
+ VT8237S 0x3372 yes
+ VT8251 0x3287 yes
+ CX700 0x8324 yes
+ VX800/VX820 0x8353 yes
+ VX855/VX875 0x8409 yes
+
+ Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static struct pci_dev *vt596_pdev;
+
+#define SMBBA1 0x90
+#define SMBBA2 0x80
+#define SMBBA3 0xD0
+
+/* SMBus address offsets */
+static unsigned short vt596_smba;
+#define SMBHSTSTS (vt596_smba + 0)
+#define SMBHSTCNT (vt596_smba + 2)
+#define SMBHSTCMD (vt596_smba + 3)
+#define SMBHSTADD (vt596_smba + 4)
+#define SMBHSTDAT0 (vt596_smba + 5)
+#define SMBHSTDAT1 (vt596_smba + 6)
+#define SMBBLKDAT (vt596_smba + 7)
+
+/* PCI Address Constants */
+
+/* SMBus data in configuration space can be found in two places,
+ We try to select the better one */
+
+static unsigned short SMBHSTCFG = 0xD2;
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* VT82C596 constants */
+#define VT596_QUICK 0x00
+#define VT596_BYTE 0x04
+#define VT596_BYTE_DATA 0x08
+#define VT596_WORD_DATA 0x0C
+#define VT596_PROC_CALL 0x10
+#define VT596_BLOCK_DATA 0x14
+#define VT596_I2C_BLOCK_DATA 0x34
+
+
+/* If force is set to anything different from 0, we forcibly enable the
+ VT596. DANGEROUS! */
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+ the VT596 at the given address. VERY DANGEROUS! */
+static u16 force_addr;
+module_param_hw(force_addr, ushort, ioport, 0);
+MODULE_PARM_DESC(force_addr,
+ "Forcibly enable the SMBus at the given address. "
+ "EXTREMELY DANGEROUS!");
+
+
+static struct pci_driver vt596_driver;
+static struct i2c_adapter vt596_adapter;
+
+#define FEATURE_I2CBLOCK (1<<0)
+static unsigned int vt596_features;
+
+#ifdef DEBUG
+static void vt596_dump_regs(const char *msg, u8 size)
+{
+ dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
+ "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+ inb_p(SMBHSTDAT1));
+
+ if (size == VT596_BLOCK_DATA
+ || size == VT596_I2C_BLOCK_DATA) {
+ int i;
+
+ dev_dbg(&vt596_adapter.dev, "BLK=");
+ for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++)
+ printk("%02x,", inb_p(SMBBLKDAT));
+ printk("\n");
+ dev_dbg(&vt596_adapter.dev, " ");
+ for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++)
+ printk("%02x,", inb_p(SMBBLKDAT));
+ printk("%02x\n", inb_p(SMBBLKDAT));
+ }
+}
+#else
+static inline void vt596_dump_regs(const char *msg, u8 size) { }
+#endif
+
+/* Return -1 on error, 0 on success */
+static int vt596_transaction(u8 size)
+{
+ int temp;
+ int result = 0;
+ int timeout = 0;
+
+ vt596_dump_regs("Transaction (pre)", size);
+
+ /* Make sure the SMBus host is ready to start transmitting */
+ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+ dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
+ "Resetting...\n", temp);
+
+ outb_p(temp, SMBHSTSTS);
+ if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+ dev_err(&vt596_adapter.dev, "SMBus reset failed! "
+ "(0x%02x)\n", temp);
+ return -EBUSY;
+ }
+ }
+
+ /* Start the transaction by setting bit 6 */
+ outb_p(0x40 | size, SMBHSTCNT);
+
+ /* We will always wait for a fraction of a second */
+ do {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ } while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout == MAX_TIMEOUT) {
+ result = -ETIMEDOUT;
+ dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
+ }
+
+ if (temp & 0x10) {
+ result = -EIO;
+ dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
+ size);
+ }
+
+ if (temp & 0x08) {
+ result = -EIO;
+ dev_err(&vt596_adapter.dev, "SMBus collision!\n");
+ }
+
+ if (temp & 0x04) {
+ result = -ENXIO;
+ dev_dbg(&vt596_adapter.dev, "No response\n");
+ }
+
+ /* Resetting status register */
+ if (temp & 0x1F)
+ outb_p(temp, SMBHSTSTS);
+
+ vt596_dump_regs("Transaction (post)", size);
+
+ return result;
+}
+
+/* Return negative errno on error, 0 on success */
+static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int i;
+ int status;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ size = VT596_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ size = VT596_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ size = VT596_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ size = VT596_WORD_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ outb_p(command, SMBHSTCMD);
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ size = VT596_PROC_CALL;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (!(vt596_features & FEATURE_I2CBLOCK))
+ goto exit_unsupported;
+ if (read_write == I2C_SMBUS_READ)
+ outb_p(data->block[0], SMBHSTDAT0);
+ /* Fall through */
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ u8 len = data->block[0];
+ if (len > I2C_SMBUS_BLOCK_MAX)
+ len = I2C_SMBUS_BLOCK_MAX;
+ outb_p(len, SMBHSTDAT0);
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ }
+ size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ?
+ VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA;
+ break;
+ default:
+ goto exit_unsupported;
+ }
+
+ outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
+
+ status = vt596_transaction(size);
+ if (status)
+ return status;
+
+ if (size == VT596_PROC_CALL)
+ read_write = I2C_SMBUS_READ;
+
+ if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
+ return 0;
+
+ switch (size) {
+ case VT596_BYTE:
+ case VT596_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case VT596_WORD_DATA:
+ case VT596_PROC_CALL:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ case VT596_I2C_BLOCK_DATA:
+ case VT596_BLOCK_DATA:
+ data->block[0] = inb_p(SMBHSTDAT0);
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ for (i = 1; i <= data->block[0]; i++)
+ data->block[i] = inb_p(SMBBLKDAT);
+ break;
+ }
+ return 0;
+
+exit_unsupported:
+ dev_warn(&vt596_adapter.dev, "Unsupported transaction %d\n",
+ size);
+ return -EOPNOTSUPP;
+}
+
+static u32 vt596_func(struct i2c_adapter *adapter)
+{
+ u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
+
+ if (vt596_features & FEATURE_I2CBLOCK)
+ func |= I2C_FUNC_SMBUS_I2C_BLOCK;
+ return func;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = vt596_access,
+ .functionality = vt596_func,
+};
+
+static struct i2c_adapter vt596_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &smbus_algorithm,
+};
+
+static int vt596_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned char temp;
+ int error;
+
+ /* Determine the address of the SMBus areas */
+ if (force_addr) {
+ vt596_smba = force_addr & 0xfff0;
+ force = 0;
+ goto found;
+ }
+
+ if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
+ !(vt596_smba & 0x0001)) {
+ /* try 2nd address and config reg. for 596 */
+ if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
+ !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
+ (vt596_smba & 0x0001)) {
+ SMBHSTCFG = 0x84;
+ } else {
+ /* no matches at all */
+ dev_err(&pdev->dev, "Cannot configure "
+ "SMBus I/O Base address\n");
+ return -ENODEV;
+ }
+ }
+
+ vt596_smba &= 0xfff0;
+ if (vt596_smba == 0) {
+ dev_err(&pdev->dev, "SMBus base address "
+ "uninitialized - upgrade BIOS or use "
+ "force_addr=0xaddr\n");
+ return -ENODEV;
+ }
+
+found:
+ error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
+ if (error)
+ return -ENODEV;
+
+ if (!request_region(vt596_smba, 8, vt596_driver.name)) {
+ dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
+ vt596_smba);
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(pdev, SMBHSTCFG, &temp);
+ /* If force_addr is set, we program the new address here. Just to make
+ sure, we disable the VT596 first. */
+ if (force_addr) {
+ pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
+ pci_write_config_word(pdev, id->driver_data, vt596_smba);
+ pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
+ dev_warn(&pdev->dev, "WARNING: SMBus interface set to new "
+ "address 0x%04x!\n", vt596_smba);
+ } else if (!(temp & 0x01)) {
+ if (force) {
+ /* NOTE: This assumes I/O space and other allocations
+ * WERE done by the Bios! Don't complain if your
+ * hardware does weird things after enabling this.
+ * :') Check for Bios updates before resorting to
+ * this.
+ */
+ pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
+ dev_info(&pdev->dev, "Enabling SMBus device\n");
+ } else {
+ dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
+ "controller not enabled! - upgrade BIOS or "
+ "use force=1\n");
+ error = -ENODEV;
+ goto release_region;
+ }
+ }
+
+ dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_VIA_CX700:
+ case PCI_DEVICE_ID_VIA_VX800:
+ case PCI_DEVICE_ID_VIA_VX855:
+ case PCI_DEVICE_ID_VIA_VX900:
+ case PCI_DEVICE_ID_VIA_8251:
+ case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
+ case PCI_DEVICE_ID_VIA_8237S:
+ case PCI_DEVICE_ID_VIA_8235:
+ case PCI_DEVICE_ID_VIA_8233A:
+ case PCI_DEVICE_ID_VIA_8233_0:
+ vt596_features |= FEATURE_I2CBLOCK;
+ break;
+ case PCI_DEVICE_ID_VIA_82C686_4:
+ /* The VT82C686B (rev 0x40) does support I2C block
+ transactions, but the VT82C686A (rev 0x30) doesn't */
+ if (pdev->revision >= 0x40)
+ vt596_features |= FEATURE_I2CBLOCK;
+ break;
+ }
+
+ vt596_adapter.dev.parent = &pdev->dev;
+ snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
+ "SMBus Via Pro adapter at %04x", vt596_smba);
+
+ vt596_pdev = pci_dev_get(pdev);
+ error = i2c_add_adapter(&vt596_adapter);
+ if (error) {
+ pci_dev_put(vt596_pdev);
+ vt596_pdev = NULL;
+ goto release_region;
+ }
+
+ /* Always return failure here. This is to allow other drivers to bind
+ * to this pci device. We don't really want to have control over the
+ * pci device, we only wanted to read as few register values from it.
+ */
+ return -ENODEV;
+
+release_region:
+ release_region(vt596_smba, 8);
+ return error;
+}
+
+static const struct pci_device_id vt596_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
+ .driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
+ .driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX900),
+ .driver_data = SMBBA3 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, vt596_ids);
+
+static struct pci_driver vt596_driver = {
+ .name = "vt596_smbus",
+ .id_table = vt596_ids,
+ .probe = vt596_probe,
+};
+
+static int __init i2c_vt596_init(void)
+{
+ return pci_register_driver(&vt596_driver);
+}
+
+
+static void __exit i2c_vt596_exit(void)
+{
+ pci_unregister_driver(&vt596_driver);
+ if (vt596_pdev != NULL) {
+ i2c_del_adapter(&vt596_adapter);
+ release_region(vt596_smba, 8);
+ pci_dev_put(vt596_pdev);
+ vt596_pdev = NULL;
+ }
+}
+
+MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
+ "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
+ "Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("vt82c596 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_vt596_init);
+module_exit(i2c_vt596_exit);
diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c
new file mode 100644
index 000000000..7235c7302
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viperboard.c
@@ -0,0 +1,473 @@
+/*
+ * Nano River Technologies viperboard i2c master driver
+ *
+ * (C) 2012 by Lemonage GmbH
+ * Author: Lars Poeschel <poeschel@lemonage.de>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#include <linux/mfd/viperboard.h>
+
+struct vprbrd_i2c {
+ struct i2c_adapter i2c;
+ u8 bus_freq_param;
+};
+
+/* i2c bus frequency module parameter */
+static u8 i2c_bus_param;
+static unsigned int i2c_bus_freq = 100;
+module_param(i2c_bus_freq, int, 0);
+MODULE_PARM_DESC(i2c_bus_freq,
+ "i2c bus frequency in khz (default is 100) valid values: 10, 100, 200, 400, 1000, 3000, 6000");
+
+static int vprbrd_i2c_status(struct i2c_adapter *i2c,
+ struct vprbrd_i2c_status *status, bool prev_error)
+{
+ u16 bytes_xfer;
+ int ret;
+ struct vprbrd *vb = (struct vprbrd *)i2c->algo_data;
+
+ /* check for protocol error */
+ bytes_xfer = sizeof(struct vprbrd_i2c_status);
+
+ ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_I2C, VPRBRD_USB_TYPE_IN, 0x0000, 0x0000,
+ status, bytes_xfer, VPRBRD_USB_TIMEOUT_MS);
+
+ if (ret != bytes_xfer)
+ prev_error = true;
+
+ if (prev_error) {
+ dev_err(&i2c->dev, "failure in usb communication\n");
+ return -EREMOTEIO;
+ }
+
+ dev_dbg(&i2c->dev, " status = %d\n", status->status);
+ if (status->status != 0x00) {
+ dev_err(&i2c->dev, "failure: i2c protocol error\n");
+ return -EPROTO;
+ }
+ return 0;
+}
+
+static int vprbrd_i2c_receive(struct usb_device *usb_dev,
+ struct vprbrd_i2c_read_msg *rmsg, int bytes_xfer)
+{
+ int ret, bytes_actual;
+ int error = 0;
+
+ /* send the read request */
+ ret = usb_bulk_msg(usb_dev,
+ usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), rmsg,
+ sizeof(struct vprbrd_i2c_read_hdr), &bytes_actual,
+ VPRBRD_USB_TIMEOUT_MS);
+
+ if ((ret < 0)
+ || (bytes_actual != sizeof(struct vprbrd_i2c_read_hdr))) {
+ dev_err(&usb_dev->dev, "failure transmitting usb\n");
+ error = -EREMOTEIO;
+ }
+
+ /* read the actual data */
+ ret = usb_bulk_msg(usb_dev,
+ usb_rcvbulkpipe(usb_dev, VPRBRD_EP_IN), rmsg,
+ bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS);
+
+ if ((ret < 0) || (bytes_xfer != bytes_actual)) {
+ dev_err(&usb_dev->dev, "failure receiving usb\n");
+ error = -EREMOTEIO;
+ }
+ return error;
+}
+
+static int vprbrd_i2c_addr(struct usb_device *usb_dev,
+ struct vprbrd_i2c_addr_msg *amsg)
+{
+ int ret, bytes_actual;
+
+ ret = usb_bulk_msg(usb_dev,
+ usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), amsg,
+ sizeof(struct vprbrd_i2c_addr_msg), &bytes_actual,
+ VPRBRD_USB_TIMEOUT_MS);
+
+ if ((ret < 0) ||
+ (sizeof(struct vprbrd_i2c_addr_msg) != bytes_actual)) {
+ dev_err(&usb_dev->dev, "failure transmitting usb\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg)
+{
+ int ret;
+ u16 remain_len, len1, len2, start = 0x0000;
+ struct vprbrd_i2c_read_msg *rmsg =
+ (struct vprbrd_i2c_read_msg *)vb->buf;
+
+ remain_len = msg->len;
+ rmsg->header.cmd = VPRBRD_I2C_CMD_READ;
+ while (remain_len > 0) {
+ rmsg->header.addr = cpu_to_le16(start + 0x4000);
+ if (remain_len <= 255) {
+ len1 = remain_len;
+ len2 = 0x00;
+ rmsg->header.len0 = remain_len;
+ rmsg->header.len1 = 0x00;
+ rmsg->header.len2 = 0x00;
+ rmsg->header.len3 = 0x00;
+ rmsg->header.len4 = 0x00;
+ rmsg->header.len5 = 0x00;
+ remain_len = 0;
+ } else if (remain_len <= 510) {
+ len1 = remain_len;
+ len2 = 0x00;
+ rmsg->header.len0 = remain_len - 255;
+ rmsg->header.len1 = 0xff;
+ rmsg->header.len2 = 0x00;
+ rmsg->header.len3 = 0x00;
+ rmsg->header.len4 = 0x00;
+ rmsg->header.len5 = 0x00;
+ remain_len = 0;
+ } else if (remain_len <= 512) {
+ len1 = remain_len;
+ len2 = 0x00;
+ rmsg->header.len0 = remain_len - 510;
+ rmsg->header.len1 = 0xff;
+ rmsg->header.len2 = 0xff;
+ rmsg->header.len3 = 0x00;
+ rmsg->header.len4 = 0x00;
+ rmsg->header.len5 = 0x00;
+ remain_len = 0;
+ } else if (remain_len <= 767) {
+ len1 = 512;
+ len2 = remain_len - 512;
+ rmsg->header.len0 = 0x02;
+ rmsg->header.len1 = 0xff;
+ rmsg->header.len2 = 0xff;
+ rmsg->header.len3 = remain_len - 512;
+ rmsg->header.len4 = 0x00;
+ rmsg->header.len5 = 0x00;
+ remain_len = 0;
+ } else if (remain_len <= 1022) {
+ len1 = 512;
+ len2 = remain_len - 512;
+ rmsg->header.len0 = 0x02;
+ rmsg->header.len1 = 0xff;
+ rmsg->header.len2 = 0xff;
+ rmsg->header.len3 = remain_len - 767;
+ rmsg->header.len4 = 0xff;
+ rmsg->header.len5 = 0x00;
+ remain_len = 0;
+ } else if (remain_len <= 1024) {
+ len1 = 512;
+ len2 = remain_len - 512;
+ rmsg->header.len0 = 0x02;
+ rmsg->header.len1 = 0xff;
+ rmsg->header.len2 = 0xff;
+ rmsg->header.len3 = remain_len - 1022;
+ rmsg->header.len4 = 0xff;
+ rmsg->header.len5 = 0xff;
+ remain_len = 0;
+ } else {
+ len1 = 512;
+ len2 = 512;
+ rmsg->header.len0 = 0x02;
+ rmsg->header.len1 = 0xff;
+ rmsg->header.len2 = 0xff;
+ rmsg->header.len3 = 0x02;
+ rmsg->header.len4 = 0xff;
+ rmsg->header.len5 = 0xff;
+ remain_len -= 1024;
+ start += 1024;
+ }
+ rmsg->header.tf1 = cpu_to_le16(len1);
+ rmsg->header.tf2 = cpu_to_le16(len2);
+
+ /* first read transfer */
+ ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len1);
+ if (ret < 0)
+ return ret;
+ /* copy the received data */
+ memcpy(msg->buf + start, rmsg, len1);
+
+ /* second read transfer if neccessary */
+ if (len2 > 0) {
+ ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len2);
+ if (ret < 0)
+ return ret;
+ /* copy the received data */
+ memcpy(msg->buf + start + 512, rmsg, len2);
+ }
+ }
+ return 0;
+}
+
+static int vprbrd_i2c_write(struct vprbrd *vb, struct i2c_msg *msg)
+{
+ int ret, bytes_actual;
+ u16 remain_len, bytes_xfer,
+ start = 0x0000;
+ struct vprbrd_i2c_write_msg *wmsg =
+ (struct vprbrd_i2c_write_msg *)vb->buf;
+
+ remain_len = msg->len;
+ wmsg->header.cmd = VPRBRD_I2C_CMD_WRITE;
+ wmsg->header.last = 0x00;
+ wmsg->header.chan = 0x00;
+ wmsg->header.spi = 0x0000;
+ while (remain_len > 0) {
+ wmsg->header.addr = cpu_to_le16(start + 0x4000);
+ if (remain_len > 503) {
+ wmsg->header.len1 = 0xff;
+ wmsg->header.len2 = 0xf8;
+ remain_len -= 503;
+ bytes_xfer = 503 + sizeof(struct vprbrd_i2c_write_hdr);
+ start += 503;
+ } else if (remain_len > 255) {
+ wmsg->header.len1 = 0xff;
+ wmsg->header.len2 = (remain_len - 255);
+ bytes_xfer = remain_len +
+ sizeof(struct vprbrd_i2c_write_hdr);
+ remain_len = 0;
+ } else {
+ wmsg->header.len1 = remain_len;
+ wmsg->header.len2 = 0x00;
+ bytes_xfer = remain_len +
+ sizeof(struct vprbrd_i2c_write_hdr);
+ remain_len = 0;
+ }
+ memcpy(wmsg->data, msg->buf + start,
+ bytes_xfer - sizeof(struct vprbrd_i2c_write_hdr));
+
+ ret = usb_bulk_msg(vb->usb_dev,
+ usb_sndbulkpipe(vb->usb_dev,
+ VPRBRD_EP_OUT), wmsg,
+ bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS);
+ if ((ret < 0) || (bytes_xfer != bytes_actual))
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_msg *pmsg;
+ int i, ret,
+ error = 0;
+ struct vprbrd *vb = (struct vprbrd *)i2c->algo_data;
+ struct vprbrd_i2c_addr_msg *amsg =
+ (struct vprbrd_i2c_addr_msg *)vb->buf;
+ struct vprbrd_i2c_status *smsg = (struct vprbrd_i2c_status *)vb->buf;
+
+ dev_dbg(&i2c->dev, "master xfer %d messages:\n", num);
+
+ for (i = 0 ; i < num ; i++) {
+ pmsg = &msgs[i];
+
+ dev_dbg(&i2c->dev,
+ " %d: %s (flags %d) %d bytes to 0x%02x\n",
+ i, pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->flags, pmsg->len, pmsg->addr);
+
+ mutex_lock(&vb->lock);
+ /* directly send the message */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read data */
+ amsg->cmd = VPRBRD_I2C_CMD_ADDR;
+ amsg->unknown2 = 0x00;
+ amsg->unknown3 = 0x00;
+ amsg->addr = pmsg->addr;
+ amsg->unknown1 = 0x01;
+ amsg->len = cpu_to_le16(pmsg->len);
+ /* send the addr and len, we're interested to board */
+ ret = vprbrd_i2c_addr(vb->usb_dev, amsg);
+ if (ret < 0)
+ error = ret;
+
+ ret = vprbrd_i2c_read(vb, pmsg);
+ if (ret < 0)
+ error = ret;
+
+ ret = vprbrd_i2c_status(i2c, smsg, error);
+ if (ret < 0)
+ error = ret;
+ /* in case of protocol error, return the error */
+ if (error < 0)
+ goto error;
+ } else {
+ /* write data */
+ ret = vprbrd_i2c_write(vb, pmsg);
+
+ amsg->cmd = VPRBRD_I2C_CMD_ADDR;
+ amsg->unknown2 = 0x00;
+ amsg->unknown3 = 0x00;
+ amsg->addr = pmsg->addr;
+ amsg->unknown1 = 0x00;
+ amsg->len = cpu_to_le16(pmsg->len);
+ /* send the addr, the data goes to to board */
+ ret = vprbrd_i2c_addr(vb->usb_dev, amsg);
+ if (ret < 0)
+ error = ret;
+
+ ret = vprbrd_i2c_status(i2c, smsg, error);
+ if (ret < 0)
+ error = ret;
+
+ if (error < 0)
+ goto error;
+ }
+ mutex_unlock(&vb->lock);
+ }
+ return num;
+error:
+ mutex_unlock(&vb->lock);
+ return error;
+}
+
+static u32 vprbrd_i2c_func(struct i2c_adapter *i2c)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm vprbrd_algorithm = {
+ .master_xfer = vprbrd_i2c_xfer,
+ .functionality = vprbrd_i2c_func,
+};
+
+static const struct i2c_adapter_quirks vprbrd_quirks = {
+ .max_read_len = 2048,
+ .max_write_len = 2048,
+};
+
+static int vprbrd_i2c_probe(struct platform_device *pdev)
+{
+ struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
+ struct vprbrd_i2c *vb_i2c;
+ int ret;
+ int pipe;
+
+ vb_i2c = devm_kzalloc(&pdev->dev, sizeof(*vb_i2c), GFP_KERNEL);
+ if (vb_i2c == NULL)
+ return -ENOMEM;
+
+ /* setup i2c adapter description */
+ vb_i2c->i2c.owner = THIS_MODULE;
+ vb_i2c->i2c.class = I2C_CLASS_HWMON;
+ vb_i2c->i2c.algo = &vprbrd_algorithm;
+ vb_i2c->i2c.quirks = &vprbrd_quirks;
+ vb_i2c->i2c.algo_data = vb;
+ /* save the param in usb capabable memory */
+ vb_i2c->bus_freq_param = i2c_bus_param;
+
+ snprintf(vb_i2c->i2c.name, sizeof(vb_i2c->i2c.name),
+ "viperboard at bus %03d device %03d",
+ vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
+
+ /* setting the bus frequency */
+ if ((i2c_bus_param <= VPRBRD_I2C_FREQ_10KHZ)
+ && (i2c_bus_param >= VPRBRD_I2C_FREQ_6MHZ)) {
+ pipe = usb_sndctrlpipe(vb->usb_dev, 0);
+ ret = usb_control_msg(vb->usb_dev, pipe,
+ VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT,
+ 0x0000, 0x0000, &vb_i2c->bus_freq_param, 1,
+ VPRBRD_USB_TIMEOUT_MS);
+ if (ret != 1) {
+ dev_err(&pdev->dev, "failure setting i2c_bus_freq to %d\n",
+ i2c_bus_freq);
+ return -EIO;
+ }
+ } else {
+ dev_err(&pdev->dev,
+ "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq);
+ return -EIO;
+ }
+
+ vb_i2c->i2c.dev.parent = &pdev->dev;
+
+ /* attach to i2c layer */
+ i2c_add_adapter(&vb_i2c->i2c);
+
+ platform_set_drvdata(pdev, vb_i2c);
+
+ return 0;
+}
+
+static int vprbrd_i2c_remove(struct platform_device *pdev)
+{
+ struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&vb_i2c->i2c);
+
+ return 0;
+}
+
+static struct platform_driver vprbrd_i2c_driver = {
+ .driver.name = "viperboard-i2c",
+ .driver.owner = THIS_MODULE,
+ .probe = vprbrd_i2c_probe,
+ .remove = vprbrd_i2c_remove,
+};
+
+static int __init vprbrd_i2c_init(void)
+{
+ switch (i2c_bus_freq) {
+ case 6000:
+ i2c_bus_param = VPRBRD_I2C_FREQ_6MHZ;
+ break;
+ case 3000:
+ i2c_bus_param = VPRBRD_I2C_FREQ_3MHZ;
+ break;
+ case 1000:
+ i2c_bus_param = VPRBRD_I2C_FREQ_1MHZ;
+ break;
+ case 400:
+ i2c_bus_param = VPRBRD_I2C_FREQ_400KHZ;
+ break;
+ case 200:
+ i2c_bus_param = VPRBRD_I2C_FREQ_200KHZ;
+ break;
+ case 100:
+ i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ;
+ break;
+ case 10:
+ i2c_bus_param = VPRBRD_I2C_FREQ_10KHZ;
+ break;
+ default:
+ pr_warn("invalid i2c_bus_freq (%d)\n", i2c_bus_freq);
+ i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ;
+ }
+
+ return platform_driver_register(&vprbrd_i2c_driver);
+}
+subsys_initcall(vprbrd_i2c_init);
+
+static void __exit vprbrd_i2c_exit(void)
+{
+ platform_driver_unregister(&vprbrd_i2c_driver);
+}
+module_exit(vprbrd_i2c_exit);
+
+MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
+MODULE_DESCRIPTION("I2C master driver for Nano River Techs Viperboard");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:viperboard-i2c");
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
new file mode 100644
index 000000000..fbd0fd59f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -0,0 +1,474 @@
+/*
+ * Wondermedia I2C Master Mode Driver
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * Derived from GPLv2+ licensed source:
+ * - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, or
+ * (at your option) any later version. as published by the Free Software
+ * Foundation
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define REG_CR 0x00
+#define REG_TCR 0x02
+#define REG_CSR 0x04
+#define REG_ISR 0x06
+#define REG_IMR 0x08
+#define REG_CDR 0x0A
+#define REG_TR 0x0C
+#define REG_MCR 0x0E
+#define REG_SLAVE_CR 0x10
+#define REG_SLAVE_SR 0x12
+#define REG_SLAVE_ISR 0x14
+#define REG_SLAVE_IMR 0x16
+#define REG_SLAVE_DR 0x18
+#define REG_SLAVE_TR 0x1A
+
+/* REG_CR Bit fields */
+#define CR_TX_NEXT_ACK 0x0000
+#define CR_ENABLE 0x0001
+#define CR_TX_NEXT_NO_ACK 0x0002
+#define CR_TX_END 0x0004
+#define CR_CPU_RDY 0x0008
+#define SLAV_MODE_SEL 0x8000
+
+/* REG_TCR Bit fields */
+#define TCR_STANDARD_MODE 0x0000
+#define TCR_MASTER_WRITE 0x0000
+#define TCR_HS_MODE 0x2000
+#define TCR_MASTER_READ 0x4000
+#define TCR_FAST_MODE 0x8000
+#define TCR_SLAVE_ADDR_MASK 0x007F
+
+/* REG_ISR Bit fields */
+#define ISR_NACK_ADDR 0x0001
+#define ISR_BYTE_END 0x0002
+#define ISR_SCL_TIMEOUT 0x0004
+#define ISR_WRITE_ALL 0x0007
+
+/* REG_IMR Bit fields */
+#define IMR_ENABLE_ALL 0x0007
+
+/* REG_CSR Bit fields */
+#define CSR_RCV_NOT_ACK 0x0001
+#define CSR_RCV_ACK_MASK 0x0001
+#define CSR_READY_MASK 0x0002
+
+/* REG_TR */
+#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8)
+#define TR_STD 0x0064
+#define TR_HS 0x0019
+
+/* REG_MCR */
+#define MCR_APB_96M 7
+#define MCR_APB_166M 12
+
+#define I2C_MODE_STANDARD 0
+#define I2C_MODE_FAST 1
+
+#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+struct wmt_i2c_dev {
+ struct i2c_adapter adapter;
+ struct completion complete;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+ int mode;
+ int irq;
+ u16 cmd_status;
+};
+
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + WMT_I2C_TIMEOUT;
+ while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+ return -EBUSY;
+ }
+ msleep(20);
+ }
+
+ return 0;
+}
+
+static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+{
+ int ret = 0;
+
+ if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+ ret = -EIO;
+
+ if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+ ret = -ETIMEDOUT;
+
+ return ret;
+}
+
+static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+ int last)
+{
+ struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ u16 val, tcr_val;
+ int ret;
+ unsigned long wait_result;
+ int xfer_len = 0;
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (pmsg->len == 0) {
+ /*
+ * We still need to run through the while (..) once, so
+ * start at -1 and break out early from the loop
+ */
+ xfer_len = -1;
+ writew(0, i2c_dev->base + REG_CDR);
+ } else {
+ writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+ }
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ val = readw(i2c_dev->base + REG_CR);
+ val &= ~CR_TX_END;
+ writew(val, i2c_dev->base + REG_CR);
+
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ reinit_completion(&i2c_dev->complete);
+
+ if (i2c_dev->mode == I2C_MODE_STANDARD)
+ tcr_val = TCR_STANDARD_MODE;
+ else
+ tcr_val = TCR_FAST_MODE;
+
+ tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+
+ writew(tcr_val, i2c_dev->base + REG_TCR);
+
+ if (pmsg->flags & I2C_M_NOSTART) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ while (xfer_len < pmsg->len) {
+ wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+ msecs_to_jiffies(500));
+
+ if (wait_result == 0)
+ return -ETIMEDOUT;
+
+ ret = wmt_check_status(i2c_dev);
+ if (ret)
+ return ret;
+
+ xfer_len++;
+
+ val = readw(i2c_dev->base + REG_CSR);
+ if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+ dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+ return -EIO;
+ }
+
+ if (pmsg->len == 0) {
+ val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
+ writew(val, i2c_dev->base + REG_CR);
+ break;
+ }
+
+ if (xfer_len == pmsg->len) {
+ if (last != 1)
+ writew(CR_ENABLE, i2c_dev->base + REG_CR);
+ } else {
+ writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
+ REG_CDR);
+ writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+ }
+ }
+
+ return 0;
+}
+
+static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+ int last)
+{
+ struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ u16 val, tcr_val;
+ int ret;
+ unsigned long wait_result;
+ u32 xfer_len = 0;
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ val = readw(i2c_dev->base + REG_CR);
+ val &= ~CR_TX_END;
+ writew(val, i2c_dev->base + REG_CR);
+
+ val = readw(i2c_dev->base + REG_CR);
+ val &= ~CR_TX_NEXT_NO_ACK;
+ writew(val, i2c_dev->base + REG_CR);
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ if (pmsg->len == 1) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_TX_NEXT_NO_ACK;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ reinit_completion(&i2c_dev->complete);
+
+ if (i2c_dev->mode == I2C_MODE_STANDARD)
+ tcr_val = TCR_STANDARD_MODE;
+ else
+ tcr_val = TCR_FAST_MODE;
+
+ tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+
+ writew(tcr_val, i2c_dev->base + REG_TCR);
+
+ if (pmsg->flags & I2C_M_NOSTART) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ while (xfer_len < pmsg->len) {
+ wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+ msecs_to_jiffies(500));
+
+ if (!wait_result)
+ return -ETIMEDOUT;
+
+ ret = wmt_check_status(i2c_dev);
+ if (ret)
+ return ret;
+
+ pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+ xfer_len++;
+
+ if (xfer_len == pmsg->len - 1) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY);
+ writew(val, i2c_dev->base + REG_CR);
+ } else {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+ }
+
+ return 0;
+}
+
+static int wmt_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct i2c_msg *pmsg;
+ int i, is_last;
+ int ret = 0;
+
+ for (i = 0; ret >= 0 && i < num; i++) {
+ is_last = ((i + 1) == num);
+
+ pmsg = &msgs[i];
+ if (pmsg->flags & I2C_M_RD)
+ ret = wmt_i2c_read(adap, pmsg, is_last);
+ else
+ ret = wmt_i2c_write(adap, pmsg, is_last);
+ }
+
+ return (ret < 0) ? ret : i;
+}
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+ .master_xfer = wmt_i2c_xfer,
+ .functionality = wmt_i2c_func,
+};
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+ struct wmt_i2c_dev *i2c_dev = data;
+
+ /* save the status and write-clear it */
+ i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
+ writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+{
+ int err;
+
+ err = clk_prepare_enable(i2c_dev->clk);
+ if (err) {
+ dev_err(i2c_dev->dev, "failed to enable clock\n");
+ return err;
+ }
+
+ 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;
+ }
+
+ writew(0, i2c_dev->base + REG_CR);
+ writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
+ writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+ writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
+ writew(CR_ENABLE, i2c_dev->base + REG_CR);
+ readw(i2c_dev->base + REG_CSR); /* read clear */
+ writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+
+ if (i2c_dev->mode == I2C_MODE_STANDARD)
+ writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+ else
+ writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+
+ return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct wmt_i2c_dev *i2c_dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int err;
+ u32 clk_rate;
+
+ 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(np, 0);
+ 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;
+ err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+ if ((!err) && (clk_rate == 400000))
+ i2c_dev->mode = I2C_MODE_FAST;
+
+ i2c_dev->dev = &pdev->dev;
+
+ err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
+ "i2c", i2c_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
+ return err;
+ }
+
+ adap = &i2c_dev->adapter;
+ i2c_set_adapdata(adap, i2c_dev);
+ strlcpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+ adap->owner = THIS_MODULE;
+ adap->algo = &wmt_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ init_completion(&i2c_dev->complete);
+
+ err = wmt_i2c_reset_hardware(i2c_dev);
+ if (err) {
+ dev_err(&pdev->dev, "error initializing hardware\n");
+ return err;
+ }
+
+ err = i2c_add_adapter(adap);
+ if (err)
+ return err;
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ return 0;
+}
+
+static int wmt_i2c_remove(struct platform_device *pdev)
+{
+ struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ /* Disable interrupts, clock and delete adapter */
+ writew(0, i2c_dev->base + REG_IMR);
+ clk_disable_unprepare(i2c_dev->clk);
+ i2c_del_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+ { .compatible = "wm,wm8505-i2c" },
+ { /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+ .probe = wmt_i2c_probe,
+ .remove = wmt_i2c_remove,
+ .driver = {
+ .name = "wmt-i2c",
+ .of_match_table = wmt_i2c_dt_ids,
+ },
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c
new file mode 100644
index 000000000..a7ac74601
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -0,0 +1,627 @@
+/*
+ * X-Gene SLIMpro I2C Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ * Author: Hieu Le <hnle@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This driver provides support for X-Gene SLIMpro I2C device access
+ * using the APM X-Gene SLIMpro mailbox driver.
+ *
+ */
+#include <acpi/pcc.h>
+#include <linux/acpi.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+
+#define MAILBOX_OP_TIMEOUT 1000 /* Operation time out in ms */
+#define MAILBOX_I2C_INDEX 0
+#define SLIMPRO_IIC_BUS 1 /* Use I2C bus 1 only */
+
+#define SMBUS_CMD_LEN 1
+#define BYTE_DATA 1
+#define WORD_DATA 2
+#define BLOCK_DATA 3
+
+#define SLIMPRO_IIC_I2C_PROTOCOL 0
+#define SLIMPRO_IIC_SMB_PROTOCOL 1
+
+#define SLIMPRO_IIC_READ 0
+#define SLIMPRO_IIC_WRITE 1
+
+#define IIC_SMB_WITHOUT_DATA_LEN 0
+#define IIC_SMB_WITH_DATA_LEN 1
+
+#define SLIMPRO_DEBUG_MSG 0
+#define SLIMPRO_MSG_TYPE_SHIFT 28
+#define SLIMPRO_DBG_SUBTYPE_I2C1READ 4
+#define SLIMPRO_DBGMSG_TYPE_SHIFT 24
+#define SLIMPRO_DBGMSG_TYPE_MASK 0x0F000000U
+#define SLIMPRO_IIC_DEV_SHIFT 23
+#define SLIMPRO_IIC_DEV_MASK 0x00800000U
+#define SLIMPRO_IIC_DEVID_SHIFT 13
+#define SLIMPRO_IIC_DEVID_MASK 0x007FE000U
+#define SLIMPRO_IIC_RW_SHIFT 12
+#define SLIMPRO_IIC_RW_MASK 0x00001000U
+#define SLIMPRO_IIC_PROTO_SHIFT 11
+#define SLIMPRO_IIC_PROTO_MASK 0x00000800U
+#define SLIMPRO_IIC_ADDRLEN_SHIFT 8
+#define SLIMPRO_IIC_ADDRLEN_MASK 0x00000700U
+#define SLIMPRO_IIC_DATALEN_SHIFT 0
+#define SLIMPRO_IIC_DATALEN_MASK 0x000000FFU
+
+/*
+ * SLIMpro I2C message encode
+ *
+ * dev - Controller number (0-based)
+ * chip - I2C chip address
+ * op - SLIMPRO_IIC_READ or SLIMPRO_IIC_WRITE
+ * proto - SLIMPRO_IIC_SMB_PROTOCOL or SLIMPRO_IIC_I2C_PROTOCOL
+ * addrlen - Length of the address field
+ * datalen - Length of the data field
+ */
+#define SLIMPRO_IIC_ENCODE_MSG(dev, chip, op, proto, addrlen, datalen) \
+ ((SLIMPRO_DEBUG_MSG << SLIMPRO_MSG_TYPE_SHIFT) | \
+ ((SLIMPRO_DBG_SUBTYPE_I2C1READ << SLIMPRO_DBGMSG_TYPE_SHIFT) & \
+ SLIMPRO_DBGMSG_TYPE_MASK) | \
+ ((dev << SLIMPRO_IIC_DEV_SHIFT) & SLIMPRO_IIC_DEV_MASK) | \
+ ((chip << SLIMPRO_IIC_DEVID_SHIFT) & SLIMPRO_IIC_DEVID_MASK) | \
+ ((op << SLIMPRO_IIC_RW_SHIFT) & SLIMPRO_IIC_RW_MASK) | \
+ ((proto << SLIMPRO_IIC_PROTO_SHIFT) & SLIMPRO_IIC_PROTO_MASK) | \
+ ((addrlen << SLIMPRO_IIC_ADDRLEN_SHIFT) & SLIMPRO_IIC_ADDRLEN_MASK) | \
+ ((datalen << SLIMPRO_IIC_DATALEN_SHIFT) & SLIMPRO_IIC_DATALEN_MASK))
+
+#define SLIMPRO_MSG_TYPE(v) (((v) & 0xF0000000) >> 28)
+
+/*
+ * Encode for upper address for block data
+ */
+#define SLIMPRO_IIC_ENCODE_FLAG_BUFADDR 0x80000000
+#define SLIMPRO_IIC_ENCODE_FLAG_WITH_DATA_LEN(a) ((u32) (((a) << 30) \
+ & 0x40000000))
+#define SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(a) ((u32) (((a) >> 12) \
+ & 0x3FF00000))
+#define SLIMPRO_IIC_ENCODE_ADDR(a) ((a) & 0x000FFFFF)
+
+#define SLIMPRO_IIC_MSG_DWORD_COUNT 3
+
+/* PCC related defines */
+#define PCC_SIGNATURE 0x50424300
+#define PCC_STS_CMD_COMPLETE BIT(0)
+#define PCC_STS_SCI_DOORBELL BIT(1)
+#define PCC_STS_ERR BIT(2)
+#define PCC_STS_PLAT_NOTIFY BIT(3)
+#define PCC_CMD_GENERATE_DB_INT BIT(15)
+
+struct slimpro_i2c_dev {
+ struct i2c_adapter adapter;
+ struct device *dev;
+ struct mbox_chan *mbox_chan;
+ struct mbox_client mbox_client;
+ int mbox_idx;
+ struct completion rd_complete;
+ u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */
+ u32 *resp_msg;
+ phys_addr_t comm_base_addr;
+ void *pcc_comm_addr;
+};
+
+#define to_slimpro_i2c_dev(cl) \
+ container_of(cl, struct slimpro_i2c_dev, mbox_client)
+
+enum slimpro_i2c_version {
+ XGENE_SLIMPRO_I2C_V1 = 0,
+ XGENE_SLIMPRO_I2C_V2 = 1,
+};
+
+/*
+ * This function tests and clears a bitmask then returns its old value
+ */
+static u16 xgene_word_tst_and_clr(u16 *addr, u16 mask)
+{
+ u16 ret, val;
+
+ val = le16_to_cpu(READ_ONCE(*addr));
+ ret = val & mask;
+ val &= ~mask;
+ WRITE_ONCE(*addr, cpu_to_le16(val));
+
+ return ret;
+}
+
+static void slimpro_i2c_rx_cb(struct mbox_client *cl, void *mssg)
+{
+ struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl);
+
+ /*
+ * Response message format:
+ * mssg[0] is the return code of the operation
+ * mssg[1] is the first data word
+ * mssg[2] is NOT used
+ */
+ if (ctx->resp_msg)
+ *ctx->resp_msg = ((u32 *)mssg)[1];
+
+ if (ctx->mbox_client.tx_block)
+ complete(&ctx->rd_complete);
+}
+
+static void slimpro_i2c_pcc_rx_cb(struct mbox_client *cl, void *msg)
+{
+ struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl);
+ struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr;
+
+ /* Check if platform sends interrupt */
+ if (!xgene_word_tst_and_clr(&generic_comm_base->status,
+ PCC_STS_SCI_DOORBELL))
+ return;
+
+ if (xgene_word_tst_and_clr(&generic_comm_base->status,
+ PCC_STS_CMD_COMPLETE)) {
+ msg = generic_comm_base + 1;
+
+ /* Response message msg[1] contains the return value. */
+ if (ctx->resp_msg)
+ *ctx->resp_msg = ((u32 *)msg)[1];
+
+ complete(&ctx->rd_complete);
+ }
+}
+
+static void slimpro_i2c_pcc_tx_prepare(struct slimpro_i2c_dev *ctx, u32 *msg)
+{
+ struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr;
+ u32 *ptr = (void *)(generic_comm_base + 1);
+ u16 status;
+ int i;
+
+ WRITE_ONCE(generic_comm_base->signature,
+ cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx));
+
+ WRITE_ONCE(generic_comm_base->command,
+ cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INT));
+
+ status = le16_to_cpu(READ_ONCE(generic_comm_base->status));
+ status &= ~PCC_STS_CMD_COMPLETE;
+ WRITE_ONCE(generic_comm_base->status, cpu_to_le16(status));
+
+ /* Copy the message to the PCC comm space */
+ for (i = 0; i < SLIMPRO_IIC_MSG_DWORD_COUNT; i++)
+ WRITE_ONCE(ptr[i], cpu_to_le32(msg[i]));
+}
+
+static int start_i2c_msg_xfer(struct slimpro_i2c_dev *ctx)
+{
+ if (ctx->mbox_client.tx_block || !acpi_disabled) {
+ if (!wait_for_completion_timeout(&ctx->rd_complete,
+ msecs_to_jiffies(MAILBOX_OP_TIMEOUT)))
+ return -ETIMEDOUT;
+ }
+
+ /* Check of invalid data or no device */
+ if (*ctx->resp_msg == 0xffffffff)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int slimpro_i2c_send_msg(struct slimpro_i2c_dev *ctx,
+ u32 *msg,
+ u32 *data)
+{
+ int rc;
+
+ ctx->resp_msg = data;
+
+ if (!acpi_disabled) {
+ reinit_completion(&ctx->rd_complete);
+ slimpro_i2c_pcc_tx_prepare(ctx, msg);
+ }
+
+ rc = mbox_send_message(ctx->mbox_chan, msg);
+ if (rc < 0)
+ goto err;
+
+ rc = start_i2c_msg_xfer(ctx);
+
+err:
+ if (!acpi_disabled)
+ mbox_chan_txdone(ctx->mbox_chan, 0);
+
+ ctx->resp_msg = NULL;
+
+ return rc;
+}
+
+static int slimpro_i2c_rd(struct slimpro_i2c_dev *ctx, u32 chip,
+ u32 addr, u32 addrlen, u32 protocol,
+ u32 readlen, u32 *data)
+{
+ u32 msg[3];
+
+ msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip,
+ SLIMPRO_IIC_READ, protocol, addrlen, readlen);
+ msg[1] = SLIMPRO_IIC_ENCODE_ADDR(addr);
+ msg[2] = 0;
+
+ return slimpro_i2c_send_msg(ctx, msg, data);
+}
+
+static int slimpro_i2c_wr(struct slimpro_i2c_dev *ctx, u32 chip,
+ u32 addr, u32 addrlen, u32 protocol, u32 writelen,
+ u32 data)
+{
+ u32 msg[3];
+
+ msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip,
+ SLIMPRO_IIC_WRITE, protocol, addrlen, writelen);
+ msg[1] = SLIMPRO_IIC_ENCODE_ADDR(addr);
+ msg[2] = data;
+
+ return slimpro_i2c_send_msg(ctx, msg, msg);
+}
+
+static int slimpro_i2c_blkrd(struct slimpro_i2c_dev *ctx, u32 chip, u32 addr,
+ u32 addrlen, u32 protocol, u32 readlen,
+ u32 with_data_len, void *data)
+{
+ dma_addr_t paddr;
+ u32 msg[3];
+ int rc;
+
+ paddr = dma_map_single(ctx->dev, ctx->dma_buffer, readlen, DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, paddr)) {
+ dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n",
+ ctx->dma_buffer);
+ return -ENOMEM;
+ }
+
+ msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, SLIMPRO_IIC_READ,
+ protocol, addrlen, readlen);
+ msg[1] = SLIMPRO_IIC_ENCODE_FLAG_BUFADDR |
+ SLIMPRO_IIC_ENCODE_FLAG_WITH_DATA_LEN(with_data_len) |
+ SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(paddr) |
+ SLIMPRO_IIC_ENCODE_ADDR(addr);
+ msg[2] = (u32)paddr;
+
+ rc = slimpro_i2c_send_msg(ctx, msg, msg);
+
+ /* Copy to destination */
+ memcpy(data, ctx->dma_buffer, readlen);
+
+ dma_unmap_single(ctx->dev, paddr, readlen, DMA_FROM_DEVICE);
+ return rc;
+}
+
+static int slimpro_i2c_blkwr(struct slimpro_i2c_dev *ctx, u32 chip,
+ u32 addr, u32 addrlen, u32 protocol, u32 writelen,
+ void *data)
+{
+ dma_addr_t paddr;
+ u32 msg[3];
+ int rc;
+
+ memcpy(ctx->dma_buffer, data, writelen);
+ paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, paddr)) {
+ dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n",
+ ctx->dma_buffer);
+ return -ENOMEM;
+ }
+
+ msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, SLIMPRO_IIC_WRITE,
+ protocol, addrlen, writelen);
+ msg[1] = SLIMPRO_IIC_ENCODE_FLAG_BUFADDR |
+ SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(paddr) |
+ SLIMPRO_IIC_ENCODE_ADDR(addr);
+ msg[2] = (u32)paddr;
+
+ if (ctx->mbox_client.tx_block)
+ reinit_completion(&ctx->rd_complete);
+
+ rc = slimpro_i2c_send_msg(ctx, msg, msg);
+
+ dma_unmap_single(ctx->dev, paddr, writelen, DMA_TO_DEVICE);
+ return rc;
+}
+
+static int xgene_slimpro_i2c_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct slimpro_i2c_dev *ctx = i2c_get_adapdata(adap);
+ int ret = -EOPNOTSUPP;
+ u32 val;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ ret = slimpro_i2c_rd(ctx, addr, 0, 0,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ BYTE_DATA, &val);
+ data->byte = val;
+ } else {
+ ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ 0, 0);
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ ret = slimpro_i2c_rd(ctx, addr, command, SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ BYTE_DATA, &val);
+ data->byte = val;
+ } else {
+ val = data->byte;
+ ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ BYTE_DATA, val);
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ ret = slimpro_i2c_rd(ctx, addr, command, SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ WORD_DATA, &val);
+ data->word = val;
+ } else {
+ val = data->word;
+ ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ WORD_DATA, val);
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ ret = slimpro_i2c_blkrd(ctx, addr, command,
+ SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ I2C_SMBUS_BLOCK_MAX + 1,
+ IIC_SMB_WITH_DATA_LEN,
+ &data->block[0]);
+
+ } else {
+ ret = slimpro_i2c_blkwr(ctx, addr, command,
+ SMBUS_CMD_LEN,
+ SLIMPRO_IIC_SMB_PROTOCOL,
+ data->block[0] + 1,
+ &data->block[0]);
+ }
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ ret = slimpro_i2c_blkrd(ctx, addr,
+ command,
+ SMBUS_CMD_LEN,
+ SLIMPRO_IIC_I2C_PROTOCOL,
+ I2C_SMBUS_BLOCK_MAX,
+ IIC_SMB_WITHOUT_DATA_LEN,
+ &data->block[1]);
+ } else {
+ ret = slimpro_i2c_blkwr(ctx, addr, command,
+ SMBUS_CMD_LEN,
+ SLIMPRO_IIC_I2C_PROTOCOL,
+ data->block[0],
+ &data->block[1]);
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+/*
+* Return list of supported functionality.
+*/
+static u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm xgene_slimpro_i2c_algorithm = {
+ .smbus_xfer = xgene_slimpro_i2c_xfer,
+ .functionality = xgene_slimpro_i2c_func,
+};
+
+static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
+{
+ struct slimpro_i2c_dev *ctx;
+ struct i2c_adapter *adapter;
+ struct mbox_client *cl;
+ int rc;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ctx);
+ cl = &ctx->mbox_client;
+
+ /* Request mailbox channel */
+ cl->dev = &pdev->dev;
+ init_completion(&ctx->rd_complete);
+ cl->tx_tout = MAILBOX_OP_TIMEOUT;
+ cl->knows_txdone = false;
+ if (acpi_disabled) {
+ cl->tx_block = true;
+ cl->rx_callback = slimpro_i2c_rx_cb;
+ ctx->mbox_chan = mbox_request_channel(cl, MAILBOX_I2C_INDEX);
+ if (IS_ERR(ctx->mbox_chan)) {
+ dev_err(&pdev->dev, "i2c mailbox channel request failed\n");
+ return PTR_ERR(ctx->mbox_chan);
+ }
+ } else {
+ struct acpi_pcct_hw_reduced *cppc_ss;
+ const struct acpi_device_id *acpi_id;
+ int version = XGENE_SLIMPRO_I2C_V1;
+
+ acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
+ &pdev->dev);
+ if (!acpi_id)
+ return -EINVAL;
+
+ version = (int)acpi_id->driver_data;
+
+ if (device_property_read_u32(&pdev->dev, "pcc-channel",
+ &ctx->mbox_idx))
+ ctx->mbox_idx = MAILBOX_I2C_INDEX;
+
+ cl->tx_block = false;
+ cl->rx_callback = slimpro_i2c_pcc_rx_cb;
+ ctx->mbox_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx);
+ if (IS_ERR(ctx->mbox_chan)) {
+ dev_err(&pdev->dev, "PCC mailbox channel request failed\n");
+ return PTR_ERR(ctx->mbox_chan);
+ }
+
+ /*
+ * The PCC mailbox controller driver should
+ * have parsed the PCCT (global table of all
+ * PCC channels) and stored pointers to the
+ * subspace communication region in con_priv.
+ */
+ cppc_ss = ctx->mbox_chan->con_priv;
+ if (!cppc_ss) {
+ dev_err(&pdev->dev, "PPC subspace not found\n");
+ rc = -ENOENT;
+ goto mbox_err;
+ }
+
+ if (!ctx->mbox_chan->mbox->txdone_irq) {
+ dev_err(&pdev->dev, "PCC IRQ not supported\n");
+ rc = -ENOENT;
+ goto mbox_err;
+ }
+
+ /*
+ * This is the shared communication region
+ * for the OS and Platform to communicate over.
+ */
+ ctx->comm_base_addr = cppc_ss->base_address;
+ if (ctx->comm_base_addr) {
+ if (version == XGENE_SLIMPRO_I2C_V2)
+ ctx->pcc_comm_addr = memremap(
+ ctx->comm_base_addr,
+ cppc_ss->length,
+ MEMREMAP_WT);
+ else
+ ctx->pcc_comm_addr = memremap(
+ ctx->comm_base_addr,
+ cppc_ss->length,
+ MEMREMAP_WB);
+ } else {
+ dev_err(&pdev->dev, "Failed to get PCC comm region\n");
+ rc = -ENOENT;
+ goto mbox_err;
+ }
+
+ if (!ctx->pcc_comm_addr) {
+ dev_err(&pdev->dev,
+ "Failed to ioremap PCC comm region\n");
+ rc = -ENOMEM;
+ goto mbox_err;
+ }
+ }
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rc)
+ dev_warn(&pdev->dev, "Unable to set dma mask\n");
+
+ /* Setup I2C adapter */
+ adapter = &ctx->adapter;
+ snprintf(adapter->name, sizeof(adapter->name), "MAILBOX I2C");
+ adapter->algo = &xgene_slimpro_i2c_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+ adapter->dev.of_node = pdev->dev.of_node;
+ ACPI_COMPANION_SET(&adapter->dev, ACPI_COMPANION(&pdev->dev));
+ i2c_set_adapdata(adapter, ctx);
+ rc = i2c_add_adapter(adapter);
+ if (rc)
+ goto mbox_err;
+
+ dev_info(&pdev->dev, "Mailbox I2C Adapter registered\n");
+ return 0;
+
+mbox_err:
+ if (acpi_disabled)
+ mbox_free_channel(ctx->mbox_chan);
+ else
+ pcc_mbox_free_channel(ctx->mbox_chan);
+
+ return rc;
+}
+
+static int xgene_slimpro_i2c_remove(struct platform_device *pdev)
+{
+ struct slimpro_i2c_dev *ctx = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&ctx->adapter);
+
+ if (acpi_disabled)
+ mbox_free_channel(ctx->mbox_chan);
+ else
+ pcc_mbox_free_channel(ctx->mbox_chan);
+
+ return 0;
+}
+
+static const struct of_device_id xgene_slimpro_i2c_dt_ids[] = {
+ {.compatible = "apm,xgene-slimpro-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = {
+ {"APMC0D40", XGENE_SLIMPRO_I2C_V1},
+ {"APMC0D8B", XGENE_SLIMPRO_I2C_V2},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids);
+#endif
+
+static struct platform_driver xgene_slimpro_i2c_driver = {
+ .probe = xgene_slimpro_i2c_probe,
+ .remove = xgene_slimpro_i2c_remove,
+ .driver = {
+ .name = "xgene-slimpro-i2c",
+ .of_match_table = of_match_ptr(xgene_slimpro_i2c_dt_ids),
+ .acpi_match_table = ACPI_PTR(xgene_slimpro_i2c_acpi_ids)
+ },
+};
+
+module_platform_driver(xgene_slimpro_i2c_driver);
+
+MODULE_DESCRIPTION("APM X-Gene SLIMpro I2C driver");
+MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
+MODULE_AUTHOR("Hieu Le <hnle@apm.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
new file mode 100644
index 000000000..52acb185a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -0,0 +1,899 @@
+/*
+ * i2c-xiic.c
+ * Copyright (c) 2002-2007 Xilinx Inc.
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * This code was implemented by Mocean Laboratories AB when porting linux
+ * to the automotive development board Russellville. The copyright holder
+ * as seen in the header is Intel corporation.
+ * Mocean Laboratories forked off the GNU/Linux platform work into a
+ * separate company called Pelagicore AB, which committed the code to the
+ * kernel.
+ */
+
+/* Supports:
+ * Xilinx IIC
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/platform_data/i2c-xiic.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+
+#define DRIVER_NAME "xiic-i2c"
+
+enum xilinx_i2c_state {
+ STATE_DONE,
+ STATE_ERROR,
+ STATE_START
+};
+
+enum xiic_endian {
+ LITTLE,
+ BIG
+};
+
+/**
+ * struct xiic_i2c - Internal representation of the XIIC I2C bus
+ * @base: Memory base of the HW registers
+ * @wait: Wait queue for callers
+ * @adap: Kernel adapter representation
+ * @tx_msg: Messages from above to be sent
+ * @lock: Mutual exclusion
+ * @tx_pos: Current pos in TX message
+ * @nmsgs: Number of messages in tx_msg
+ * @state: See STATE_
+ * @rx_msg: Current RX message
+ * @rx_pos: Position within current RX message
+ * @endianness: big/little-endian byte order
+ */
+struct xiic_i2c {
+ struct device *dev;
+ void __iomem *base;
+ wait_queue_head_t wait;
+ struct i2c_adapter adap;
+ struct i2c_msg *tx_msg;
+ struct mutex lock;
+ unsigned int tx_pos;
+ unsigned int nmsgs;
+ enum xilinx_i2c_state state;
+ struct i2c_msg *rx_msg;
+ int rx_pos;
+ enum xiic_endian endianness;
+ struct clk *clk;
+};
+
+
+#define XIIC_MSB_OFFSET 0
+#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
+
+/*
+ * Register offsets in bytes from RegisterBase. Three is added to the
+ * base offset to access LSB (IBM style) of the word
+ */
+#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */
+#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */
+#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */
+#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */
+#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */
+#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
+#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
+#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */
+#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
+#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */
+
+/* Control Register masks */
+#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
+#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
+#define XIIC_CR_MSMS_MASK 0x04 /* Master starts Txing=1 */
+#define XIIC_CR_DIR_IS_TX_MASK 0x08 /* Dir of tx. Txing=1 */
+#define XIIC_CR_NO_ACK_MASK 0x10 /* Tx Ack. NO ack = 1 */
+#define XIIC_CR_REPEATED_START_MASK 0x20 /* Repeated start = 1 */
+#define XIIC_CR_GENERAL_CALL_MASK 0x40 /* Gen Call enabled = 1 */
+
+/* Status Register masks */
+#define XIIC_SR_GEN_CALL_MASK 0x01 /* 1=a mstr issued a GC */
+#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x02 /* 1=when addr as slave */
+#define XIIC_SR_BUS_BUSY_MASK 0x04 /* 1 = bus is busy */
+#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x08 /* 1=Dir: mstr <-- slave */
+#define XIIC_SR_TX_FIFO_FULL_MASK 0x10 /* 1 = Tx FIFO full */
+#define XIIC_SR_RX_FIFO_FULL_MASK 0x20 /* 1 = Rx FIFO full */
+#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x40 /* 1 = Rx FIFO empty */
+#define XIIC_SR_TX_FIFO_EMPTY_MASK 0x80 /* 1 = Tx FIFO empty */
+
+/* Interrupt Status Register masks Interrupt occurs when... */
+#define XIIC_INTR_ARB_LOST_MASK 0x01 /* 1 = arbitration lost */
+#define XIIC_INTR_TX_ERROR_MASK 0x02 /* 1=Tx error/msg complete */
+#define XIIC_INTR_TX_EMPTY_MASK 0x04 /* 1 = Tx FIFO/reg empty */
+#define XIIC_INTR_RX_FULL_MASK 0x08 /* 1=Rx FIFO/reg=OCY level */
+#define XIIC_INTR_BNB_MASK 0x10 /* 1 = Bus not busy */
+#define XIIC_INTR_AAS_MASK 0x20 /* 1 = when addr as slave */
+#define XIIC_INTR_NAAS_MASK 0x40 /* 1 = not addr as slave */
+#define XIIC_INTR_TX_HALF_MASK 0x80 /* 1 = TX FIFO half empty */
+
+/* The following constants specify the depth of the FIFOs */
+#define IIC_RX_FIFO_DEPTH 16 /* Rx fifo capacity */
+#define IIC_TX_FIFO_DEPTH 16 /* Tx fifo capacity */
+
+/* The following constants specify groups of interrupts that are typically
+ * enabled or disables at the same time
+ */
+#define XIIC_TX_INTERRUPTS \
+(XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)
+
+#define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS)
+
+/*
+ * Tx Fifo upper bit masks.
+ */
+#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
+#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
+
+/*
+ * The following constants define the register offsets for the Interrupt
+ * registers. There are some holes in the memory map for reserved addresses
+ * to allow other registers to be added and still match the memory map of the
+ * interrupt controller registers
+ */
+#define XIIC_DGIER_OFFSET 0x1C /* Device Global Interrupt Enable Register */
+#define XIIC_IISR_OFFSET 0x20 /* Interrupt Status Register */
+#define XIIC_IIER_OFFSET 0x28 /* Interrupt Enable Register */
+#define XIIC_RESETR_OFFSET 0x40 /* Reset Register */
+
+#define XIIC_RESET_MASK 0xAUL
+
+#define XIIC_PM_TIMEOUT 1000 /* ms */
+/*
+ * The following constant is used for the device global interrupt enable
+ * register, to enable all interrupts for the device, this is the only bit
+ * in the register
+ */
+#define XIIC_GINTR_ENABLE_MASK 0x80000000UL
+
+#define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
+#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
+
+static void xiic_start_xfer(struct xiic_i2c *i2c);
+static void __xiic_start_xfer(struct xiic_i2c *i2c);
+
+/*
+ * For the register read and write functions, a little-endian and big-endian
+ * version are necessary. Endianness is detected during the probe function.
+ * Only the least significant byte [doublet] of the register are ever
+ * accessed. This requires an offset of 3 [2] from the base address for
+ * big-endian systems.
+ */
+
+static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
+{
+ if (i2c->endianness == LITTLE)
+ iowrite8(value, i2c->base + reg);
+ else
+ iowrite8(value, i2c->base + reg + 3);
+}
+
+static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
+{
+ u8 ret;
+
+ if (i2c->endianness == LITTLE)
+ ret = ioread8(i2c->base + reg);
+ else
+ ret = ioread8(i2c->base + reg + 3);
+ return ret;
+}
+
+static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
+{
+ if (i2c->endianness == LITTLE)
+ iowrite16(value, i2c->base + reg);
+ else
+ iowrite16be(value, i2c->base + reg + 2);
+}
+
+static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
+{
+ if (i2c->endianness == LITTLE)
+ iowrite32(value, i2c->base + reg);
+ else
+ iowrite32be(value, i2c->base + reg);
+}
+
+static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
+{
+ u32 ret;
+
+ if (i2c->endianness == LITTLE)
+ ret = ioread32(i2c->base + reg);
+ else
+ ret = ioread32be(i2c->base + reg);
+ return ret;
+}
+
+static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask);
+}
+
+static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask);
+}
+
+static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask)
+{
+ u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask);
+}
+
+static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
+{
+ xiic_irq_clr(i2c, mask);
+ xiic_irq_en(i2c, mask);
+}
+
+static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
+{
+ u8 sr;
+ for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+ !(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
+ sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
+ xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+}
+
+static void xiic_reinit(struct xiic_i2c *i2c)
+{
+ xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+ /* Set receive Fifo depth to maximum (zero based). */
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1);
+
+ /* Reset Tx Fifo. */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK);
+
+ /* Enable IIC Device, remove Tx Fifo reset & disable general call. */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
+
+ /* make sure RX fifo is empty */
+ xiic_clear_rx_fifo(i2c);
+
+ /* Enable interrupts */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
+}
+
+static void xiic_deinit(struct xiic_i2c *i2c)
+{
+ u8 cr;
+
+ xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+ /* Disable IIC Device. */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
+}
+
+static void xiic_read_rx(struct xiic_i2c *i2c)
+{
+ u8 bytes_in_fifo;
+ int i;
+
+ bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s entry, bytes in fifo: %d, msg: %d, SR: 0x%x, CR: 0x%x\n",
+ __func__, bytes_in_fifo, xiic_rx_space(i2c),
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+ if (bytes_in_fifo > xiic_rx_space(i2c))
+ bytes_in_fifo = xiic_rx_space(i2c);
+
+ for (i = 0; i < bytes_in_fifo; i++)
+ i2c->rx_msg->buf[i2c->rx_pos++] =
+ xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET,
+ (xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ?
+ IIC_RX_FIFO_DEPTH - 1 : xiic_rx_space(i2c) - 1);
+}
+
+static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
+{
+ /* return the actual space left in the FIFO */
+ return IIC_TX_FIFO_DEPTH - xiic_getreg8(i2c, XIIC_TFO_REG_OFFSET) - 1;
+}
+
+static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
+{
+ u8 fifo_space = xiic_tx_fifo_space(i2c);
+ int len = xiic_tx_space(i2c);
+
+ len = (len > fifo_space) ? fifo_space : len;
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n",
+ __func__, len, fifo_space);
+
+ while (len--) {
+ u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
+ if ((xiic_tx_space(i2c) == 0) && (i2c->nmsgs == 1)) {
+ /* last message in transfer -> STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+ dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
+ }
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+}
+
+static void xiic_wakeup(struct xiic_i2c *i2c, int code)
+{
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ i2c->state = code;
+ wake_up(&i2c->wait);
+}
+
+static irqreturn_t xiic_process(int irq, void *dev_id)
+{
+ struct xiic_i2c *i2c = dev_id;
+ u32 pend, isr, ier;
+ u32 clr = 0;
+
+ /* Get the interrupt Status from the IPIF. There is no clearing of
+ * interrupts in the IPIF. Interrupts must be cleared at the source.
+ * To find which interrupts are pending; AND interrupts pending with
+ * interrupts masked.
+ */
+ mutex_lock(&i2c->lock);
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ pend = isr & ier;
+
+ dev_dbg(i2c->adap.dev.parent, "%s: IER: 0x%x, ISR: 0x%x, pend: 0x%x\n",
+ __func__, ier, isr, pend);
+ dev_dbg(i2c->adap.dev.parent, "%s: SR: 0x%x, msg: %p, nmsgs: %d\n",
+ __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ i2c->tx_msg, i2c->nmsgs);
+
+
+ /* Service requesting interrupt */
+ if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
+ ((pend & XIIC_INTR_TX_ERROR_MASK) &&
+ !(pend & XIIC_INTR_RX_FULL_MASK))) {
+ /* bus arbritration lost, or...
+ * Transmit error _OR_ RX completed
+ * if this happens when RX_FULL is not set
+ * this is probably a TX error
+ */
+
+ dev_dbg(i2c->adap.dev.parent, "%s error\n", __func__);
+
+ /* dynamic mode seem to suffer from problems if we just flushes
+ * fifos and the next message is a TX with len 0 (only addr)
+ * reset the IP instead of just flush fifos
+ */
+ xiic_reinit(i2c);
+
+ if (i2c->rx_msg)
+ xiic_wakeup(i2c, STATE_ERROR);
+ if (i2c->tx_msg)
+ xiic_wakeup(i2c, STATE_ERROR);
+ }
+ if (pend & XIIC_INTR_RX_FULL_MASK) {
+ /* Receive register/FIFO is full */
+
+ clr |= XIIC_INTR_RX_FULL_MASK;
+ if (!i2c->rx_msg) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s unexpected RX IRQ\n", __func__);
+ xiic_clear_rx_fifo(i2c);
+ goto out;
+ }
+
+ xiic_read_rx(i2c);
+ if (xiic_rx_space(i2c) == 0) {
+ /* this is the last part of the message */
+ i2c->rx_msg = NULL;
+
+ /* also clear TX error if there (RX complete) */
+ clr |= (isr & XIIC_INTR_TX_ERROR_MASK);
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s end of message, nmsgs: %d\n",
+ __func__, i2c->nmsgs);
+
+ /* send next message if this wasn't the last,
+ * otherwise the transfer will be finialise when
+ * receiving the bus not busy interrupt
+ */
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ dev_dbg(i2c->adap.dev.parent,
+ "%s will start next...\n", __func__);
+
+ __xiic_start_xfer(i2c);
+ }
+ }
+ }
+ if (pend & XIIC_INTR_BNB_MASK) {
+ /* IIC bus has transitioned to not busy */
+ clr |= XIIC_INTR_BNB_MASK;
+
+ /* The bus is not busy, disable BusNotBusy interrupt */
+ xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+
+ if (!i2c->tx_msg)
+ goto out;
+
+ if ((i2c->nmsgs == 1) && !i2c->rx_msg &&
+ xiic_tx_space(i2c) == 0)
+ xiic_wakeup(i2c, STATE_DONE);
+ else
+ xiic_wakeup(i2c, STATE_ERROR);
+ }
+ if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
+ /* Transmit register/FIFO is empty or ½ empty */
+
+ clr |= (pend &
+ (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK));
+
+ if (!i2c->tx_msg) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s unexpected TX IRQ\n", __func__);
+ goto out;
+ }
+
+ xiic_fill_tx_fifo(i2c);
+
+ /* current message sent and there is space in the fifo */
+ if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
+ dev_dbg(i2c->adap.dev.parent,
+ "%s end of message sent, nmsgs: %d\n",
+ __func__, i2c->nmsgs);
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ __xiic_start_xfer(i2c);
+ } else {
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s Got TX IRQ but no more to do...\n",
+ __func__);
+ }
+ } else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
+ /* current frame is sent and is last,
+ * make sure to disable tx half
+ */
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+ }
+out:
+ dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
+
+ xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
+ mutex_unlock(&i2c->lock);
+ return IRQ_HANDLED;
+}
+
+static int xiic_bus_busy(struct xiic_i2c *i2c)
+{
+ u8 sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+
+ return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0;
+}
+
+static int xiic_busy(struct xiic_i2c *i2c)
+{
+ int tries = 3;
+ int err;
+
+ if (i2c->tx_msg)
+ return -EBUSY;
+
+ /* for instance if previous transfer was terminated due to TX error
+ * it might be that the bus is on it's way to become available
+ * give it at most 3 ms to wake
+ */
+ err = xiic_bus_busy(i2c);
+ while (err && tries--) {
+ msleep(1);
+ err = xiic_bus_busy(i2c);
+ }
+
+ return err;
+}
+
+static void xiic_start_recv(struct xiic_i2c *i2c)
+{
+ u8 rx_watermark;
+ struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
+ unsigned long flags;
+
+ /* Clear and enable Rx full interrupt. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+
+ /* we want to get all but last byte, because the TX_ERROR IRQ is used
+ * to inidicate error ACK on the address, and negative ack on the last
+ * received byte, so to not mix them receive all but last.
+ * In the case where there is only one byte to receive
+ * we can check if ERROR and RX full is set at the same time
+ */
+ rx_watermark = msg->len;
+ if (rx_watermark > IIC_RX_FIFO_DEPTH)
+ rx_watermark = IIC_RX_FIFO_DEPTH;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
+
+ local_irq_save(flags);
+ if (!(msg->flags & I2C_M_NOSTART))
+ /* write the address */
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+ local_irq_restore(flags);
+
+ if (i2c->nmsgs == 1)
+ /* very last, enable bus not busy as well */
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+ /* the message is tx:ed */
+ i2c->tx_pos = msg->len;
+}
+
+static void xiic_start_send(struct xiic_i2c *i2c)
+{
+ struct i2c_msg *msg = i2c->tx_msg;
+
+ xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK);
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d",
+ __func__, msg, msg->len);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ /* write the address */
+ u16 data = i2c_8bit_addr_from_msg(msg) |
+ XIIC_TX_DYN_START_MASK;
+ if ((i2c->nmsgs == 1) && msg->len == 0)
+ /* no data and last message -> add STOP */
+ data |= XIIC_TX_DYN_STOP_MASK;
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+
+ xiic_fill_tx_fifo(i2c);
+
+ /* Clear any pending Tx empty, Tx Error and then enable them. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK);
+}
+
+static irqreturn_t xiic_isr(int irq, void *dev_id)
+{
+ struct xiic_i2c *i2c = dev_id;
+ u32 pend, isr, ier;
+ irqreturn_t ret = IRQ_NONE;
+ /* Do not processes a devices interrupts if the device has no
+ * interrupts pending
+ */
+
+ dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__);
+
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ pend = isr & ier;
+ if (pend)
+ ret = IRQ_WAKE_THREAD;
+
+ return ret;
+}
+
+static void __xiic_start_xfer(struct xiic_i2c *i2c)
+{
+ int first = 1;
+ int fifo_space = xiic_tx_fifo_space(i2c);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
+ __func__, i2c->tx_msg, fifo_space);
+
+ if (!i2c->tx_msg)
+ return;
+
+ i2c->rx_pos = 0;
+ i2c->tx_pos = 0;
+ i2c->state = STATE_START;
+ while ((fifo_space >= 2) && (first || (i2c->nmsgs > 1))) {
+ if (!first) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ i2c->tx_pos = 0;
+ } else
+ first = 0;
+
+ if (i2c->tx_msg->flags & I2C_M_RD) {
+ /* we dont date putting several reads in the FIFO */
+ xiic_start_recv(i2c);
+ return;
+ } else {
+ xiic_start_send(i2c);
+ if (xiic_tx_space(i2c) != 0) {
+ /* the message could not be completely sent */
+ break;
+ }
+ }
+
+ fifo_space = xiic_tx_fifo_space(i2c);
+ }
+
+ /* there are more messages or the current one could not be completely
+ * put into the FIFO, also enable the half empty interrupt
+ */
+ if (i2c->nmsgs > 1 || xiic_tx_space(i2c))
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_HALF_MASK);
+
+}
+
+static void xiic_start_xfer(struct xiic_i2c *i2c)
+{
+ mutex_lock(&i2c->lock);
+ xiic_reinit(i2c);
+ __xiic_start_xfer(i2c);
+ mutex_unlock(&i2c->lock);
+}
+
+static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct xiic_i2c *i2c = i2c_get_adapdata(adap);
+ int err;
+
+ dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__,
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET));
+
+ err = pm_runtime_get_sync(i2c->dev);
+ if (err < 0)
+ return err;
+
+ err = xiic_busy(i2c);
+ if (err)
+ goto out;
+
+ i2c->tx_msg = msgs;
+ i2c->nmsgs = num;
+
+ xiic_start_xfer(i2c);
+
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+ (i2c->state == STATE_DONE), HZ)) {
+ err = (i2c->state == STATE_DONE) ? num : -EIO;
+ goto out;
+ } else {
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ err = -ETIMEDOUT;
+ goto out;
+ }
+out:
+ pm_runtime_mark_last_busy(i2c->dev);
+ pm_runtime_put_autosuspend(i2c->dev);
+ return err;
+}
+
+static u32 xiic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm xiic_algorithm = {
+ .master_xfer = xiic_xfer,
+ .functionality = xiic_func,
+};
+
+static const struct i2c_adapter_quirks xiic_quirks = {
+ .max_read_len = 255,
+};
+
+static const struct i2c_adapter xiic_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_DEPRECATED,
+ .algo = &xiic_algorithm,
+ .quirks = &xiic_quirks,
+};
+
+
+static int xiic_i2c_probe(struct platform_device *pdev)
+{
+ struct xiic_i2c *i2c;
+ struct xiic_i2c_platform_data *pdata;
+ struct resource *res;
+ int ret, irq;
+ u8 i;
+ u32 sr;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ /* hook up driver to tree */
+ platform_set_drvdata(pdev, i2c);
+ i2c->adap = xiic_adapter;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ DRIVER_NAME " %s", pdev->name);
+
+ mutex_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "input clock not found.\n");
+ return PTR_ERR(i2c->clk);
+ }
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+ return ret;
+ }
+ i2c->dev = &pdev->dev;
+ pm_runtime_enable(i2c->dev);
+ pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(i2c->dev);
+ pm_runtime_set_active(i2c->dev);
+ ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
+ xiic_process, IRQF_ONESHOT,
+ pdev->name, i2c);
+
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto err_clk_dis;
+ }
+
+ /*
+ * Detect endianness
+ * Try to reset the TX FIFO. Then check the EMPTY flag. If it is not
+ * set, assume that the endianness was wrong and swap.
+ */
+ i2c->endianness = LITTLE;
+ xiic_setreg32(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK);
+ /* Reset is cleared in xiic_reinit */
+ sr = xiic_getreg32(i2c, XIIC_SR_REG_OFFSET);
+ if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
+ i2c->endianness = BIG;
+
+ xiic_reinit(i2c);
+
+ /* add i2c adapter to i2c tree */
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret) {
+ xiic_deinit(i2c);
+ goto err_clk_dis;
+ }
+
+ if (pdata) {
+ /* add in known devices to the bus */
+ for (i = 0; i < pdata->num_devices; i++)
+ i2c_new_device(&i2c->adap, pdata->devices + i);
+ }
+
+ return 0;
+
+err_clk_dis:
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int xiic_i2c_remove(struct platform_device *pdev)
+{
+ struct xiic_i2c *i2c = platform_get_drvdata(pdev);
+ int ret;
+
+ /* remove adapter & data */
+ i2c_del_adapter(&i2c->adap);
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+ return ret;
+ }
+ xiic_deinit(i2c);
+ clk_disable_unprepare(i2c->clk);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id xiic_of_match[] = {
+ { .compatible = "xlnx,xps-iic-2.00.a", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xiic_of_match);
+#endif
+
+static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev)
+{
+ struct xiic_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_disable(i2c->clk);
+
+ return 0;
+}
+
+static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev)
+{
+ struct xiic_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(i2c->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops xiic_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend,
+ xiic_i2c_runtime_resume, NULL)
+};
+static struct platform_driver xiic_i2c_driver = {
+ .probe = xiic_i2c_probe,
+ .remove = xiic_i2c_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(xiic_of_match),
+ .pm = &xiic_dev_pm_ops,
+ },
+};
+
+module_platform_driver(xiic_i2c_driver);
+
+MODULE_AUTHOR("info@mocean-labs.com");
+MODULE_DESCRIPTION("Xilinx I2C bus driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
new file mode 100644
index 000000000..8a873975c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2003-2015 Broadcom Corporation
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#define XLP9XX_I2C_DIV 0x0
+#define XLP9XX_I2C_CTRL 0x1
+#define XLP9XX_I2C_CMD 0x2
+#define XLP9XX_I2C_STATUS 0x3
+#define XLP9XX_I2C_MTXFIFO 0x4
+#define XLP9XX_I2C_MRXFIFO 0x5
+#define XLP9XX_I2C_MFIFOCTRL 0x6
+#define XLP9XX_I2C_STXFIFO 0x7
+#define XLP9XX_I2C_SRXFIFO 0x8
+#define XLP9XX_I2C_SFIFOCTRL 0x9
+#define XLP9XX_I2C_SLAVEADDR 0xA
+#define XLP9XX_I2C_OWNADDR 0xB
+#define XLP9XX_I2C_FIFOWCNT 0xC
+#define XLP9XX_I2C_INTEN 0xD
+#define XLP9XX_I2C_INTST 0xE
+#define XLP9XX_I2C_WAITCNT 0xF
+#define XLP9XX_I2C_TIMEOUT 0X10
+#define XLP9XX_I2C_GENCALLADDR 0x11
+
+#define XLP9XX_I2C_STATUS_BUSY BIT(0)
+
+#define XLP9XX_I2C_CMD_START BIT(7)
+#define XLP9XX_I2C_CMD_STOP BIT(6)
+#define XLP9XX_I2C_CMD_READ BIT(5)
+#define XLP9XX_I2C_CMD_WRITE BIT(4)
+#define XLP9XX_I2C_CMD_ACK BIT(3)
+
+#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16
+#define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000
+#define XLP9XX_I2C_CTRL_RST BIT(8)
+#define XLP9XX_I2C_CTRL_EN BIT(6)
+#define XLP9XX_I2C_CTRL_MASTER BIT(4)
+#define XLP9XX_I2C_CTRL_FIFORD BIT(1)
+#define XLP9XX_I2C_CTRL_ADDMODE BIT(0)
+
+#define XLP9XX_I2C_INTEN_NACKADDR BIT(25)
+#define XLP9XX_I2C_INTEN_SADDR BIT(13)
+#define XLP9XX_I2C_INTEN_DATADONE BIT(12)
+#define XLP9XX_I2C_INTEN_ARLOST BIT(11)
+#define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4)
+#define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3)
+#define XLP9XX_I2C_INTEN_MFIFOHI BIT(2)
+#define XLP9XX_I2C_INTEN_BUSERR BIT(0)
+
+#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8
+#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0
+#define XLP9XX_I2C_MFIFOCTRL_RST BIT(16)
+
+#define XLP9XX_I2C_SLAVEADDR_RW BIT(0)
+#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1
+
+#define XLP9XX_I2C_IP_CLK_FREQ 133000000UL
+#define XLP9XX_I2C_DEFAULT_FREQ 100000
+#define XLP9XX_I2C_HIGH_FREQ 400000
+#define XLP9XX_I2C_FIFO_SIZE 0x80U
+#define XLP9XX_I2C_TIMEOUT_MS 1000
+#define XLP9XX_I2C_BUSY_TIMEOUT 50
+
+#define XLP9XX_I2C_FIFO_WCNT_MASK 0xff
+#define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \
+ XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR)
+
+struct xlp9xx_i2c_dev {
+ struct device *dev;
+ struct i2c_adapter adapter;
+ struct completion msg_complete;
+ struct i2c_smbus_alert_setup alert_data;
+ struct i2c_client *ara;
+ int irq;
+ bool msg_read;
+ bool len_recv;
+ bool client_pec;
+ u32 __iomem *base;
+ u32 msg_buf_remaining;
+ u32 msg_len;
+ u32 ip_clk_hz;
+ u32 clk_hz;
+ u32 msg_err;
+ u8 *msg_buf;
+};
+
+static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv,
+ unsigned long reg, u32 val)
+{
+ writel(val, priv->base + reg);
+}
+
+static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv,
+ unsigned long reg)
+{
+ return readl(priv->base + reg);
+}
+
+static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
+{
+ u32 inten;
+
+ inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask;
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
+}
+
+static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
+{
+ u32 inten;
+
+ inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask;
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
+}
+
+static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv)
+{
+ u32 thres;
+
+ if (priv->len_recv)
+ /* interrupt after the first read to examine
+ * the length byte before proceeding further
+ */
+ thres = 1;
+ else if (priv->msg_buf_remaining > XLP9XX_I2C_FIFO_SIZE)
+ thres = XLP9XX_I2C_FIFO_SIZE;
+ else
+ thres = priv->msg_buf_remaining;
+
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
+ thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT);
+}
+
+static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
+{
+ u32 len, i;
+ u8 *buf = priv->msg_buf;
+
+ len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
+ for (i = 0; i < len; i++)
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]);
+ priv->msg_buf_remaining -= len;
+ priv->msg_buf += len;
+}
+
+static void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv)
+{
+ u32 val, len;
+
+ /*
+ * Update receive length. Re-read len to get the latest value,
+ * and then add 4 to have a minimum value that can be safely
+ * written. This is to account for the byte read above, the
+ * transfer in progress and any delays in the register I/O
+ */
+ val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
+ len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
+ XLP9XX_I2C_FIFO_WCNT_MASK;
+ len = max_t(u32, priv->msg_len, len + 4);
+ if (len >= I2C_SMBUS_BLOCK_MAX + 2)
+ return;
+ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
+ (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
+}
+
+static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
+{
+ u32 len, i;
+ u8 rlen, *buf = priv->msg_buf;
+
+ len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
+ XLP9XX_I2C_FIFO_WCNT_MASK;
+ if (!len)
+ return;
+ if (priv->len_recv) {
+ /* read length byte */
+ rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
+
+ /*
+ * We expect at least 2 interrupts for I2C_M_RECV_LEN
+ * transactions. The length is updated during the first
+ * interrupt, and the buffer contents are only copied
+ * during subsequent interrupts. If in case the interrupts
+ * get merged we would complete the transaction without
+ * copying out the bytes from RX fifo. To avoid this now we
+ * drain the fifo as and when data is available.
+ * We drained the rlen byte already, decrement total length
+ * by one.
+ */
+
+ len--;
+ if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) {
+ rlen = 0; /*abort transfer */
+ priv->msg_buf_remaining = 0;
+ priv->msg_len = 0;
+ xlp9xx_i2c_update_rlen(priv);
+ return;
+ }
+
+ *buf++ = rlen;
+ if (priv->client_pec)
+ ++rlen; /* account for error check byte */
+ /* update remaining bytes and message length */
+ priv->msg_buf_remaining = rlen;
+ priv->msg_len = rlen + 1;
+ xlp9xx_i2c_update_rlen(priv);
+ priv->len_recv = false;
+ }
+
+ len = min(priv->msg_buf_remaining, len);
+ for (i = 0; i < len; i++, buf++)
+ *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
+
+ priv->msg_buf_remaining -= len;
+ priv->msg_buf = buf;
+
+ if (priv->msg_buf_remaining)
+ xlp9xx_i2c_update_rx_fifo_thres(priv);
+}
+
+static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id)
+{
+ struct xlp9xx_i2c_dev *priv = dev_id;
+ u32 status;
+
+ status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST);
+ if (status == 0)
+ return IRQ_NONE;
+
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status);
+ if (status & XLP9XX_I2C_STATUS_ERRMASK) {
+ priv->msg_err = status;
+ goto xfer_done;
+ }
+
+ /* SADDR ACK for SMBUS_QUICK */
+ if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0))
+ goto xfer_done;
+
+ if (!priv->msg_read) {
+ if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) {
+ /* TX FIFO got empty, fill it up again */
+ if (priv->msg_buf_remaining)
+ xlp9xx_i2c_fill_tx_fifo(priv);
+ else
+ xlp9xx_i2c_mask_irq(priv,
+ XLP9XX_I2C_INTEN_MFIFOEMTY);
+ }
+ } else {
+ if (status & (XLP9XX_I2C_INTEN_DATADONE |
+ XLP9XX_I2C_INTEN_MFIFOHI)) {
+ /* data is in FIFO, read it */
+ if (priv->msg_buf_remaining)
+ xlp9xx_i2c_drain_rx_fifo(priv);
+ }
+ }
+
+ /* Transfer complete */
+ if (status & XLP9XX_I2C_INTEN_DATADONE)
+ goto xfer_done;
+
+ return IRQ_HANDLED;
+
+xfer_done:
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+ complete(&priv->msg_complete);
+ return IRQ_HANDLED;
+}
+
+static int xlp9xx_i2c_check_bus_status(struct xlp9xx_i2c_dev *priv)
+{
+ u32 status;
+ u32 busy_timeout = XLP9XX_I2C_BUSY_TIMEOUT;
+
+ while (busy_timeout) {
+ status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_STATUS);
+ if ((status & XLP9XX_I2C_STATUS_BUSY) == 0)
+ break;
+
+ busy_timeout--;
+ usleep_range(1000, 1100);
+ }
+
+ if (!busy_timeout)
+ return -EIO;
+
+ return 0;
+}
+
+static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv)
+{
+ u32 prescale;
+
+ /*
+ * The controller uses 5 * SCL clock internally.
+ * So prescale value should be divided by 5.
+ */
+ prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz);
+ prescale = ((prescale - 8) / 5) - 1;
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN |
+ XLP9XX_I2C_CTRL_MASTER);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+
+ return 0;
+}
+
+static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
+ int last_msg)
+{
+ unsigned long timeleft;
+ u32 intr_mask, cmd, val, len;
+
+ priv->msg_buf = msg->buf;
+ priv->msg_buf_remaining = priv->msg_len = msg->len;
+ priv->msg_err = 0;
+ priv->msg_read = (msg->flags & I2C_M_RD);
+ reinit_completion(&priv->msg_complete);
+
+ /* Reset FIFO */
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
+ XLP9XX_I2C_MFIFOCTRL_RST);
+
+ /* set slave addr */
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR,
+ (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) |
+ (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0));
+
+ /* Build control word for transfer */
+ val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
+ if (!priv->msg_read)
+ val &= ~XLP9XX_I2C_CTRL_FIFORD;
+ else
+ val |= XLP9XX_I2C_CTRL_FIFORD; /* read */
+
+ if (msg->flags & I2C_M_TEN)
+ val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/
+ else
+ val &= ~XLP9XX_I2C_CTRL_ADDMODE;
+
+ priv->len_recv = msg->flags & I2C_M_RECV_LEN;
+ len = priv->len_recv ? I2C_SMBUS_BLOCK_MAX + 2 : msg->len;
+ priv->client_pec = msg->flags & I2C_CLIENT_PEC;
+
+ /* set FIFO threshold if reading */
+ if (priv->msg_read)
+ xlp9xx_i2c_update_rx_fifo_thres(priv);
+
+ /* set data length to be transferred */
+ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
+ (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
+
+ /* fill fifo during tx */
+ if (!priv->msg_read)
+ xlp9xx_i2c_fill_tx_fifo(priv);
+
+ /* set interrupt mask */
+ intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR |
+ XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE);
+
+ if (priv->msg_read) {
+ intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI;
+ if (msg->len == 0)
+ intr_mask |= XLP9XX_I2C_INTEN_SADDR;
+ } else {
+ if (msg->len == 0)
+ intr_mask |= XLP9XX_I2C_INTEN_SADDR;
+ else
+ intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY;
+ }
+ xlp9xx_i2c_unmask_irq(priv, intr_mask);
+
+ /* set cmd reg */
+ cmd = XLP9XX_I2C_CMD_START;
+ if (msg->len)
+ cmd |= (priv->msg_read ?
+ XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE);
+ if (last_msg)
+ cmd |= XLP9XX_I2C_CMD_STOP;
+
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd);
+
+ timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS);
+ timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft);
+
+ if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) {
+ dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, XLP9XX_I2C_CMD_STOP);
+ return -EIO;
+ } else if (priv->msg_err & XLP9XX_I2C_INTEN_NACKADDR) {
+ return -ENXIO;
+ }
+
+ if (timeleft == 0) {
+ dev_dbg(priv->dev, "i2c transfer timed out!\n");
+ xlp9xx_i2c_init(priv);
+ return -ETIMEDOUT;
+ }
+
+ /* update msg->len with actual received length */
+ if (msg->flags & I2C_M_RECV_LEN) {
+ if (!priv->msg_len)
+ return -EPROTO;
+ msg->len = priv->msg_len;
+ }
+ return 0;
+}
+
+static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int i, ret;
+ struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap);
+
+ ret = xlp9xx_i2c_check_bus_status(priv);
+ if (ret) {
+ xlp9xx_i2c_init(priv);
+ ret = xlp9xx_i2c_check_bus_status(priv);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
+ if (ret != 0)
+ return ret;
+ }
+
+ return num;
+}
+
+static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm xlp9xx_i2c_algo = {
+ .master_xfer = xlp9xx_i2c_xfer,
+ .functionality = xlp9xx_i2c_functionality,
+};
+
+static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
+ struct xlp9xx_i2c_dev *priv)
+{
+ struct clk *clk;
+ u32 freq;
+ int err;
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ;
+ dev_dbg(&pdev->dev, "using default input frequency %u\n",
+ priv->ip_clk_hz);
+ } else {
+ priv->ip_clk_hz = clk_get_rate(clk);
+ }
+
+ err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq);
+ if (err) {
+ freq = XLP9XX_I2C_DEFAULT_FREQ;
+ dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
+ } else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) {
+ dev_warn(&pdev->dev, "invalid frequency %u, using default\n",
+ freq);
+ freq = XLP9XX_I2C_DEFAULT_FREQ;
+ }
+ priv->clk_hz = freq;
+
+ return 0;
+}
+
+static int xlp9xx_i2c_smbus_setup(struct xlp9xx_i2c_dev *priv,
+ struct platform_device *pdev)
+{
+ if (!priv->alert_data.irq)
+ return -EINVAL;
+
+ priv->ara = i2c_setup_smbus_alert(&priv->adapter, &priv->alert_data);
+ if (!priv->ara)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int xlp9xx_i2c_probe(struct platform_device *pdev)
+{
+ struct xlp9xx_i2c_dev *priv;
+ struct resource *res;
+ int err = 0;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0) {
+ dev_err(&pdev->dev, "invalid irq!\n");
+ return priv->irq;
+ }
+ /* SMBAlert irq */
+ priv->alert_data.irq = platform_get_irq(pdev, 1);
+ if (priv->alert_data.irq <= 0)
+ priv->alert_data.irq = 0;
+
+ xlp9xx_i2c_get_frequency(pdev, priv);
+ xlp9xx_i2c_init(priv);
+
+ err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0,
+ pdev->name, priv);
+ if (err) {
+ dev_err(&pdev->dev, "IRQ request failed!\n");
+ return err;
+ }
+
+ init_completion(&priv->msg_complete);
+ priv->adapter.dev.parent = &pdev->dev;
+ priv->adapter.algo = &xlp9xx_i2c_algo;
+ priv->adapter.class = I2C_CLASS_HWMON;
+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
+ priv->adapter.dev.of_node = pdev->dev.of_node;
+ priv->dev = &pdev->dev;
+
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c");
+ i2c_set_adapdata(&priv->adapter, priv);
+
+ err = i2c_add_adapter(&priv->adapter);
+ if (err)
+ return err;
+
+ err = xlp9xx_i2c_smbus_setup(priv, pdev);
+ if (err)
+ dev_dbg(&pdev->dev, "No active SMBus alert %d\n", err);
+
+ platform_set_drvdata(pdev, priv);
+ dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
+
+ return 0;
+}
+
+static int xlp9xx_i2c_remove(struct platform_device *pdev)
+{
+ struct xlp9xx_i2c_dev *priv;
+
+ priv = platform_get_drvdata(pdev);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+ synchronize_irq(priv->irq);
+ i2c_del_adapter(&priv->adapter);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0);
+
+ return 0;
+}
+
+static const struct of_device_id xlp9xx_i2c_of_match[] = {
+ { .compatible = "netlogic,xlp980-i2c", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = {
+ {"BRCM9007", 0},
+ {"CAV9007", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids);
+#endif
+
+static struct platform_driver xlp9xx_i2c_driver = {
+ .probe = xlp9xx_i2c_probe,
+ .remove = xlp9xx_i2c_remove,
+ .driver = {
+ .name = "xlp9xx-i2c",
+ .of_match_table = xlp9xx_i2c_of_match,
+ .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids),
+ },
+};
+
+module_platform_driver(xlp9xx_i2c_driver);
+
+MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>");
+MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
new file mode 100644
index 000000000..dda6cb848
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2011, Netlogic Microsystems Inc.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+
+/* XLR I2C REGISTERS */
+#define XLR_I2C_CFG 0x00
+#define XLR_I2C_CLKDIV 0x01
+#define XLR_I2C_DEVADDR 0x02
+#define XLR_I2C_ADDR 0x03
+#define XLR_I2C_DATAOUT 0x04
+#define XLR_I2C_DATAIN 0x05
+#define XLR_I2C_STATUS 0x06
+#define XLR_I2C_STARTXFR 0x07
+#define XLR_I2C_BYTECNT 0x08
+#define XLR_I2C_HDSTATIM 0x09
+
+/* Sigma Designs additional registers */
+#define XLR_I2C_INT_EN 0x09
+#define XLR_I2C_INT_STAT 0x0a
+
+/* XLR I2C REGISTERS FLAGS */
+#define XLR_I2C_BUS_BUSY 0x01
+#define XLR_I2C_SDOEMPTY 0x02
+#define XLR_I2C_RXRDY 0x04
+#define XLR_I2C_ACK_ERR 0x08
+#define XLR_I2C_ARB_STARTERR 0x30
+
+/* Register Values */
+#define XLR_I2C_CFG_ADDR 0xF8
+#define XLR_I2C_CFG_NOADDR 0xFA
+#define XLR_I2C_STARTXFR_ND 0x02 /* No Data */
+#define XLR_I2C_STARTXFR_RD 0x01 /* Read */
+#define XLR_I2C_STARTXFR_WR 0x00 /* Write */
+
+#define XLR_I2C_TIMEOUT 10 /* timeout per byte in msec */
+
+/*
+ * On XLR/XLS, we need to use __raw_ IO to read the I2C registers
+ * because they are in the big-endian MMIO area on the SoC.
+ *
+ * The readl/writel implementation on XLR/XLS byteswaps, because
+ * those are for its little-endian PCI space (see arch/mips/Kconfig).
+ */
+static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val)
+{
+ __raw_writel(val, base + reg);
+}
+
+static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg)
+{
+ return __raw_readl(base + reg);
+}
+
+#define XLR_I2C_FLAG_IRQ 1
+
+struct xlr_i2c_config {
+ u32 flags; /* optional feature support */
+ u32 status_busy; /* value of STATUS[0] when busy */
+ u32 cfg_extra; /* extra CFG bits to set */
+};
+
+struct xlr_i2c_private {
+ struct i2c_adapter adap;
+ u32 __iomem *iobase;
+ int irq;
+ int pos;
+ struct i2c_msg *msg;
+ const struct xlr_i2c_config *cfg;
+ wait_queue_head_t wait;
+ struct clk *clk;
+};
+
+static int xlr_i2c_busy(struct xlr_i2c_private *priv, u32 status)
+{
+ return (status & XLR_I2C_BUS_BUSY) == priv->cfg->status_busy;
+}
+
+static int xlr_i2c_idle(struct xlr_i2c_private *priv)
+{
+ return !xlr_i2c_busy(priv, xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS));
+}
+
+static int xlr_i2c_wait(struct xlr_i2c_private *priv, unsigned long timeout)
+{
+ int status;
+ int t;
+
+ t = wait_event_timeout(priv->wait, xlr_i2c_idle(priv),
+ msecs_to_jiffies(timeout));
+ if (!t)
+ return -ETIMEDOUT;
+
+ status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+ return status & XLR_I2C_ACK_ERR ? -EIO : 0;
+}
+
+static void xlr_i2c_tx_irq(struct xlr_i2c_private *priv, u32 status)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ if (status & XLR_I2C_SDOEMPTY)
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT,
+ msg->buf[priv->pos++]);
+}
+
+static void xlr_i2c_rx_irq(struct xlr_i2c_private *priv, u32 status)
+{
+ struct i2c_msg *msg = priv->msg;
+
+ if (status & XLR_I2C_RXRDY)
+ msg->buf[priv->pos++] =
+ xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
+}
+
+static irqreturn_t xlr_i2c_irq(int irq, void *dev_id)
+{
+ struct xlr_i2c_private *priv = dev_id;
+ struct i2c_msg *msg = priv->msg;
+ u32 int_stat, status;
+
+ int_stat = xlr_i2c_rdreg(priv->iobase, XLR_I2C_INT_STAT);
+ if (!int_stat)
+ return IRQ_NONE;
+
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, int_stat);
+
+ if (!msg)
+ return IRQ_HANDLED;
+
+ status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+ if (priv->pos < msg->len) {
+ if (msg->flags & I2C_M_RD)
+ xlr_i2c_rx_irq(priv, status);
+ else
+ xlr_i2c_tx_irq(priv, status);
+ }
+
+ if (!xlr_i2c_busy(priv, status))
+ wake_up(&priv->wait);
+
+ return IRQ_HANDLED;
+}
+
+static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
+ u8 *buf, u16 addr)
+{
+ struct i2c_adapter *adap = &priv->adap;
+ unsigned long timeout, stoptime, checktime;
+ u32 i2c_status;
+ int pos, timedout;
+ u8 offset;
+ u32 xfer;
+
+ offset = buf[0];
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
+ XLR_I2C_CFG_ADDR | priv->cfg->cfg_extra);
+
+ timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+ stoptime = jiffies + timeout;
+ timedout = 0;
+
+ if (len == 1) {
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+ xfer = XLR_I2C_STARTXFR_ND;
+ pos = 1;
+ } else {
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 2);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[1]);
+ xfer = XLR_I2C_STARTXFR_WR;
+ pos = 2;
+ }
+
+ priv->pos = pos;
+
+retry:
+ /* retry can only happen on the first byte */
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, xfer);
+
+ if (priv->irq > 0)
+ return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len);
+
+ while (!timedout) {
+ checktime = jiffies;
+ i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+ if ((i2c_status & XLR_I2C_SDOEMPTY) && pos < len) {
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos++]);
+
+ /* reset timeout on successful xmit */
+ stoptime = jiffies + timeout;
+ }
+ timedout = time_after(checktime, stoptime);
+
+ if (i2c_status & XLR_I2C_ARB_STARTERR) {
+ if (timedout)
+ break;
+ goto retry;
+ }
+
+ if (i2c_status & XLR_I2C_ACK_ERR)
+ return -EIO;
+
+ if (!xlr_i2c_busy(priv, i2c_status) && pos >= len)
+ return 0;
+ }
+ dev_err(&adap->dev, "I2C transmit timeout\n");
+ return -ETIMEDOUT;
+}
+
+static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
+{
+ struct i2c_adapter *adap = &priv->adap;
+ u32 i2c_status;
+ unsigned long timeout, stoptime, checktime;
+ int nbytes, timedout;
+
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
+ XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+
+ priv->pos = 0;
+
+ timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+ stoptime = jiffies + timeout;
+ timedout = 0;
+ nbytes = 0;
+retry:
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
+
+ if (priv->irq > 0)
+ return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len);
+
+ while (!timedout) {
+ checktime = jiffies;
+ i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+ if (i2c_status & XLR_I2C_RXRDY) {
+ if (nbytes >= len)
+ return -EIO; /* should not happen */
+
+ buf[nbytes++] =
+ xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
+
+ /* reset timeout on successful read */
+ stoptime = jiffies + timeout;
+ }
+
+ timedout = time_after(checktime, stoptime);
+ if (i2c_status & XLR_I2C_ARB_STARTERR) {
+ if (timedout)
+ break;
+ goto retry;
+ }
+
+ if (i2c_status & XLR_I2C_ACK_ERR)
+ return -EIO;
+
+ if (!xlr_i2c_busy(priv, i2c_status))
+ return 0;
+ }
+
+ dev_err(&adap->dev, "I2C receive timeout\n");
+ return -ETIMEDOUT;
+}
+
+static int xlr_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *msg;
+ int i;
+ int ret = 0;
+ struct xlr_i2c_private *priv = i2c_get_adapdata(adap);
+
+ ret = clk_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ if (priv->irq)
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0xf);
+
+
+ for (i = 0; ret == 0 && i < num; i++) {
+ msg = &msgs[i];
+ priv->msg = msg;
+ if (msg->flags & I2C_M_RD)
+ ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0],
+ msg->addr);
+ else
+ ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0],
+ msg->addr);
+ }
+
+ if (priv->irq)
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0);
+
+ clk_disable(priv->clk);
+ priv->msg = NULL;
+
+ return (ret != 0) ? ret : num;
+}
+
+static u32 xlr_func(struct i2c_adapter *adap)
+{
+ /* Emulate SMBUS over I2C */
+ return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm xlr_i2c_algo = {
+ .master_xfer = xlr_i2c_xfer,
+ .functionality = xlr_func,
+};
+
+static const struct i2c_adapter_quirks xlr_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static const struct xlr_i2c_config xlr_i2c_config_default = {
+ .status_busy = XLR_I2C_BUS_BUSY,
+ .cfg_extra = 0,
+};
+
+static const struct xlr_i2c_config xlr_i2c_config_tangox = {
+ .flags = XLR_I2C_FLAG_IRQ,
+ .status_busy = 0,
+ .cfg_extra = 1 << 8,
+};
+
+static const struct of_device_id xlr_i2c_dt_ids[] = {
+ {
+ .compatible = "sigma,smp8642-i2c",
+ .data = &xlr_i2c_config_tangox,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xlr_i2c_dt_ids);
+
+static int xlr_i2c_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct xlr_i2c_private *priv;
+ struct resource *res;
+ struct clk *clk;
+ unsigned long clk_rate;
+ unsigned long clk_div;
+ u32 busfreq;
+ int irq;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ match = of_match_device(xlr_i2c_dt_ids, &pdev->dev);
+ if (match)
+ priv->cfg = match->data;
+ else
+ priv->cfg = &xlr_i2c_config_default;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
+
+ irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0 && (priv->cfg->flags & XLR_I2C_FLAG_IRQ)) {
+ priv->irq = irq;
+
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, 0xf);
+
+ ret = devm_request_irq(&pdev->dev, priv->irq, xlr_i2c_irq,
+ IRQF_SHARED, dev_name(&pdev->dev),
+ priv);
+ if (ret)
+ return ret;
+
+ init_waitqueue_head(&priv->wait);
+ }
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &busfreq))
+ busfreq = 100000;
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(clk)) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(clk);
+ clk_div = DIV_ROUND_UP(clk_rate, 2 * busfreq);
+ xlr_i2c_wreg(priv->iobase, XLR_I2C_CLKDIV, clk_div);
+
+ clk_disable(clk);
+ priv->clk = clk;
+ }
+
+ priv->adap.dev.parent = &pdev->dev;
+ priv->adap.dev.of_node = pdev->dev.of_node;
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo_data = priv;
+ priv->adap.algo = &xlr_i2c_algo;
+ priv->adap.quirks = &xlr_i2c_quirks;
+ priv->adap.nr = pdev->id;
+ priv->adap.class = I2C_CLASS_HWMON;
+ snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c");
+
+ i2c_set_adapdata(&priv->adap, priv);
+ ret = i2c_add_numbered_adapter(&priv->adap);
+ if (ret < 0)
+ goto err_unprepare_clk;
+
+ platform_set_drvdata(pdev, priv);
+ dev_info(&priv->adap.dev, "Added I2C Bus.\n");
+ return 0;
+
+err_unprepare_clk:
+ clk_unprepare(clk);
+ return ret;
+}
+
+static int xlr_i2c_remove(struct platform_device *pdev)
+{
+ struct xlr_i2c_private *priv;
+
+ priv = platform_get_drvdata(pdev);
+ i2c_del_adapter(&priv->adap);
+ clk_unprepare(priv->clk);
+
+ return 0;
+}
+
+static struct platform_driver xlr_i2c_driver = {
+ .probe = xlr_i2c_probe,
+ .remove = xlr_i2c_remove,
+ .driver = {
+ .name = "xlr-i2cbus",
+ .of_match_table = xlr_i2c_dt_ids,
+ },
+};
+
+module_platform_driver(xlr_i2c_driver);
+
+MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>");
+MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:xlr-i2cbus");
diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c
new file mode 100644
index 000000000..b8f9e020d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zx2967.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2017 Sanechips Technology Co., Ltd.
+ * Copyright 2017 Linaro Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define REG_CMD 0x04
+#define REG_DEVADDR_H 0x0C
+#define REG_DEVADDR_L 0x10
+#define REG_CLK_DIV_FS 0x14
+#define REG_CLK_DIV_HS 0x18
+#define REG_WRCONF 0x1C
+#define REG_RDCONF 0x20
+#define REG_DATA 0x24
+#define REG_STAT 0x28
+
+#define I2C_STOP 0
+#define I2C_MASTER BIT(0)
+#define I2C_ADDR_MODE_TEN BIT(1)
+#define I2C_IRQ_MSK_ENABLE BIT(3)
+#define I2C_RW_READ BIT(4)
+#define I2C_CMB_RW_EN BIT(5)
+#define I2C_START BIT(6)
+
+#define I2C_ADDR_LOW_MASK GENMASK(6, 0)
+#define I2C_ADDR_LOW_SHIFT 0
+#define I2C_ADDR_HI_MASK GENMASK(2, 0)
+#define I2C_ADDR_HI_SHIFT 7
+
+#define I2C_WFIFO_RESET BIT(7)
+#define I2C_RFIFO_RESET BIT(7)
+
+#define I2C_IRQ_ACK_CLEAR BIT(7)
+#define I2C_INT_MASK GENMASK(6, 0)
+
+#define I2C_TRANS_DONE BIT(0)
+#define I2C_SR_EDEVICE BIT(1)
+#define I2C_SR_EDATA BIT(2)
+
+#define I2C_FIFO_MAX 16
+
+#define I2C_TIMEOUT msecs_to_jiffies(1000)
+
+#define DEV(i2c) ((i2c)->adap.dev.parent)
+
+struct zx2967_i2c {
+ struct i2c_adapter adap;
+ struct clk *clk;
+ struct completion complete;
+ u32 clk_freq;
+ void __iomem *reg_base;
+ size_t residue;
+ int irq;
+ int msg_rd;
+ u8 *cur_trans;
+ u8 access_cnt;
+ bool is_suspended;
+ int error;
+};
+
+static void zx2967_i2c_writel(struct zx2967_i2c *i2c,
+ u32 val, unsigned long reg)
+{
+ writel_relaxed(val, i2c->reg_base + reg);
+}
+
+static u32 zx2967_i2c_readl(struct zx2967_i2c *i2c, unsigned long reg)
+{
+ return readl_relaxed(i2c->reg_base + reg);
+}
+
+static void zx2967_i2c_writesb(struct zx2967_i2c *i2c,
+ void *data, unsigned long reg, int len)
+{
+ writesb(i2c->reg_base + reg, data, len);
+}
+
+static void zx2967_i2c_readsb(struct zx2967_i2c *i2c,
+ void *data, unsigned long reg, int len)
+{
+ readsb(i2c->reg_base + reg, data, len);
+}
+
+static void zx2967_i2c_start_ctrl(struct zx2967_i2c *i2c)
+{
+ u32 status;
+ u32 ctl;
+
+ status = zx2967_i2c_readl(i2c, REG_STAT);
+ status |= I2C_IRQ_ACK_CLEAR;
+ zx2967_i2c_writel(i2c, status, REG_STAT);
+
+ ctl = zx2967_i2c_readl(i2c, REG_CMD);
+ if (i2c->msg_rd)
+ ctl |= I2C_RW_READ;
+ else
+ ctl &= ~I2C_RW_READ;
+ ctl &= ~I2C_CMB_RW_EN;
+ ctl |= I2C_START;
+ zx2967_i2c_writel(i2c, ctl, REG_CMD);
+}
+
+static void zx2967_i2c_flush_fifos(struct zx2967_i2c *i2c)
+{
+ u32 offset;
+ u32 val;
+
+ if (i2c->msg_rd) {
+ offset = REG_RDCONF;
+ val = I2C_RFIFO_RESET;
+ } else {
+ offset = REG_WRCONF;
+ val = I2C_WFIFO_RESET;
+ }
+
+ val |= zx2967_i2c_readl(i2c, offset);
+ zx2967_i2c_writel(i2c, val, offset);
+}
+
+static int zx2967_i2c_empty_rx_fifo(struct zx2967_i2c *i2c, u32 size)
+{
+ u8 val[I2C_FIFO_MAX] = {0};
+ int i;
+
+ if (size > I2C_FIFO_MAX) {
+ dev_err(DEV(i2c), "fifo size %d over the max value %d\n",
+ size, I2C_FIFO_MAX);
+ return -EINVAL;
+ }
+
+ zx2967_i2c_readsb(i2c, val, REG_DATA, size);
+ for (i = 0; i < size; i++) {
+ *i2c->cur_trans++ = val[i];
+ i2c->residue--;
+ }
+
+ barrier();
+
+ return 0;
+}
+
+static int zx2967_i2c_fill_tx_fifo(struct zx2967_i2c *i2c)
+{
+ size_t residue = i2c->residue;
+ u8 *buf = i2c->cur_trans;
+
+ if (residue == 0) {
+ dev_err(DEV(i2c), "residue is %d\n", (int)residue);
+ return -EINVAL;
+ }
+
+ if (residue <= I2C_FIFO_MAX) {
+ zx2967_i2c_writesb(i2c, buf, REG_DATA, residue);
+
+ /* Again update before writing to FIFO to make sure isr sees. */
+ i2c->residue = 0;
+ i2c->cur_trans = NULL;
+ } else {
+ zx2967_i2c_writesb(i2c, buf, REG_DATA, I2C_FIFO_MAX);
+ i2c->residue -= I2C_FIFO_MAX;
+ i2c->cur_trans += I2C_FIFO_MAX;
+ }
+
+ barrier();
+
+ return 0;
+}
+
+static int zx2967_i2c_reset_hardware(struct zx2967_i2c *i2c)
+{
+ u32 val;
+ u32 clk_div;
+
+ val = I2C_MASTER | I2C_IRQ_MSK_ENABLE;
+ zx2967_i2c_writel(i2c, val, REG_CMD);
+
+ clk_div = clk_get_rate(i2c->clk) / i2c->clk_freq - 1;
+ zx2967_i2c_writel(i2c, clk_div, REG_CLK_DIV_FS);
+ zx2967_i2c_writel(i2c, clk_div, REG_CLK_DIV_HS);
+
+ zx2967_i2c_writel(i2c, I2C_FIFO_MAX - 1, REG_WRCONF);
+ zx2967_i2c_writel(i2c, I2C_FIFO_MAX - 1, REG_RDCONF);
+ zx2967_i2c_writel(i2c, 1, REG_RDCONF);
+
+ zx2967_i2c_flush_fifos(i2c);
+
+ return 0;
+}
+
+static void zx2967_i2c_isr_clr(struct zx2967_i2c *i2c)
+{
+ u32 status;
+
+ status = zx2967_i2c_readl(i2c, REG_STAT);
+ status |= I2C_IRQ_ACK_CLEAR;
+ zx2967_i2c_writel(i2c, status, REG_STAT);
+}
+
+static irqreturn_t zx2967_i2c_isr(int irq, void *dev_id)
+{
+ u32 status;
+ struct zx2967_i2c *i2c = (struct zx2967_i2c *)dev_id;
+
+ status = zx2967_i2c_readl(i2c, REG_STAT) & I2C_INT_MASK;
+ zx2967_i2c_isr_clr(i2c);
+
+ if (status & I2C_SR_EDEVICE)
+ i2c->error = -ENXIO;
+ else if (status & I2C_SR_EDATA)
+ i2c->error = -EIO;
+ else if (status & I2C_TRANS_DONE)
+ i2c->error = 0;
+ else
+ goto done;
+
+ complete(&i2c->complete);
+done:
+ return IRQ_HANDLED;
+}
+
+static void zx2967_set_addr(struct zx2967_i2c *i2c, u16 addr)
+{
+ u16 val;
+
+ val = (addr >> I2C_ADDR_LOW_SHIFT) & I2C_ADDR_LOW_MASK;
+ zx2967_i2c_writel(i2c, val, REG_DEVADDR_L);
+
+ val = (addr >> I2C_ADDR_HI_SHIFT) & I2C_ADDR_HI_MASK;
+ zx2967_i2c_writel(i2c, val, REG_DEVADDR_H);
+ if (val)
+ val = zx2967_i2c_readl(i2c, REG_CMD) | I2C_ADDR_MODE_TEN;
+ else
+ val = zx2967_i2c_readl(i2c, REG_CMD) & ~I2C_ADDR_MODE_TEN;
+ zx2967_i2c_writel(i2c, val, REG_CMD);
+}
+
+static int zx2967_i2c_xfer_bytes(struct zx2967_i2c *i2c, u32 bytes)
+{
+ unsigned long time_left;
+ int rd = i2c->msg_rd;
+ int ret;
+
+ reinit_completion(&i2c->complete);
+
+ if (rd) {
+ zx2967_i2c_writel(i2c, bytes - 1, REG_RDCONF);
+ } else {
+ ret = zx2967_i2c_fill_tx_fifo(i2c);
+ if (ret)
+ return ret;
+ }
+
+ zx2967_i2c_start_ctrl(i2c);
+
+ time_left = wait_for_completion_timeout(&i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ if (i2c->error)
+ return i2c->error;
+
+ return rd ? zx2967_i2c_empty_rx_fifo(i2c, bytes) : 0;
+}
+
+static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c,
+ struct i2c_msg *msg)
+{
+ int ret;
+ int i;
+
+ zx2967_i2c_flush_fifos(i2c);
+
+ i2c->cur_trans = msg->buf;
+ i2c->residue = msg->len;
+ i2c->access_cnt = msg->len / I2C_FIFO_MAX;
+ i2c->msg_rd = msg->flags & I2C_M_RD;
+
+ for (i = 0; i < i2c->access_cnt; i++) {
+ ret = zx2967_i2c_xfer_bytes(i2c, I2C_FIFO_MAX);
+ if (ret)
+ return ret;
+ }
+
+ if (i2c->residue > 0) {
+ ret = zx2967_i2c_xfer_bytes(i2c, i2c->residue);
+ if (ret)
+ return ret;
+ }
+
+ i2c->residue = 0;
+ i2c->access_cnt = 0;
+
+ return 0;
+}
+
+static int zx2967_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct zx2967_i2c *i2c = i2c_get_adapdata(adap);
+ int ret;
+ int i;
+
+ if (i2c->is_suspended)
+ return -EBUSY;
+
+ zx2967_set_addr(i2c, msgs->addr);
+
+ for (i = 0; i < num; i++) {
+ ret = zx2967_i2c_xfer_msg(i2c, &msgs[i]);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static void
+zx2967_smbus_xfer_prepare(struct zx2967_i2c *i2c, u16 addr,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ u32 val;
+
+ val = zx2967_i2c_readl(i2c, REG_RDCONF);
+ val |= I2C_RFIFO_RESET;
+ zx2967_i2c_writel(i2c, val, REG_RDCONF);
+ zx2967_set_addr(i2c, addr);
+ val = zx2967_i2c_readl(i2c, REG_CMD);
+ val &= ~I2C_RW_READ;
+ zx2967_i2c_writel(i2c, val, REG_CMD);
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ zx2967_i2c_writel(i2c, command, REG_DATA);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ zx2967_i2c_writel(i2c, command, REG_DATA);
+ if (read_write == I2C_SMBUS_WRITE)
+ zx2967_i2c_writel(i2c, data->byte, REG_DATA);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ zx2967_i2c_writel(i2c, command, REG_DATA);
+ if (read_write == I2C_SMBUS_WRITE) {
+ zx2967_i2c_writel(i2c, (data->word >> 8), REG_DATA);
+ zx2967_i2c_writel(i2c, (data->word & 0xff),
+ REG_DATA);
+ }
+ break;
+ }
+}
+
+static int zx2967_smbus_xfer_read(struct zx2967_i2c *i2c, int size,
+ union i2c_smbus_data *data)
+{
+ unsigned long time_left;
+ u8 buf[2];
+ u32 val;
+
+ reinit_completion(&i2c->complete);
+
+ val = zx2967_i2c_readl(i2c, REG_CMD);
+ val |= I2C_CMB_RW_EN;
+ zx2967_i2c_writel(i2c, val, REG_CMD);
+
+ val = zx2967_i2c_readl(i2c, REG_CMD);
+ val |= I2C_START;
+ zx2967_i2c_writel(i2c, val, REG_CMD);
+
+ time_left = wait_for_completion_timeout(&i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ if (i2c->error)
+ return i2c->error;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ val = zx2967_i2c_readl(i2c, REG_DATA);
+ data->byte = val;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ buf[0] = zx2967_i2c_readl(i2c, REG_DATA);
+ buf[1] = zx2967_i2c_readl(i2c, REG_DATA);
+ data->word = (buf[0] << 8) | buf[1];
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int zx2967_smbus_xfer_write(struct zx2967_i2c *i2c)
+{
+ unsigned long time_left;
+ u32 val;
+
+ reinit_completion(&i2c->complete);
+ val = zx2967_i2c_readl(i2c, REG_CMD);
+ val |= I2C_START;
+ zx2967_i2c_writel(i2c, val, REG_CMD);
+
+ time_left = wait_for_completion_timeout(&i2c->complete,
+ I2C_TIMEOUT);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ if (i2c->error)
+ return i2c->error;
+
+ return 0;
+}
+
+static int zx2967_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct zx2967_i2c *i2c = i2c_get_adapdata(adap);
+
+ if (size == I2C_SMBUS_QUICK)
+ read_write = I2C_SMBUS_WRITE;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ case I2C_SMBUS_WORD_DATA:
+ zx2967_smbus_xfer_prepare(i2c, addr, read_write,
+ command, size, data);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (read_write == I2C_SMBUS_READ)
+ return zx2967_smbus_xfer_read(i2c, size, data);
+
+ return zx2967_smbus_xfer_write(i2c);
+}
+
+static u32 zx2967_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_QUICK |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static int __maybe_unused zx2967_i2c_suspend(struct device *dev)
+{
+ struct zx2967_i2c *i2c = dev_get_drvdata(dev);
+
+ i2c->is_suspended = true;
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static int __maybe_unused zx2967_i2c_resume(struct device *dev)
+{
+ struct zx2967_i2c *i2c = dev_get_drvdata(dev);
+
+ i2c->is_suspended = false;
+ clk_prepare_enable(i2c->clk);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(zx2967_i2c_dev_pm_ops,
+ zx2967_i2c_suspend, zx2967_i2c_resume);
+
+static const struct i2c_algorithm zx2967_i2c_algo = {
+ .master_xfer = zx2967_i2c_xfer,
+ .smbus_xfer = zx2967_smbus_xfer,
+ .functionality = zx2967_i2c_func,
+};
+
+static const struct i2c_adapter_quirks zx2967_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static const struct of_device_id zx2967_i2c_of_match[] = {
+ { .compatible = "zte,zx296718-i2c", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, zx2967_i2c_of_match);
+
+static int zx2967_i2c_probe(struct platform_device *pdev)
+{
+ struct zx2967_i2c *i2c;
+ void __iomem *reg_base;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "missing controller clock");
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable i2c_clk\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency",
+ &i2c->clk_freq);
+ if (ret) {
+ dev_err(&pdev->dev, "missing clock-frequency");
+ return ret;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+
+ i2c->irq = ret;
+ i2c->reg_base = reg_base;
+ i2c->clk = clk;
+
+ init_completion(&i2c->complete);
+ platform_set_drvdata(pdev, i2c);
+
+ ret = zx2967_i2c_reset_hardware(i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize i2c controller\n");
+ goto err_clk_unprepare;
+ }
+
+ ret = devm_request_irq(&pdev->dev, i2c->irq,
+ zx2967_i2c_isr, 0, dev_name(&pdev->dev), i2c);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq %i\n", i2c->irq);
+ goto err_clk_unprepare;
+ }
+
+ i2c_set_adapdata(&i2c->adap, i2c);
+ strlcpy(i2c->adap.name, "zx2967 i2c adapter",
+ sizeof(i2c->adap.name));
+ i2c->adap.algo = &zx2967_i2c_algo;
+ i2c->adap.quirks = &zx2967_i2c_quirks;
+ i2c->adap.nr = pdev->id;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret)
+ goto err_clk_unprepare;
+
+ return 0;
+
+err_clk_unprepare:
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int zx2967_i2c_remove(struct platform_device *pdev)
+{
+ struct zx2967_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static struct platform_driver zx2967_i2c_driver = {
+ .probe = zx2967_i2c_probe,
+ .remove = zx2967_i2c_remove,
+ .driver = {
+ .name = "zx2967_i2c",
+ .of_match_table = zx2967_i2c_of_match,
+ .pm = &zx2967_i2c_dev_pm_ops,
+ },
+};
+module_platform_driver(zx2967_i2c_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE ZX2967 I2C Bus Controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
new file mode 100644
index 000000000..e0923bee8
--- /dev/null
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -0,0 +1,608 @@
+/*
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ National Semiconductor SCx200 ACCESS.bus support
+ Also supports the AMD CS5535 and AMD CS5536
+
+ Based on i2c-keywest.c which is:
+ Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/scx200.h>
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x820, 0x840 };
+module_param_hw_array(base, int, ioport, NULL, 0);
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define POLL_TIMEOUT (HZ/5)
+
+enum scx200_acb_state {
+ state_idle,
+ state_address,
+ state_command,
+ state_repeat_start,
+ state_quick,
+ state_read,
+ state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+ "idle",
+ "address",
+ "command",
+ "repeat_start",
+ "quick",
+ "read",
+ "write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface {
+ struct scx200_acb_iface *next;
+ struct i2c_adapter adapter;
+ unsigned base;
+ struct mutex mutex;
+
+ /* State machine data */
+ enum scx200_acb_state state;
+ int result;
+ u8 address_byte;
+ u8 command;
+ u8 *ptr;
+ char needs_reset;
+ unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA (iface->base + 0)
+#define ACBST (iface->base + 1)
+#define ACBST_SDAST 0x40 /* SDA Status */
+#define ACBST_BER 0x20
+#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
+#define ACBST_STASTR 0x08 /* Stall After Start */
+#define ACBST_MASTER 0x02
+#define ACBCST (iface->base + 2)
+#define ACBCST_BB 0x02
+#define ACBCTL1 (iface->base + 3)
+#define ACBCTL1_STASTRE 0x80
+#define ACBCTL1_NMINTE 0x40
+#define ACBCTL1_ACK 0x10
+#define ACBCTL1_STOP 0x02
+#define ACBCTL1_START 0x01
+#define ACBADDR (iface->base + 4)
+#define ACBCTL2 (iface->base + 5)
+#define ACBCTL2_ENABLE 0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+ const char *errmsg;
+
+ dev_dbg(&iface->adapter.dev, "state %s, status = 0x%02x\n",
+ scx200_acb_state_name[iface->state], status);
+
+ if (status & ACBST_BER) {
+ errmsg = "bus error";
+ goto error;
+ }
+ if (!(status & ACBST_MASTER)) {
+ errmsg = "not master";
+ goto error;
+ }
+ if (status & ACBST_NEGACK) {
+ dev_dbg(&iface->adapter.dev, "negative ack in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -ENXIO;
+
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+
+ /* Reset the status register */
+ outb(0, ACBST);
+ return;
+ }
+
+ switch (iface->state) {
+ case state_idle:
+ dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
+ break;
+
+ case state_address:
+ /* Do a pointer write first */
+ outb(iface->address_byte & ~1, ACBSDA);
+
+ iface->state = state_command;
+ break;
+
+ case state_command:
+ outb(iface->command, ACBSDA);
+
+ if (iface->address_byte & 1)
+ iface->state = state_repeat_start;
+ else
+ iface->state = state_write;
+ break;
+
+ case state_repeat_start:
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+ /* fallthrough */
+
+ case state_quick:
+ if (iface->address_byte & 1) {
+ if (iface->len == 1)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_read;
+ } else {
+ outb(iface->address_byte, ACBSDA);
+
+ iface->state = state_write;
+ }
+ break;
+
+ case state_read:
+ /* Set ACK if _next_ byte will be the last one */
+ if (iface->len == 2)
+ outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+ else
+ outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+ if (iface->len == 1) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ }
+
+ *iface->ptr++ = inb(ACBSDA);
+ --iface->len;
+
+ break;
+
+ case state_write:
+ if (iface->len == 0) {
+ iface->result = 0;
+ iface->state = state_idle;
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ break;
+ }
+
+ outb(*iface->ptr++, ACBSDA);
+ --iface->len;
+
+ break;
+ }
+
+ return;
+
+ error:
+ dev_err(&iface->adapter.dev,
+ "%s in state %s (addr=0x%02x, len=%d, status=0x%02x)\n", errmsg,
+ scx200_acb_state_name[iface->state], iface->address_byte,
+ iface->len, status);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+ u8 status;
+ unsigned long timeout;
+
+ timeout = jiffies + POLL_TIMEOUT;
+ while (1) {
+ status = inb(ACBST);
+
+ /* Reset the status register to avoid the hang */
+ outb(0, ACBST);
+
+ if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+ scx200_acb_machine(iface, status);
+ return;
+ }
+ if (time_after(jiffies, timeout))
+ break;
+ cpu_relax();
+ cond_resched();
+ }
+
+ dev_err(&iface->adapter.dev, "timeout in state %s\n",
+ scx200_acb_state_name[iface->state]);
+
+ iface->state = state_idle;
+ iface->result = -EIO;
+ iface->needs_reset = 1;
+}
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+ /* Polling mode */
+ outb(0, ACBCTL1);
+ /* Disable slave address */
+ outb(0, ACBADDR);
+ /* Enable the ACCESS.bus device */
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+ /* Free STALL after START */
+ outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+ /* Send a STOP */
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ /* Clear BER, NEGACK and STASTR bits */
+ outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+ /* Clear BB bit */
+ outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+ u16 address, unsigned short flags,
+ char rw, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
+ int len;
+ u8 *buffer;
+ u16 cur_word;
+ int rc;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ len = 0;
+ buffer = NULL;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ len = 1;
+ buffer = rw ? &data->byte : &command;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ len = 1;
+ buffer = &data->byte;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ len = 2;
+ cur_word = cpu_to_le16(data->word);
+ buffer = (u8 *)&cur_word;
+ break;
+
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+ buffer = &data->block[1];
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(&adapter->dev,
+ "size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+ size, address, command, len, rw);
+
+ if (!len && rw == I2C_SMBUS_READ) {
+ dev_dbg(&adapter->dev, "zero length read\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&iface->mutex);
+
+ iface->address_byte = (address << 1) | rw;
+ iface->command = command;
+ iface->ptr = buffer;
+ iface->len = len;
+ iface->result = -EINVAL;
+ iface->needs_reset = 0;
+
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+ iface->state = state_quick;
+ else
+ iface->state = state_address;
+
+ while (iface->state != state_idle)
+ scx200_acb_poll(iface);
+
+ if (iface->needs_reset)
+ scx200_acb_reset(iface);
+
+ rc = iface->result;
+
+ mutex_unlock(&iface->mutex);
+
+ if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+ data->word = le16_to_cpu(cur_word);
+
+#ifdef DEBUG
+ dev_dbg(&adapter->dev, "transfer done, result: %d", rc);
+ if (buffer) {
+ int i;
+ printk(" data:");
+ for (i = 0; i < len; ++i)
+ printk(" %02x", buffer[i]);
+ }
+ printk("\n");
+#endif
+
+ return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static const struct i2c_algorithm scx200_acb_algorithm = {
+ .smbus_xfer = scx200_acb_smbus_xfer,
+ .functionality = scx200_acb_func,
+};
+
+static struct scx200_acb_iface *scx200_acb_list;
+static DEFINE_MUTEX(scx200_acb_list_mutex);
+
+static int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+ u8 val;
+
+ /* Disable the ACCESS.bus device and Configure the SCL
+ frequency: 16 clock cycles */
+ outb(0x70, ACBCTL2);
+
+ if (inb(ACBCTL2) != 0x70) {
+ pr_debug("ACBCTL2 readback failed\n");
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if (val) {
+ pr_debug("disabled, but ACBCTL1=0x%02x\n", val);
+ return -ENXIO;
+ }
+
+ outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+ outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+ val = inb(ACBCTL1);
+ if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+ pr_debug("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n",
+ val);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static struct scx200_acb_iface *scx200_create_iface(const char *text,
+ struct device *dev, int index)
+{
+ struct scx200_acb_iface *iface;
+ struct i2c_adapter *adapter;
+
+ iface = kzalloc(sizeof(*iface), GFP_KERNEL);
+ if (!iface)
+ return NULL;
+
+ adapter = &iface->adapter;
+ i2c_set_adapdata(adapter, iface);
+ snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
+ adapter->owner = THIS_MODULE;
+ adapter->algo = &scx200_acb_algorithm;
+ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adapter->dev.parent = dev;
+
+ mutex_init(&iface->mutex);
+
+ return iface;
+}
+
+static int scx200_acb_create(struct scx200_acb_iface *iface)
+{
+ struct i2c_adapter *adapter;
+ int rc;
+
+ adapter = &iface->adapter;
+
+ rc = scx200_acb_probe(iface);
+ if (rc) {
+ pr_warn("probe failed\n");
+ return rc;
+ }
+
+ scx200_acb_reset(iface);
+
+ if (i2c_add_adapter(adapter) < 0) {
+ pr_err("failed to register\n");
+ return -ENODEV;
+ }
+
+ if (!adapter->dev.parent) {
+ /* If there's no dev, we're tracking (ISA) ifaces manually */
+ mutex_lock(&scx200_acb_list_mutex);
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ mutex_unlock(&scx200_acb_list_mutex);
+ }
+
+ return 0;
+}
+
+static struct scx200_acb_iface *scx200_create_dev(const char *text,
+ unsigned long base, int index, struct device *dev)
+{
+ struct scx200_acb_iface *iface;
+ int rc;
+
+ iface = scx200_create_iface(text, dev, index);
+
+ if (iface == NULL)
+ return NULL;
+
+ if (!request_region(base, 8, iface->adapter.name)) {
+ pr_err("can't allocate io 0x%lx-0x%lx\n", base, base + 8 - 1);
+ goto errout_free;
+ }
+
+ iface->base = base;
+ rc = scx200_acb_create(iface);
+
+ if (rc == 0)
+ return iface;
+
+ release_region(base, 8);
+ errout_free:
+ kfree(iface);
+ return NULL;
+}
+
+static int scx200_probe(struct platform_device *pdev)
+{
+ struct scx200_acb_iface *iface;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -ENODEV;
+ }
+
+ iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+ if (!iface)
+ return -EIO;
+
+ dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+ iface->adapter.name);
+ platform_set_drvdata(pdev, iface);
+
+ return 0;
+}
+
+static void scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+}
+
+static int scx200_remove(struct platform_device *pdev)
+{
+ struct scx200_acb_iface *iface;
+
+ iface = platform_get_drvdata(pdev);
+ scx200_cleanup_iface(iface);
+
+ return 0;
+}
+
+static struct platform_driver scx200_pci_driver = {
+ .driver = {
+ .name = "cs5535-smb",
+ },
+ .probe = scx200_probe,
+ .remove = scx200_remove,
+};
+
+static const struct pci_device_id scx200_isa[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+ { 0, }
+};
+
+static __init void scx200_scan_isa(void)
+{
+ int i;
+
+ if (!pci_dev_present(scx200_isa))
+ return;
+
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] == 0)
+ continue;
+
+ /* XXX: should we care about failures? */
+ scx200_create_dev("SCx200", base[i], i, NULL);
+ }
+}
+
+static int __init scx200_acb_init(void)
+{
+ pr_debug("NatSemi SCx200 ACCESS.bus Driver\n");
+
+ /* First scan for ISA-based devices */
+ scx200_scan_isa(); /* XXX: should we care about errors? */
+
+ /* If at least one bus was created, init must succeed */
+ if (scx200_acb_list)
+ return 0;
+
+ /* No ISA devices; register the platform driver for PCI-based devices */
+ return platform_driver_register(&scx200_pci_driver);
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+ struct scx200_acb_iface *iface;
+
+ platform_driver_unregister(&scx200_pci_driver);
+
+ mutex_lock(&scx200_acb_list_mutex);
+ while ((iface = scx200_acb_list) != NULL) {
+ scx200_acb_list = iface->next;
+ mutex_unlock(&scx200_acb_list_mutex);
+
+ scx200_cleanup_iface(iface);
+
+ mutex_lock(&scx200_acb_list_mutex);
+ }
+ mutex_unlock(&scx200_acb_list_mutex);
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);