From 392e8802486cb573b916e746010e141a75f507e6 Mon Sep 17 00:00:00 2001
From: Kevin
Date: Sat, 15 Nov 2014 09:58:27 +0800
Subject: init android origin source code
---
ANDROID_3.4.5/drivers/i2c/Kconfig | 113 ++
ANDROID_3.4.5/drivers/i2c/Makefile | 13 +
ANDROID_3.4.5/drivers/i2c/algos/Kconfig | 17 +
ANDROID_3.4.5/drivers/i2c/algos/Makefile | 9 +
ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-bit.c | 671 ++++++
ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pca.c | 566 ++++++
ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.c | 442 ++++
ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.h | 77 +
ANDROID_3.4.5/drivers/i2c/busses/Kconfig | 910 +++++++++
ANDROID_3.4.5/drivers/i2c/busses/Makefile | 91 +
ANDROID_3.4.5/drivers/i2c/busses/i2c-acorn.c | 96 +
ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1535.c | 552 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1563.c | 448 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-ali15x3.c | 533 +++++
.../drivers/i2c/busses/i2c-amd756-s4882.c | 262 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756.c | 430 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-amd8111.c | 505 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-at91.c | 314 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-au1550.c | 434 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-bfin-twi.c | 797 ++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-cpm.c | 731 +++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-davinci.c | 830 ++++++++
.../drivers/i2c/busses/i2c-designware-core.c | 705 +++++++
.../drivers/i2c/busses/i2c-designware-core.h | 105 +
.../drivers/i2c/busses/i2c-designware-pcidrv.c | 391 ++++
.../drivers/i2c/busses/i2c-designware-platdrv.c | 227 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-diolan-u2c.c | 522 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-eg20t.c | 1068 ++++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-elektor.c | 347 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-gpio.c | 279 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-highlander.c | 487 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-hydra.c | 178 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-i801.c | 949 +++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-ibm_iic.c | 818 ++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-ibm_iic.h | 123 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-imx.c | 642 ++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-intel-mid.c | 1135 +++++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c | 531 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.h | 107 +
ANDROID_3.4.5/drivers/i2c/busses/i2c-isch.c | 314 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-ixp2000.c | 157 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-mpc.c | 758 +++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-mv64xxx.c | 618 ++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-mxs.c | 419 ++++
.../drivers/i2c/busses/i2c-nforce2-s4985.c | 257 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-nforce2.c | 468 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-nomadik.c | 1068 ++++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-nuc900.c | 708 +++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-ocores.c | 414 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-octeon.c | 638 ++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-omap.c | 1219 +++++++++++
.../drivers/i2c/busses/i2c-parport-light.c | 281 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-parport.c | 306 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-parport.h | 110 +
ANDROID_3.4.5/drivers/i2c/busses/i2c-pasemi.c | 433 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-pca-isa.c | 229 +++
.../drivers/i2c/busses/i2c-pca-platform.c | 293 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-piix4.c | 563 ++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-pmcmsp.c | 643 ++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-pnx.c | 733 +++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-powermac.c | 326 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-puv3.c | 294 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-pxa-pci.c | 180 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-pxa.c | 1308 ++++++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-s3c2410.c | 1161 +++++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-s6000.c | 404 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-s6000.h | 79 +
ANDROID_3.4.5/drivers/i2c/busses/i2c-scmi.c | 445 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sh7760.c | 567 ++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sh_mobile.c | 739 +++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sibyte.c | 198 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-simtec.c | 175 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sirf.c | 459 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sis5595.c | 434 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sis630.c | 533 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-sis96x.c | 344 ++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-stu300.c | 1057 ++++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-stub.c | 222 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-taos-evm.c | 331 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-tegra.c | 791 ++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-tiny-usb.c | 271 +++
ANDROID_3.4.5/drivers/i2c/busses/i2c-versatile.c | 170 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-via.c | 180 ++
ANDROID_3.4.5/drivers/i2c/busses/i2c-viapro.c | 508 +++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-xiic.c | 812 ++++++++
ANDROID_3.4.5/drivers/i2c/busses/i2c-xlr.c | 278 +++
ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c | 618 ++++++
ANDROID_3.4.5/drivers/i2c/busses/scx200_i2c.c | 131 ++
ANDROID_3.4.5/drivers/i2c/i2c-boardinfo.c | 94 +
ANDROID_3.4.5/drivers/i2c/i2c-core.c | 2136 ++++++++++++++++++++
ANDROID_3.4.5/drivers/i2c/i2c-core.h | 34 +
ANDROID_3.4.5/drivers/i2c/i2c-dev.c | 652 ++++++
ANDROID_3.4.5/drivers/i2c/i2c-mux.c | 164 ++
ANDROID_3.4.5/drivers/i2c/i2c-smbus.c | 263 +++
ANDROID_3.4.5/drivers/i2c/muxes/Kconfig | 40 +
ANDROID_3.4.5/drivers/i2c/muxes/Makefile | 8 +
ANDROID_3.4.5/drivers/i2c/muxes/gpio-i2cmux.c | 173 ++
ANDROID_3.4.5/drivers/i2c/muxes/pca9541.c | 400 ++++
ANDROID_3.4.5/drivers/i2c/muxes/pca954x.c | 291 +++
99 files changed, 45354 insertions(+)
create mode 100644 ANDROID_3.4.5/drivers/i2c/Kconfig
create mode 100644 ANDROID_3.4.5/drivers/i2c/Makefile
create mode 100644 ANDROID_3.4.5/drivers/i2c/algos/Kconfig
create mode 100644 ANDROID_3.4.5/drivers/i2c/algos/Makefile
create mode 100644 ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-bit.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pca.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/Kconfig
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/Makefile
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-acorn.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1535.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1563.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ali15x3.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756-s4882.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-amd8111.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-at91.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-au1550.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-bfin-twi.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-cpm.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-davinci.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-pcidrv.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-platdrv.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-diolan-u2c.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-eg20t.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-elektor.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-gpio.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-highlander.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-hydra.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-i801.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ibm_iic.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ibm_iic.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-imx.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-intel-mid.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-isch.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ixp2000.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-mpc.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-mv64xxx.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-mxs.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-nforce2-s4985.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-nforce2.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-nomadik.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-nuc900.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-ocores.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-octeon.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-omap.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-parport-light.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-parport.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-parport.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pasemi.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pca-isa.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pca-platform.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-piix4.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pmcmsp.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pnx.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-powermac.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-puv3.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pxa-pci.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-pxa.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-s3c2410.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-s6000.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-s6000.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-scmi.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sh7760.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sh_mobile.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sibyte.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-simtec.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sirf.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sis5595.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sis630.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-sis96x.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-stu300.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-stub.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-taos-evm.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-tegra.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-tiny-usb.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-versatile.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-via.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-viapro.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-xiic.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/i2c-xlr.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/busses/scx200_i2c.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/i2c-boardinfo.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/i2c-core.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/i2c-core.h
create mode 100644 ANDROID_3.4.5/drivers/i2c/i2c-dev.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/i2c-mux.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/i2c-smbus.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/muxes/Kconfig
create mode 100644 ANDROID_3.4.5/drivers/i2c/muxes/Makefile
create mode 100644 ANDROID_3.4.5/drivers/i2c/muxes/gpio-i2cmux.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/muxes/pca9541.c
create mode 100644 ANDROID_3.4.5/drivers/i2c/muxes/pca954x.c
(limited to 'ANDROID_3.4.5/drivers/i2c')
diff --git a/ANDROID_3.4.5/drivers/i2c/Kconfig b/ANDROID_3.4.5/drivers/i2c/Kconfig
new file mode 100644
index 00000000..5f13c62e
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/Kconfig
@@ -0,0 +1,113 @@
+#
+# I2C subsystem configuration
+#
+
+menuconfig I2C
+ tristate "I2C support"
+ depends on HAS_IOMEM
+ select RT_MUTEXES
+ ---help---
+ I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
+ many micro controller applications and developed by Philips. SMBus,
+ or System Management Bus is a subset of the I2C protocol. More
+ information is contained in the directory ,
+ especially in the file called "summary" there.
+
+ Both I2C and SMBus are supported here. You will need this for
+ hardware sensors support, and also for Video For Linux support.
+
+ If you want I2C support, you should say Y here and also to the
+ specific driver for your bus adapter(s) below.
+
+ This I2C support can also be built as a module. If so, the module
+ will be called i2c-core.
+
+if I2C
+
+config I2C_BOARDINFO
+ boolean
+ default y
+
+config I2C_COMPAT
+ boolean "Enable compatibility bits for old user-space"
+ default y
+ help
+ Say Y here if you intend to run lm-sensors 3.1.1 or older, or any
+ other user-space package which expects i2c adapters to be class
+ devices. If you don't know, say Y.
+
+config I2C_CHARDEV
+ tristate "I2C device interface"
+ help
+ Say Y here to use i2c-* device files, usually found in the /dev
+ directory on your system. They make it possible to have user-space
+ programs use the I2C bus. Information on how to do this is
+ contained in the file .
+
+ This support is also available as a module. If so, the module
+ will be called i2c-dev.
+
+config I2C_MUX
+ tristate "I2C bus multiplexing support"
+ depends on EXPERIMENTAL
+ help
+ Say Y here if you want the I2C core to support the ability to
+ handle multiplexed I2C bus topologies, by presenting each
+ multiplexed segment as a I2C adapter.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-mux.
+
+source drivers/i2c/muxes/Kconfig
+
+config I2C_HELPER_AUTO
+ bool "Autoselect pertinent helper modules"
+ default y
+ help
+ Some I2C bus drivers require so-called "I2C algorithm" modules
+ to work. These are basically software-only abstractions of generic
+ I2C interfaces. This option will autoselect them so that you don't
+ have to care.
+
+ Unselect this only if you need to enable additional helper
+ modules, for example for use with external I2C bus drivers.
+
+ In doubt, say Y.
+
+config I2C_SMBUS
+ tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
+ help
+ Say Y here if you want support for SMBus extensions to the I2C
+ specification. At the moment, the only supported extension is
+ the SMBus alert protocol.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-smbus.
+
+source drivers/i2c/algos/Kconfig
+source drivers/i2c/busses/Kconfig
+
+config I2C_DEBUG_CORE
+ bool "I2C Core debugging messages"
+ help
+ Say Y here if you want the I2C core to produce a bunch of debug
+ messages to the system log. Select this if you are having a
+ problem with I2C support and want to see more of what is going on.
+
+config I2C_DEBUG_ALGO
+ bool "I2C Algorithm debugging messages"
+ help
+ Say Y here if you want the I2C algorithm drivers to produce a bunch
+ of debug messages to the system log. Select this if you are having
+ a problem with I2C support and want to see more of what is going
+ on.
+
+config I2C_DEBUG_BUS
+ bool "I2C Bus debugging messages"
+ help
+ Say Y here if you want the I2C bus drivers to produce a bunch of
+ debug messages to the system log. Select this if you are having
+ a problem with I2C support and want to see more of what is going
+ on.
+
+endif # I2C
diff --git a/ANDROID_3.4.5/drivers/i2c/Makefile b/ANDROID_3.4.5/drivers/i2c/Makefile
new file mode 100644
index 00000000..beee6b2d
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the i2c core.
+#
+
+obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
+obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
+obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
+obj-$(CONFIG_I2C_MUX) += i2c-mux.o
+obj-y += algos/ busses/ muxes/
+
+ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
+CFLAGS_i2c-core.o := -Wno-deprecated-declarations
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/Kconfig b/ANDROID_3.4.5/drivers/i2c/algos/Kconfig
new file mode 100644
index 00000000..f1cfe7e5
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/Kconfig
@@ -0,0 +1,17 @@
+#
+# I2C algorithm drivers configuration
+#
+
+menu "I2C Algorithms"
+ visible if !I2C_HELPER_AUTO
+
+config I2C_ALGOBIT
+ tristate "I2C bit-banging interfaces"
+
+config I2C_ALGOPCF
+ tristate "I2C PCF 8584 interfaces"
+
+config I2C_ALGOPCA
+ tristate "I2C PCA 9564 interfaces"
+
+endmenu
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/Makefile b/ANDROID_3.4.5/drivers/i2c/algos/Makefile
new file mode 100644
index 00000000..215303f6
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the i2c algorithms
+#
+
+obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
+obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
+obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
+
+ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-bit.c b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-bit.c
new file mode 100644
index 00000000..7f0b8321
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-bit.c
@@ -0,0 +1,671 @@
+/* -------------------------------------------------------------------------
+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
+ * -------------------------------------------------------------------------
+ * 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA.
+ * ------------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard , Kyösti Mälkki
+ and Jean Delvare */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* ----- global defines ----------------------------------------------- */
+
+#ifdef DEBUG
+#define bit_dbg(level, dev, format, args...) \
+ do { \
+ if (i2c_debug >= level) \
+ dev_dbg(dev, format, ##args); \
+ } while (0)
+#else
+#define bit_dbg(level, dev, format, args...) \
+ do {} while (0)
+#endif /* DEBUG */
+
+/* ----- global variables --------------------------------------------- */
+
+static int bit_test; /* see if the line-setting functions work */
+module_param(bit_test, int, S_IRUGO);
+MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck");
+
+#ifdef DEBUG
+static int i2c_debug = 1;
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose");
+#endif
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define setsda(adap, val) adap->setsda(adap->data, val)
+#define setscl(adap, val) adap->setscl(adap->data, val)
+#define getsda(adap) adap->getsda(adap->data)
+#define getscl(adap) adap->getscl(adap->data)
+
+static inline void sdalo(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+}
+
+static inline void sdahi(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap, 1);
+ udelay((adap->udelay + 1) / 2);
+}
+
+static inline void scllo(struct i2c_algo_bit_data *adap)
+{
+ setscl(adap, 0);
+ udelay(adap->udelay / 2);
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static int sclhi(struct i2c_algo_bit_data *adap)
+{
+ unsigned long start;
+
+ setscl(adap, 1);
+
+ /* Not all adapters have scl sense line... */
+ if (!adap->getscl)
+ goto done;
+
+ start = jiffies;
+ while (!getscl(adap)) {
+ /* This hw knows how to read the clock line, so we wait
+ * until it actually gets high. This is safer as some
+ * chips may hold it low ("clock stretching") while they
+ * are processing data internally.
+ */
+ if (time_after(jiffies, start + adap->timeout)) {
+ /* Test one last time, as we may have been preempted
+ * between last check and timeout test.
+ */
+ if (getscl(adap))
+ break;
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+#ifdef DEBUG
+ if (jiffies != start && i2c_debug >= 3)
+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+ "high\n", jiffies - start);
+#endif
+
+done:
+ udelay(adap->udelay);
+ return 0;
+}
+
+
+/* --- other auxiliary functions -------------------------------------- */
+static void i2c_start(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl, sda are high */
+ setsda(adap, 0);
+ udelay(adap->udelay);
+ scllo(adap);
+}
+
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl is low */
+ sdahi(adap);
+ sclhi(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
+ scllo(adap);
+}
+
+
+static void i2c_stop(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl is low */
+ sdalo(adap);
+ sclhi(adap);
+ setsda(adap, 1);
+ udelay(adap->udelay);
+}
+
+
+
+/* send a byte without start cond., look for arbitration,
+ check ackn. from slave */
+/* returns:
+ * 1 if the device acknowledged
+ * 0 if the device did not ack
+ * -ETIMEDOUT if an error occurred (while raising the scl line)
+ */
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+{
+ int i;
+ int sb;
+ int ack;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ for (i = 7; i >= 0; i--) {
+ sb = (c >> i) & 1;
+ setsda(adap, sb);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timed out */
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at bit #%d\n", (int)c, i);
+ return -ETIMEDOUT;
+ }
+ /* FIXME do arbitration here:
+ * if (sb && !getsda(adap)) -> ouch! Get out of here.
+ *
+ * Report a unique code, so higher level code can retry
+ * the whole (combined) message and *NOT* issue STOP.
+ */
+ scllo(adap);
+ }
+ sdahi(adap);
+ if (sclhi(adap) < 0) { /* timeout */
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at ack\n", (int)c);
+ return -ETIMEDOUT;
+ }
+
+ /* read ack: SDA should be pulled down by slave, or it may
+ * NAK (usually to report problems with the data we wrote).
+ */
+ ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+ ack ? "A" : "NA");
+
+ scllo(adap);
+ return ack;
+ /* assert: scl is low (sda undef) */
+}
+
+
+static int i2c_inb(struct i2c_adapter *i2c_adap)
+{
+ /* read byte via i2c port, without start/stop sequence */
+ /* acknowledge is sent in i2c_read. */
+ int i;
+ unsigned char indata = 0;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ sdahi(adap);
+ for (i = 0; i < 8; i++) {
+ if (sclhi(adap) < 0) { /* timeout */
+ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+ "#%d\n", 7 - i);
+ return -ETIMEDOUT;
+ }
+ indata *= 2;
+ if (getsda(adap))
+ indata |= 0x01;
+ setscl(adap, 0);
+ udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
+ }
+ /* assert: scl is low */
+ return indata;
+}
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_adapter *i2c_adap)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ const char *name = i2c_adap->name;
+ int scl, sda, ret;
+
+ if (adap->pre_xfer) {
+ ret = adap->pre_xfer(i2c_adap);
+ if (ret < 0)
+ return -ENODEV;
+ }
+
+ if (adap->getscl == NULL)
+ pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (!scl || !sda) {
+ printk(KERN_WARNING
+ "%s: bus seems to be busy (scl=%d, sda=%d)\n",
+ name, scl, sda);
+ goto bailout;
+ }
+
+ sdalo(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (sda) {
+ printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+ goto bailout;
+ }
+ if (!scl) {
+ printk(KERN_WARNING "%s: SCL unexpected low "
+ "while pulling SDA low!\n", name);
+ goto bailout;
+ }
+
+ sdahi(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (!sda) {
+ printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+ goto bailout;
+ }
+ if (!scl) {
+ printk(KERN_WARNING "%s: SCL unexpected low "
+ "while pulling SDA high!\n", name);
+ goto bailout;
+ }
+
+ scllo(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 0 : getscl(adap);
+ if (scl) {
+ printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+ goto bailout;
+ }
+ if (!sda) {
+ printk(KERN_WARNING "%s: SDA unexpected low "
+ "while pulling SCL low!\n", name);
+ goto bailout;
+ }
+
+ sclhi(adap);
+ sda = getsda(adap);
+ scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ if (!scl) {
+ printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+ goto bailout;
+ }
+ if (!sda) {
+ printk(KERN_WARNING "%s: SDA unexpected low "
+ "while pulling SCL high!\n", name);
+ goto bailout;
+ }
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
+
+ pr_info("%s: Test OK\n", name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
+
+ return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+/* try_address tries to contact a chip for a number of
+ * times before it gives up.
+ * return values:
+ * 1 chip answered
+ * 0 chip did not answer
+ * -x transmission error
+ */
+static int try_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ int i, ret = 0;
+
+ for (i = 0; i <= retries; i++) {
+ ret = i2c_outb(i2c_adap, addr);
+ if (ret == 1 || i == retries)
+ break;
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+ i2c_stop(adap);
+ udelay(adap->udelay);
+ yield();
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ i2c_start(adap);
+ }
+ if (i && ret)
+ bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+ "0x%02x: %s\n", i + 1,
+ addr & 1 ? "read from" : "write to", addr >> 1,
+ ret == 1 ? "success" : "failed, timeout?");
+ return ret;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ const unsigned char *temp = msg->buf;
+ int count = msg->len;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ int retval;
+ int wrcount = 0;
+
+ while (count > 0) {
+ retval = i2c_outb(i2c_adap, *temp);
+
+ /* OK/ACK; or ignored NAK */
+ if ((retval > 0) || (nak_ok && (retval == 0))) {
+ count--;
+ temp++;
+ wrcount++;
+
+ /* A slave NAKing the master means the slave didn't like
+ * something about the data it saw. For example, maybe
+ * the SMBus PEC was wrong.
+ */
+ } else if (retval == 0) {
+ dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+ return -EIO;
+
+ /* Timeout; or (someday) lost arbitration
+ *
+ * FIXME Lost ARB implies retrying the transaction from
+ * the first message, after the "winning" master issues
+ * its STOP. As a rule, upper layer code has no reason
+ * to know or care about this ... it is *NOT* an error.
+ */
+ } else {
+ dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+ retval);
+ return retval;
+ }
+ }
+ return wrcount;
+}
+
+static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: sda is high */
+ if (is_ack) /* send ack */
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timeout */
+ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
+ return -ETIMEDOUT;
+ }
+ scllo(adap);
+ return 0;
+}
+
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ int inval;
+ int rdcount = 0; /* counts bytes read */
+ unsigned char *temp = msg->buf;
+ int count = msg->len;
+ const unsigned flags = msg->flags;
+
+ while (count > 0) {
+ inval = i2c_inb(i2c_adap);
+ if (inval >= 0) {
+ *temp = inval;
+ rdcount++;
+ } else { /* read timed out */
+ break;
+ }
+
+ temp++;
+ count--;
+
+ /* Some SMBus transactions require that we receive the
+ transaction length as the first read byte. */
+ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
+ if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+ if (!(flags & I2C_M_NO_RD_ACK))
+ acknak(i2c_adap, 0);
+ dev_err(&i2c_adap->dev, "readbytes: invalid "
+ "block length (%d)\n", inval);
+ return -EPROTO;
+ }
+ /* The original count value accounts for the extra
+ bytes, that is, either 1 for a regular transaction,
+ or 2 for a PEC transaction. */
+ count += inval;
+ msg->len += inval;
+ }
+
+ bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+ inval,
+ (flags & I2C_M_NO_RD_ACK)
+ ? "(no ack/nak)"
+ : (count ? "A" : "NA"));
+
+ if (!(flags & I2C_M_NO_RD_ACK)) {
+ inval = acknak(i2c_adap, count);
+ if (inval < 0)
+ return inval;
+ }
+ }
+ return rdcount;
+}
+
+/* doAddress initiates the transfer by generating the start condition (in
+ * try_address) and transmits the address in the necessary format to handle
+ * reads, writes as well as 10bit-addresses.
+ * returns:
+ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
+ * -x an error occurred (like: -ENXIO if the device did not answer, or
+ * -ETIMEDOUT, for example if the lines are stuck...)
+ */
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ unsigned short flags = msg->flags;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ unsigned char addr;
+ int ret, retries;
+
+ retries = nak_ok ? 0 : i2c_adap->retries;
+
+ if (flags & I2C_M_TEN) {
+ /* a ten bit address */
+ addr = 0xf0 | ((msg->addr >> 7) & 0x06);
+ bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
+ /* try extended address code...*/
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ dev_err(&i2c_adap->dev,
+ "died at extended address code\n");
+ return -ENXIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(i2c_adap, msg->addr & 0xff);
+ if ((ret != 1) && !nak_ok) {
+ /* the chip did not ack / xmission error occurred */
+ dev_err(&i2c_adap->dev, "died at 2nd address code\n");
+ return -ENXIO;
+ }
+ if (flags & I2C_M_RD) {
+ bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+ "start condition\n");
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ dev_err(&i2c_adap->dev,
+ "died at repeated address code\n");
+ return -EIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = msg->addr << 1;
+ if (flags & I2C_M_RD)
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok)
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int bit_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_msg *pmsg;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ int i, ret;
+ unsigned short nak_ok;
+
+ if (adap->pre_xfer) {
+ ret = adap->pre_xfer(i2c_adap);
+ if (ret < 0)
+ return ret;
+ }
+
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ i2c_start(adap);
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ if (i) {
+ bit_dbg(3, &i2c_adap->dev, "emitting "
+ "repeated start condition\n");
+ i2c_repstart(adap);
+ }
+ ret = bit_doAddress(i2c_adap, pmsg);
+ if ((ret != 0) && !nak_ok) {
+ bit_dbg(1, &i2c_adap->dev, "NAK from "
+ "device addr 0x%02x msg #%d\n",
+ msgs[i].addr, i);
+ goto bailout;
+ }
+ }
+ if (pmsg->flags & I2C_M_RD) {
+ /* read bytes into buffer*/
+ ret = readbytes(i2c_adap, pmsg);
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EIO;
+ goto bailout;
+ }
+ } else {
+ /* write bytes from buffer */
+ ret = sendbytes(i2c_adap, pmsg);
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EIO;
+ goto bailout;
+ }
+ }
+ }
+ ret = i;
+
+bailout:
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+ i2c_stop(adap);
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
+ return ret;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+const struct i2c_algorithm i2c_bit_algo = {
+ .master_xfer = bit_xfer,
+ .functionality = bit_func,
+};
+EXPORT_SYMBOL(i2c_bit_algo);
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __i2c_bit_add_bus(struct i2c_adapter *adap,
+ int (*add_adapter)(struct i2c_adapter *))
+{
+ struct i2c_algo_bit_data *bit_adap = adap->algo_data;
+ int ret;
+
+ if (bit_test) {
+ ret = test_bus(adap);
+ if (bit_test >= 2 && ret < 0)
+ return -ENODEV;
+ }
+
+ /* register new adapter to i2c module... */
+ adap->algo = &i2c_bit_algo;
+ adap->retries = 3;
+
+ ret = add_adapter(adap);
+ if (ret < 0)
+ return ret;
+
+ /* Complain if SCL can't be read */
+ if (bit_adap->getscl == NULL) {
+ dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+ dev_warn(&adap->dev, "Bus may be unreliable\n");
+ }
+ return 0;
+}
+
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+ return __i2c_bit_add_bus(adap, i2c_add_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_bus);
+
+int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
+{
+ return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
+
+MODULE_AUTHOR("Simon G. Vogl ");
+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pca.c b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pca.c
new file mode 100644
index 00000000..73133b10
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pca.c
@@ -0,0 +1,566 @@
+/*
+ * i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DEB1(fmt, args...) do { if (i2c_debug >= 1) \
+ printk(KERN_DEBUG fmt, ## args); } while (0)
+#define DEB2(fmt, args...) do { if (i2c_debug >= 2) \
+ printk(KERN_DEBUG fmt, ## args); } while (0)
+#define DEB3(fmt, args...) do { if (i2c_debug >= 3) \
+ printk(KERN_DEBUG fmt, ## args); } while (0)
+
+static int i2c_debug;
+
+#define pca_outw(adap, reg, val) adap->write_byte(adap->data, reg, val)
+#define pca_inw(adap, reg) adap->read_byte(adap->data, reg)
+
+#define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
+#define pca_clock(adap) adap->i2c_clock
+#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
+#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
+#define pca_wait(adap) adap->wait_for_completion(adap->data)
+#define pca_reset(adap) adap->reset_chip(adap->data)
+
+static void pca9665_reset(void *pd)
+{
+ struct i2c_algo_pca_data *adap = pd;
+ pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
+ pca_outw(adap, I2C_PCA_IND, 0xA5);
+ pca_outw(adap, I2C_PCA_IND, 0x5A);
+}
+
+/*
+ * Generate a start condition on the i2c bus.
+ *
+ * returns after the start condition has occurred
+ */
+static int pca_start(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== START\n");
+ sta |= I2C_PCA_CON_STA;
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+ return pca_wait(adap);
+}
+
+/*
+ * Generate a repeated start condition on the i2c bus
+ *
+ * return after the repeated start condition has occurred
+ */
+static int pca_repeated_start(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== REPEATED START\n");
+ sta |= I2C_PCA_CON_STA;
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+ return pca_wait(adap);
+}
+
+/*
+ * Generate a stop condition on the i2c bus
+ *
+ * returns after the stop condition has been generated
+ *
+ * STOPs do not generate an interrupt or set the SI flag, since the
+ * part returns the idle state (0xf8). Hence we don't need to
+ * pca_wait here.
+ */
+static void pca_stop(struct i2c_algo_pca_data *adap)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== STOP\n");
+ sta |= I2C_PCA_CON_STO;
+ sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+}
+
+/*
+ * Send the slave address and R/W bit
+ *
+ * returns after the address has been sent
+ */
+static int pca_address(struct i2c_algo_pca_data *adap,
+ struct i2c_msg *msg)
+{
+ int sta = pca_get_con(adap);
+ int addr;
+
+ addr = ((0x7f & msg->addr) << 1);
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+ DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
+ msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
+
+ pca_outw(adap, I2C_PCA_DAT, addr);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+
+ return pca_wait(adap);
+}
+
+/*
+ * Transmit a byte.
+ *
+ * Returns after the byte has been transmitted
+ */
+static int pca_tx_byte(struct i2c_algo_pca_data *adap,
+ __u8 b)
+{
+ int sta = pca_get_con(adap);
+ DEB2("=== WRITE %#04x\n", b);
+ pca_outw(adap, I2C_PCA_DAT, b);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+ pca_set_con(adap, sta);
+
+ return pca_wait(adap);
+}
+
+/*
+ * Receive a byte
+ *
+ * returns immediately.
+ */
+static void pca_rx_byte(struct i2c_algo_pca_data *adap,
+ __u8 *b, int ack)
+{
+ *b = pca_inw(adap, I2C_PCA_DAT);
+ DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
+}
+
+/*
+ * Setup ACK or NACK for next received byte and wait for it to arrive.
+ *
+ * Returns after next byte has arrived.
+ */
+static int pca_rx_ack(struct i2c_algo_pca_data *adap,
+ int ack)
+{
+ int sta = pca_get_con(adap);
+
+ sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA);
+
+ if (ack)
+ sta |= I2C_PCA_CON_AA;
+
+ pca_set_con(adap, sta);
+ return pca_wait(adap);
+}
+
+static int pca_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *msg = NULL;
+ int curmsg;
+ int numbytes = 0;
+ int state;
+ int ret;
+ int completed = 1;
+ unsigned long timeout = jiffies + i2c_adap->timeout;
+
+ while ((state = pca_status(adap)) != 0xf8) {
+ if (time_before(jiffies, timeout)) {
+ msleep(10);
+ } else {
+ dev_dbg(&i2c_adap->dev, "bus is not idle. status is "
+ "%#04x\n", state);
+ return -EBUSY;
+ }
+ }
+
+ DEB1("{{{ XFER %d messages\n", num);
+
+ if (i2c_debug >= 2) {
+ for (curmsg = 0; curmsg < num; curmsg++) {
+ int addr, i;
+ msg = &msgs[curmsg];
+
+ addr = (0x7f & msg->addr) ;
+
+ if (msg->flags & I2C_M_RD)
+ printk(KERN_INFO " [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
+ curmsg, msg->len, addr, (addr << 1) | 1);
+ else {
+ printk(KERN_INFO " [%02d] WR %d bytes to %#02x [%#02x%s",
+ curmsg, msg->len, addr, addr << 1,
+ msg->len == 0 ? "" : ", ");
+ for (i = 0; i < msg->len; i++)
+ printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", ");
+ printk("]\n");
+ }
+ }
+ }
+
+ curmsg = 0;
+ ret = -EIO;
+ while (curmsg < num) {
+ state = pca_status(adap);
+
+ DEB3("STATE is 0x%02x\n", state);
+ msg = &msgs[curmsg];
+
+ switch (state) {
+ case 0xf8: /* On reset or stop the bus is idle */
+ completed = pca_start(adap);
+ break;
+
+ case 0x08: /* A START condition has been transmitted */
+ case 0x10: /* A repeated start condition has been transmitted */
+ completed = pca_address(adap, msg);
+ break;
+
+ case 0x18: /* SLA+W has been transmitted; ACK has been received */
+ case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
+ if (numbytes < msg->len) {
+ completed = pca_tx_byte(adap,
+ msg->buf[numbytes]);
+ numbytes++;
+ break;
+ }
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ completed = pca_repeated_start(adap);
+ break;
+
+ case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after SLA+W\n");
+ pca_stop(adap);
+ ret = -ENXIO;
+ goto out;
+
+ case 0x40: /* SLA+R has been transmitted; ACK has been received */
+ completed = pca_rx_ack(adap, msg->len > 1);
+ break;
+
+ case 0x50: /* Data bytes has been received; ACK has been returned */
+ if (numbytes < msg->len) {
+ pca_rx_byte(adap, &msg->buf[numbytes], 1);
+ numbytes++;
+ completed = pca_rx_ack(adap,
+ numbytes < msg->len - 1);
+ break;
+ }
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ completed = pca_repeated_start(adap);
+ break;
+
+ case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after SLA+R\n");
+ pca_stop(adap);
+ ret = -ENXIO;
+ goto out;
+
+ case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
+ DEB2("NOT ACK received after data byte\n");
+ pca_stop(adap);
+ goto out;
+
+ case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
+ DEB2("Arbitration lost\n");
+ /*
+ * The PCA9564 data sheet (2006-09-01) says "A
+ * START condition will be transmitted when the
+ * bus becomes free (STOP or SCL and SDA high)"
+ * when the STA bit is set (p. 11).
+ *
+ * In case this won't work, try pca_reset()
+ * instead.
+ */
+ pca_start(adap);
+ goto out;
+
+ case 0x58: /* Data byte has been received; NOT ACK has been returned */
+ if (numbytes == msg->len - 1) {
+ pca_rx_byte(adap, &msg->buf[numbytes], 0);
+ curmsg++; numbytes = 0;
+ if (curmsg == num)
+ pca_stop(adap);
+ else
+ completed = pca_repeated_start(adap);
+ } else {
+ DEB2("NOT ACK sent after data byte received. "
+ "Not final byte. numbytes %d. len %d\n",
+ numbytes, msg->len);
+ pca_stop(adap);
+ goto out;
+ }
+ break;
+ case 0x70: /* Bus error - SDA stuck low */
+ DEB2("BUS ERROR - SDA Stuck low\n");
+ pca_reset(adap);
+ goto out;
+ case 0x90: /* Bus error - SCL stuck low */
+ DEB2("BUS ERROR - SCL Stuck low\n");
+ pca_reset(adap);
+ goto out;
+ case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
+ DEB2("BUS ERROR - Illegal START or STOP\n");
+ pca_reset(adap);
+ goto out;
+ default:
+ dev_err(&i2c_adap->dev, "unhandled SIO state 0x%02x\n", state);
+ break;
+ }
+
+ if (!completed)
+ goto out;
+ }
+
+ ret = curmsg;
+ out:
+ DEB1("}}} transferred %d/%d messages. "
+ "status is %#04x. control is %#04x\n",
+ curmsg, num, pca_status(adap),
+ pca_get_con(adap));
+ return ret;
+}
+
+static u32 pca_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm pca_algo = {
+ .master_xfer = pca_xfer,
+ .functionality = pca_func,
+};
+
+static unsigned int pca_probe_chip(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pca_data *pca_data = adap->algo_data;
+ /* The trick here is to check if there is an indirect register
+ * available. If there is one, we will read the value we first
+ * wrote on I2C_PCA_IADR. Otherwise, we will read the last value
+ * we wrote on I2C_PCA_ADR
+ */
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
+ pca_outw(pca_data, I2C_PCA_IND, 0xAA);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ITO);
+ pca_outw(pca_data, I2C_PCA_IND, 0x00);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
+ if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {
+ printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name);
+ return I2C_PCA_CHIP_9665;
+ } else {
+ printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name);
+ return I2C_PCA_CHIP_9564;
+ }
+}
+
+static int pca_init(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pca_data *pca_data = adap->algo_data;
+
+ adap->algo = &pca_algo;
+
+ if (pca_probe_chip(adap) == I2C_PCA_CHIP_9564) {
+ static int freqs[] = {330, 288, 217, 146, 88, 59, 44, 36};
+ int clock;
+
+ if (pca_data->i2c_clock > 7) {
+ switch (pca_data->i2c_clock) {
+ case 330000:
+ pca_data->i2c_clock = I2C_PCA_CON_330kHz;
+ break;
+ case 288000:
+ pca_data->i2c_clock = I2C_PCA_CON_288kHz;
+ break;
+ case 217000:
+ pca_data->i2c_clock = I2C_PCA_CON_217kHz;
+ break;
+ case 146000:
+ pca_data->i2c_clock = I2C_PCA_CON_146kHz;
+ break;
+ case 88000:
+ pca_data->i2c_clock = I2C_PCA_CON_88kHz;
+ break;
+ case 59000:
+ pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ break;
+ case 44000:
+ pca_data->i2c_clock = I2C_PCA_CON_44kHz;
+ break;
+ case 36000:
+ pca_data->i2c_clock = I2C_PCA_CON_36kHz;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Invalid I2C clock speed selected."
+ " Using default 59kHz.\n", adap->name);
+ pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ }
+ } else {
+ printk(KERN_WARNING "%s: "
+ "Choosing the clock frequency based on "
+ "index is deprecated."
+ " Use the nominal frequency.\n", adap->name);
+ }
+
+ pca_reset(pca_data);
+
+ clock = pca_clock(pca_data);
+ printk(KERN_INFO "%s: Clock frequency is %dkHz\n",
+ adap->name, freqs[clock]);
+
+ pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+ } else {
+ int clock;
+ int mode;
+ int tlow, thi;
+ /* Values can be found on PCA9665 datasheet section 7.3.2.6 */
+ int min_tlow, min_thi;
+ /* These values are the maximum raise and fall values allowed
+ * by the I2C operation mode (Standard, Fast or Fast+)
+ * They are used (added) below to calculate the clock dividers
+ * of PCA9665. Note that they are slightly different of the
+ * real maximum, to allow the change on mode exactly on the
+ * maximum clock rate for each mode
+ */
+ int raise_fall_time;
+
+ /* Ignore the reset function from the module,
+ * we can use the parallel bus reset
+ */
+ pca_data->reset_chip = pca9665_reset;
+
+ if (pca_data->i2c_clock > 1265800) {
+ printk(KERN_WARNING "%s: I2C clock speed too high."
+ " Using 1265.8kHz.\n", adap->name);
+ pca_data->i2c_clock = 1265800;
+ }
+
+ if (pca_data->i2c_clock < 60300) {
+ printk(KERN_WARNING "%s: I2C clock speed too low."
+ " Using 60.3kHz.\n", adap->name);
+ pca_data->i2c_clock = 60300;
+ }
+
+ /* To avoid integer overflow, use clock/100 for calculations */
+ clock = pca_clock(pca_data) / 100;
+
+ if (pca_data->i2c_clock > 10000) {
+ mode = I2C_PCA_MODE_TURBO;
+ min_tlow = 14;
+ min_thi = 5;
+ raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
+ } else if (pca_data->i2c_clock > 4000) {
+ mode = I2C_PCA_MODE_FASTP;
+ min_tlow = 17;
+ min_thi = 9;
+ raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
+ } else if (pca_data->i2c_clock > 1000) {
+ mode = I2C_PCA_MODE_FAST;
+ min_tlow = 44;
+ min_thi = 20;
+ raise_fall_time = 58; /* Raise 29e-8s, Fall 29e-8s */
+ } else {
+ mode = I2C_PCA_MODE_STD;
+ min_tlow = 157;
+ min_thi = 134;
+ raise_fall_time = 127; /* Raise 29e-8s, Fall 98e-8s */
+ }
+
+ /* The minimum clock that respects the thi/tlow = 134/157 is
+ * 64800 Hz. Below that, we have to fix the tlow to 255 and
+ * calculate the thi factor.
+ */
+ if (clock < 648) {
+ tlow = 255;
+ thi = 1000000 - clock * raise_fall_time;
+ thi /= (I2C_PCA_OSC_PER * clock) - tlow;
+ } else {
+ tlow = (1000000 - clock * raise_fall_time) * min_tlow;
+ tlow /= I2C_PCA_OSC_PER * clock * (min_thi + min_tlow);
+ thi = tlow * min_thi / min_tlow;
+ }
+
+ pca_reset(pca_data);
+
+ printk(KERN_INFO
+ "%s: Clock frequency is %dHz\n", adap->name, clock * 100);
+
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE);
+ pca_outw(pca_data, I2C_PCA_IND, mode);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
+ pca_outw(pca_data, I2C_PCA_IND, tlow);
+ pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
+ pca_outw(pca_data, I2C_PCA_IND, thi);
+
+ pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
+ }
+ udelay(500); /* 500 us for oscilator to stabilise */
+
+ return 0;
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pca_add_bus(struct i2c_adapter *adap)
+{
+ int rval;
+
+ rval = pca_init(adap);
+ if (rval)
+ return rval;
+
+ return i2c_add_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_bus);
+
+int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
+{
+ int rval;
+
+ rval = pca_init(adap);
+ if (rval)
+ return rval;
+
+ return i2c_add_numbered_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
+
+MODULE_AUTHOR("Ian Campbell , "
+ "Wolfram Sang ");
+MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, 0);
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.c b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.c
new file mode 100644
index 00000000..5c237952
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.c
@@ -0,0 +1,442 @@
+/*
+ * i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters
+ *
+ * Copyright (C) 1995-1997 Simon G. Vogl
+ * 1998-2000 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ *
+ * With some changes from Kyösti Mälkki and
+ * Frodo Looijaard , and also from Martin Bailey
+ *
+ *
+ * Partially rewriten by Oleg I. Vdovikin to handle multiple
+ * messages, proper stop/repstart signaling during receive, added detect code
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "i2c-algo-pcf.h"
+
+
+#define DEB2(x) if (i2c_debug >= 2) x
+#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */
+#define DEBPROTO(x) if (i2c_debug >= 9) x;
+ /* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 16
+
+/*
+ * module parameters:
+ */
+static int i2c_debug;
+
+/* setting states on the bus with the right timing: */
+
+#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
+#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl)
+#define get_own(adap) adap->getown(adap->data)
+#define get_clock(adap) adap->getclock(adap->data)
+#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
+#define i2c_inb(adap) adap->getpcf(adap->data, 0)
+
+/* other auxiliary functions */
+
+static void i2c_start(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk(KERN_DEBUG "S "));
+ set_pcf(adap, 1, I2C_PCF_START);
+}
+
+static void i2c_repstart(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk(" Sr "));
+ set_pcf(adap, 1, I2C_PCF_REPSTART);
+}
+
+static void i2c_stop(struct i2c_algo_pcf_data *adap)
+{
+ DEBPROTO(printk("P\n"));
+ set_pcf(adap, 1, I2C_PCF_STOP);
+}
+
+static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
+{
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+ *status));
+ /*
+ * Cleanup from LAB -- reset and enable ESO.
+ * This resets the PCF8584; since we've lost the bus, no
+ * further attempts should be made by callers to clean up
+ * (no i2c_stop() etc.)
+ */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ /*
+ * We pause for a time period sufficient for any running
+ * I2C transaction to complete -- the arbitration logic won't
+ * work properly until the next START is seen.
+ * It is assumed the bus driver or client has set a proper value.
+ *
+ * REVISIT: should probably use msleep instead of mdelay if we
+ * know we can sleep.
+ */
+ if (adap->lab_mdelay)
+ mdelay(adap->lab_mdelay);
+
+ DEB2(printk(KERN_INFO
+ "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
+ get_pcf(adap, 1)));
+}
+
+static int wait_for_bb(struct i2c_algo_pcf_data *adap)
+{
+
+ int timeout = DEF_TIMEOUT;
+ int status;
+
+ status = get_pcf(adap, 1);
+
+ while (!(status & I2C_PCF_BB) && --timeout) {
+ udelay(100); /* wait for 100 us */
+ status = get_pcf(adap, 1);
+ }
+
+ if (timeout == 0) {
+ printk(KERN_ERR "Timeout waiting for Bus Busy\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status)
+{
+
+ int timeout = DEF_TIMEOUT;
+
+ *status = get_pcf(adap, 1);
+
+ while ((*status & I2C_PCF_PIN) && --timeout) {
+ adap->waitforpin(adap->data);
+ *status = get_pcf(adap, 1);
+ }
+ if (*status & I2C_PCF_LAB) {
+ handle_lab(adap, status);
+ return -EINTR;
+ }
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/*
+ * This should perform the 'PCF8584 initialization sequence' as described
+ * in the Philips IC12 data book (1995, Aug 29).
+ * There should be a 30 clock cycle wait after reset, I assume this
+ * has been fulfilled.
+ * There should be a delay at the end equal to the longest I2C message
+ * to synchronize the BB-bit (in multimaster systems). How long is
+ * this? I assume 1 second is always long enough.
+ *
+ * vdovikin: added detect code for PCF8584
+ */
+static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+{
+ unsigned char temp;
+
+ DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n",
+ get_pcf(adap, 1)));
+
+ /* S1=0x80: S0 selected, serial interface off */
+ set_pcf(adap, 1, I2C_PCF_PIN);
+ /*
+ * check to see S1 now used as R/W ctrl -
+ * PCF8584 does that when ESO is zero
+ */
+ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+ return -ENXIO; /* definitely not PCF8584 */
+ }
+
+ /* load own address in S0, effective address is (own << 1) */
+ i2c_outb(adap, get_own(adap));
+ /* check it's really written */
+ if ((temp = i2c_inb(adap)) != get_own(adap)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* S1=0xA0, next byte in S2 */
+ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+ /* check to see S2 now selected */
+ if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* load clock register S2 */
+ i2c_outb(adap, get_clock(adap));
+ /* check it's really written, the only 5 lowest bits does matter */
+ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ /* Enable serial interface, idle, S0 selected */
+ set_pcf(adap, 1, I2C_PCF_IDLE);
+
+ /* check to see PCF is really idled and we can access status register */
+ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+ return -ENXIO;
+ }
+
+ printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
+
+ return 0;
+}
+
+static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+ int count, int last)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wrcount, status, timeout;
+
+ for (wrcount=0; wrcountdev, "i2c_write: writing %2.2X\n",
+ buf[wrcount] & 0xff));
+ i2c_outb(adap, buf[wrcount]);
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ if (timeout == -EINTR)
+ return -EINTR; /* arbitration lost */
+
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n");
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ }
+ if (last)
+ i2c_stop(adap);
+ else
+ i2c_repstart(adap);
+
+ return wrcount;
+}
+
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+ int count, int last)
+{
+ int i, status;
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ int wfp;
+
+ /* increment number of bytes to read by one -- read dummy byte */
+ for (i = 0; i <= count; i++) {
+
+ if ((wfp = wait_for_pin(adap, &status))) {
+ if (wfp == -EINTR)
+ return -EINTR; /* arbitration lost */
+
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
+ return -1;
+ }
+
+ if ((status & I2C_PCF_LRB) && (i != count)) {
+ i2c_stop(adap);
+ dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n");
+ return -1;
+ }
+
+ if (i == count - 1) {
+ set_pcf(adap, 1, I2C_PCF_ESO);
+ } else if (i == count) {
+ if (last)
+ i2c_stop(adap);
+ else
+ i2c_repstart(adap);
+ }
+
+ if (i)
+ buf[i - 1] = i2c_inb(adap);
+ else
+ i2c_inb(adap); /* dummy read */
+ }
+
+ return i - 1;
+}
+
+
+static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+ struct i2c_msg *msg)
+{
+ unsigned short flags = msg->flags;
+ unsigned char addr;
+
+ addr = msg->addr << 1;
+ if (flags & I2C_M_RD)
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+ i2c_outb(adap, addr);
+
+ return 0;
+}
+
+static int pcf_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i;
+ int ret=0, timeout, status;
+
+ if (adap->xfer_begin)
+ adap->xfer_begin(adap->data);
+
+ /* Check for bus busy */
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
+ "Timeout waiting for BB in pcf_xfer\n");)
+ i = -EIO;
+ goto out;
+ }
+
+ for (i = 0;ret >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: 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);)
+
+ ret = pcf_doAddress(adap, pmsg);
+
+ /* Send START */
+ if (i == 0)
+ i2c_start(adap);
+
+ /* Wait for PIN (pending interrupt NOT) */
+ timeout = wait_for_pin(adap, &status);
+ if (timeout) {
+ if (timeout == -EINTR) {
+ /* arbitration lost */
+ i = -EINTR;
+ goto out;
+ }
+ i2c_stop(adap);
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
+ "for PIN(1) in pcf_xfer\n");)
+ i = -EREMOTEIO;
+ goto out;
+ }
+
+ /* Check LRB (last rcvd bit - slave ack) */
+ if (status & I2C_PCF_LRB) {
+ i2c_stop(adap);
+ DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
+ i = -EREMOTEIO;
+ goto out;
+ }
+
+ DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+ i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+
+ if (pmsg->flags & I2C_M_RD) {
+ ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
+
+ if (ret != pmsg->len) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+ "only read %d bytes.\n",ret));
+ } else {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
+ }
+ } else {
+ ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+ (i + 1 == num));
+
+ if (ret != pmsg->len) {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+ "only wrote %d bytes.\n",ret));
+ } else {
+ DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+ }
+ }
+ }
+
+out:
+ if (adap->xfer_end)
+ adap->xfer_end(adap->data);
+ return i;
+}
+
+static u32 pcf_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* exported algorithm data: */
+static const struct i2c_algorithm pcf_algo = {
+ .master_xfer = pcf_xfer,
+ .functionality = pcf_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pcf_add_bus(struct i2c_adapter *adap)
+{
+ struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
+ int rval;
+
+ DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
+
+ /* register new adapter to i2c module... */
+ adap->algo = &pcf_algo;
+
+ if ((rval = pcf_init_8584(pcf_adap)))
+ return rval;
+
+ rval = i2c_add_adapter(adap);
+
+ return rval;
+}
+EXPORT_SYMBOL(i2c_pcf_add_bus);
+
+MODULE_AUTHOR("Hans Berglund ");
+MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff --git a/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.h b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.h
new file mode 100644
index 00000000..1ec703ee
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/algos/i2c-algo-pcf.h
@@ -0,0 +1,77 @@
+/* -------------------------------------------------------------------- */
+/* i2c-pcf8584.h: PCF 8584 global defines */
+/* -------------------------------------------------------------------- */
+/* Copyright (C) 1996 Simon G. Vogl
+ 1999 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA. */
+/* -------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard */
+
+#ifndef I2C_PCF8584_H
+#define I2C_PCF8584_H 1
+
+/* ----- Control register bits ---------------------------------------- */
+#define I2C_PCF_PIN 0x80
+#define I2C_PCF_ESO 0x40
+#define I2C_PCF_ES1 0x20
+#define I2C_PCF_ES2 0x10
+#define I2C_PCF_ENI 0x08
+#define I2C_PCF_STA 0x04
+#define I2C_PCF_STO 0x02
+#define I2C_PCF_ACK 0x01
+
+#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
+#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK)
+
+/* ----- Status register bits ----------------------------------------- */
+/*#define I2C_PCF_PIN 0x80 as above*/
+
+#define I2C_PCF_INI 0x40 /* 1 if not initialized */
+#define I2C_PCF_STS 0x20
+#define I2C_PCF_BER 0x10
+#define I2C_PCF_AD0 0x08
+#define I2C_PCF_LRB 0x08
+#define I2C_PCF_AAS 0x04
+#define I2C_PCF_LAB 0x02
+#define I2C_PCF_BB 0x01
+
+/* ----- Chip clock frequencies --------------------------------------- */
+#define I2C_PCF_CLK3 0x00
+#define I2C_PCF_CLK443 0x10
+#define I2C_PCF_CLK6 0x14
+#define I2C_PCF_CLK 0x18
+#define I2C_PCF_CLK12 0x1c
+
+/* ----- transmission frequencies ------------------------------------- */
+#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
+#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
+#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
+#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
+
+
+/* ----- Access to internal registers according to ES1,ES2 ------------ */
+/* they are mapped to the data port ( a0 = 0 ) */
+/* available when ESO == 0 : */
+
+#define I2C_PCF_OWNADR 0
+#define I2C_PCF_INTREG I2C_PCF_ES2
+#define I2C_PCF_CLKREG I2C_PCF_ES1
+
+#endif /* I2C_PCF8584_H */
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/Kconfig b/ANDROID_3.4.5/drivers/i2c/busses/Kconfig
new file mode 100644
index 00000000..d2c5095d
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/Kconfig
@@ -0,0 +1,910 @@
+#
+# Sensor device configuration
+#
+
+menu "I2C Hardware Bus support"
+
+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 && EXPERIMENTAL
+ 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 && EXPERIMENTAL
+ 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_I801
+ tristate "Intel 82801 (ICH/PCH)"
+ depends on PCI
+ select CHECK_SIGNATURE if X86 && DMI
+ 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)
+
+ 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_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
+ ATI SB800
+ AMD Hudson-2
+ Serverworks OSB4
+ Serverworks CSB5
+ Serverworks CSB6
+ Serverworks HT-1000
+ Serverworks HT-1100
+ SMSC Victory66
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-piix4.
+
+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 && EXPERIMENTAL
+ 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"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ SiS630 and SiS730 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 && EXPERIMENTAL
+ 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"
+ 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
+
+ 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 && EXPERIMENTAL
+ 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_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+ depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
+ This driver is BROKEN because the controller which it uses
+ will easily trigger RX overrun and TX underrun errors. Using
+ low I2C clock rates may partially work around those issues
+ on some systems. Another serious problem is that there is no
+ documented way to issue repeated START conditions, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+ unless your system can cope with those limitations.
+
+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_BLACKFIN_TWI
+ tristate "Blackfin TWI I2C support"
+ depends on BLACKFIN
+ depends on !BF561 && !BF531 && !BF532 && !BF533
+ help
+ This is the I2C bus driver for Blackfin on-chip TWI interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-bfin-twi.
+
+config I2C_BLACKFIN_TWI_CLK_KHZ
+ int "Blackfin TWI I2C clock (kHz)"
+ depends on I2C_BLACKFIN_TWI
+ range 21 400
+ default 50
+ help
+ The unit of the TWI clock is kHz.
+
+config I2C_CPM
+ tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
+ depends on (CPM1 || CPM2) && OF_I2C
+ 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
+ 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_PLATFORM
+ tristate "Synopsys DesignWare Platfrom"
+ depends on HAVE_CLK
+ 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-platform.
+
+config I2C_DESIGNWARE_PCI
+ tristate "Synopsys DesignWare PCI"
+ depends on PCI
+ 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_EG20T
+ tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
+ depends on PCI
+ 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_GPIO
+ tristate "GPIO-based bitbanging I2C"
+ depends on GENERIC_GPIO
+ 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_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_IMX
+ tristate "IMX I2C interface"
+ depends on ARCH_MXC
+ help
+ Say Y here if you want to use the IIC bus controller on
+ the Freescale i.MX/MXC processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-imx.
+
+config I2C_INTEL_MID
+ tristate "Intel Moorestown/Medfield Platform I2C controller"
+ depends on PCI
+ help
+ Say Y here if you have an Intel Moorestown/Medfield platform I2C
+ controller.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-intel-mid.
+
+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_IXP2000
+ tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP2000
+ select I2C_ALGOBIT
+ help
+ Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
+ system and are using GPIO lines for an I2C bus.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-ixp2000.
+
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
+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_MV64XXX
+ tristate "Marvell mv64xxx I2C Controller"
+ depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
+ 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 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
+ 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 PLAT_NOMADIK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
+
+config I2C_NUC900
+ tristate "NUC900 I2C Driver"
+ depends on ARCH_W90X900
+ help
+ Say Y here to include support for I2C controller in the
+ Winbond/Nuvoton NUC900 based System-on-Chip devices.
+
+config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+ depends on EXPERIMENTAL
+ 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
+ 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_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_PNX4008 || 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 || (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 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_S6000
+ tristate "S6000 I2C support"
+ depends on XTENSA_VARIANT_S6000
+ help
+ This driver supports the on chip I2C device on the
+ S6000 xtensa processor family.
+
+ To compile this driver as a module, choose M here. The module
+ will be called i2c-s6000.
+
+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 SUPERH || ARCH_SHMOBILE
+ 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_PRIMA2
+ 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_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_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_VERSATILE
+ tristate "ARM Versatile/Realview I2C bus support"
+ depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+ 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_OCTEON
+ tristate "Cavium OCTEON I2C bus support"
+ depends on CPU_CAVIUM_OCTEON
+ 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_XILINX
+ tristate "Xilinx I2C Controller"
+ depends on EXPERIMENTAL && 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 "XLR I2C support"
+ depends on CPU_XLR
+ help
+ This driver enables support for the on-chip I2C interface of
+ the Netlogic XLR/XLS MIPS processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-xlr.
+
+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_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_TAOS_EVM
+ tristate "TAOS evaluation module"
+ depends on EXPERIMENTAL
+ 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.
+
+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 && 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_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_STUB
+ tristate "I2C/SMBus Test Stub"
+ depends on EXPERIMENTAL && m
+ default 'n'
+ help
+ This module may be useful to developers of SMBus client drivers,
+ especially for certain kinds of sensor chips.
+
+ If you do build this module, be sure to read the notes and warnings
+ in .
+
+ If you don't know what to do here, definitely say N.
+
+config SCx200_I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+ depends on SCx200_GPIO
+ select I2C_ALGOBIT
+ help
+ Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+ 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_i2c.
+
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ (or scx200_acb) instead.
+
+config SCx200_I2C_SCL
+ int "GPIO pin used for SCL"
+ depends on SCx200_I2C
+ default "12"
+ help
+ Enter the GPIO pin number used for the SCL signal. This value can
+ also be specified with a module parameter.
+
+config SCx200_I2C_SDA
+ int "GPIO pin used for SDA"
+ depends on SCx200_I2C
+ default "13"
+ help
+ Enter the GPIO pin number used for the SSA signal. This value can
+ also be specified with a module parameter.
+
+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.
+
+endmenu
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/Makefile b/ANDROID_3.4.5/drivers/i2c/busses/Makefile
new file mode 100644
index 00000000..569567b0
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/Makefile
@@ -0,0 +1,91 @@
+#
+# 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_I801) += i2c-i801.o
+obj-$(CONFIG_I2C_ISCH) += i2c-isch.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_AT91) += i2c-at91.o
+obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
+obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
+i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o
+obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
+i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o
+obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
+obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
+obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
+obj-$(CONFIG_I2C_IMX) += i2c-imx.o
+obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o
+obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
+obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
+obj-$(CONFIG_I2C_MPC) += i2c-mpc.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_NUC900) += i2c-nuc900.o
+obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.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_S3C2410) += i2c-s3c2410.o
+obj-$(CONFIG_I2C_S6000) += i2c-s6000.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_STU300) += i2c-stu300.o
+obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
+obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
+obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
+obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
+
+# External I2C/SMBus adapter drivers
+obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
+obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
+obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
+obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
+
+# Other I2C/SMBus bus drivers
+obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
+obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
+obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-acorn.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-acorn.c
new file mode 100644
index 00000000..ed9f48d5
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-acorn.c
@@ -0,0 +1,96 @@
+/*
+ * linux/drivers/acorn/char/i2c.c
+ *
+ * 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.
+ *
+ * ARM IOC/IOMD i2c driver.
+ *
+ * On Acorn machines, the following i2c devices are on the bus:
+ * - PCF8583 real time clock & static RAM
+ */
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#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,
+ .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);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1535.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1535.c
new file mode 100644
index 00000000..e66d248f
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1535.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2000 Frodo Looijaard ,
+ * Philip Edelbrock ,
+ * Mark D. Studebaker ,
+ * Dan Eaton and
+ * Stephen Rousset
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* 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 __devinit 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 DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, ali1535_ids);
+
+static int __devinit 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 __devexit 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 = __devexit_p(ali1535_remove),
+};
+
+static int __init i2c_ali1535_init(void)
+{
+ return pci_register_driver(&ali1535_driver);
+}
+
+static void __exit i2c_ali1535_exit(void)
+{
+ pci_unregister_driver(&ali1535_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard , "
+ "Philip Edelbrock , "
+ "Mark D. Studebaker "
+ "and Dan Eaton ");
+MODULE_DESCRIPTION("ALI1535 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali1535_init);
+module_exit(i2c_ali1535_exit);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1563.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1563.c
new file mode 100644
index 00000000..47ae0091
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali1563.c
@@ -0,0 +1,448 @@
+/**
+ * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
+ *
+ * Copyright (C) 2004 Patrick Mochel
+ * 2005 Rudolf Marek
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+
+#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);
+ if ((error = ali1563_block_start(a)))
+ break;
+ } else {
+ if ((error = ali1563_block_start(a)))
+ 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--) {
+ if (!(reg = inb_p(SMB_HST_STS) & 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;
+ }
+
+ if ((error = ali1563_transaction(a, size)))
+ 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 __devinit 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 __devinit ali1563_probe(struct pci_dev * dev,
+ const struct pci_device_id * id_table)
+{
+ int error;
+
+ if ((error = ali1563_setup(dev)))
+ goto exit;
+ ali1563_adapter.dev.parent = &dev->dev;
+ snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
+ "SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
+ if ((error = i2c_add_adapter(&ali1563_adapter)))
+ 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 __devexit ali1563_remove(struct pci_dev * dev)
+{
+ i2c_del_adapter(&ali1563_adapter);
+ ali1563_shutdown(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(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 = __devexit_p(ali1563_remove),
+};
+
+static int __init ali1563_init(void)
+{
+ return pci_register_driver(&ali1563_pci_driver);
+}
+
+module_init(ali1563_init);
+
+static void __exit ali1563_exit(void)
+{
+ pci_unregister_driver(&ali1563_pci_driver);
+}
+
+module_exit(ali1563_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali15x3.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali15x3.c
new file mode 100644
index 00000000..087ea9ca
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-ali15x3.c
@@ -0,0 +1,533 @@
+/*
+ Copyright (c) 1999 Frodo Looijaard and
+ Philip Edelbrock and
+ Mark D. Studebaker
+
+ 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* 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(force_addr, ushort, 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 __devinit 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 DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, ali15x3_ids);
+
+static int __devinit 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 __devexit 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 = __devexit_p(ali15x3_remove),
+};
+
+static int __init i2c_ali15x3_init(void)
+{
+ return pci_register_driver(&ali15x3_driver);
+}
+
+static void __exit i2c_ali15x3_exit(void)
+{
+ pci_unregister_driver(&ali15x3_driver);
+}
+
+MODULE_AUTHOR ("Frodo Looijaard , "
+ "Philip Edelbrock , "
+ "and Mark D. Studebaker ");
+MODULE_DESCRIPTION("ALI15X3 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali15x3_init);
+module_exit(i2c_ali15x3_exit);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756-s4882.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756-s4882.c
new file mode 100644
index 00000000..378fcb5d
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -0,0 +1,262 @@
+/*
+ * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
+ *
+ * Copyright (C) 2004, 2008 Jean Delvare
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+
+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 */
+ error = i2c_del_adapter(&amd756_smbus);
+ if (error) {
+ dev_err(&amd756_smbus.dev, "Physical bus removal failed\n");
+ goto ERROR0;
+ }
+
+ printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
+ /* Define the 5 virtual adapters and algorithms structures */
+ if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter),
+ GFP_KERNEL))) {
+ error = -ENOMEM;
+ goto ERROR1;
+ }
+ if (!(s4882_algo = kzalloc(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 ");
+MODULE_DESCRIPTION("S4882 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(amd756_s4882_init);
+module_exit(amd756_s4882_exit);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756.c
new file mode 100644
index 00000000..eb778bf1
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd756.c
@@ -0,0 +1,430 @@
+/*
+ Copyright (c) 1999-2002 Merlin Hughes
+
+ Shamelessly ripped from i2c-piix4.c:
+
+ Copyright (c) 1998, 1999 Frodo Looijaard and
+ Philip Edelbrock
+
+ 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* 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 DEFINE_PCI_DEVICE_TABLE(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 __devinit 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) {
+ dev_err(&pdev->dev,
+ "Adapter registration failed, module not inserted\n");
+ goto out_err;
+ }
+
+ return 0;
+
+ out_err:
+ release_region(amd756_ioport, SMB_IOSIZE);
+ return error;
+}
+
+static void __devexit 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 = __devexit_p(amd756_remove),
+};
+
+static int __init amd756_init(void)
+{
+ return pci_register_driver(&amd756_driver);
+}
+
+static void __exit amd756_exit(void)
+{
+ pci_unregister_driver(&amd756_driver);
+}
+
+MODULE_AUTHOR("Merlin Hughes ");
+MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(amd756_smbus);
+
+module_init(amd756_init)
+module_exit(amd756_exit)
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd8111.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd8111.c
new file mode 100644
index 00000000..e5ac53b9
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-amd8111.c
@@ -0,0 +1,505 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Vojtech Pavlik ");
+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);
+ 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 DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd8111_ids);
+
+static int __devinit 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 __devexit 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 = __devexit_p(amd8111_remove),
+};
+
+static int __init i2c_amd8111_init(void)
+{
+ return pci_register_driver(&amd8111_driver);
+}
+
+static void __exit i2c_amd8111_exit(void)
+{
+ pci_unregister_driver(&amd8111_driver);
+}
+
+module_init(i2c_amd8111_init);
+module_exit(i2c_amd8111_exit);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-at91.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 00000000..1679deef
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,314 @@
+/*
+ i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+
+ Copyright (C) 2004 Rick Bronson
+ Converted to 2.6 by Andrew Victor
+
+ Borrowed heavily from original work by:
+ Copyright (C) 2000 Philip Edelbrock
+
+ 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+
+
+static struct clk *twi_clk;
+static void __iomem *twi_base;
+
+#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
+#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+
+
+/*
+ * Initialize the TWI hardware registers.
+ */
+static void __devinit at91_twi_hwinit(void)
+{
+ unsigned long cdiv, ckdiv;
+
+ at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
+
+ /* Calcuate clock dividers */
+ cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+ cdiv = cdiv + 1; /* round up */
+ ckdiv = 0;
+ while (cdiv > 255) {
+ ckdiv++;
+ cdiv = cdiv >> 1;
+ }
+
+ if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
+ if (ckdiv > 5) {
+ printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+ ckdiv = 5;
+ }
+ }
+
+ at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+}
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short at91_poll_status(unsigned long bit)
+{
+ int loop_cntr = 10000;
+
+ do {
+ udelay(10);
+ } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+
+ return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ /* Read data */
+ while (length--) {
+ if (!length) /* need to send Stop before reading last byte */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+ if (!at91_poll_status(AT91_TWI_RXRDY)) {
+ dev_dbg(&adap->dev, "RXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+ *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+ }
+
+ return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+ /* Load first byte into transmitter */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+
+ /* Send Start */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+ do {
+ if (!at91_poll_status(AT91_TWI_TXRDY)) {
+ dev_dbg(&adap->dev, "TXRDY timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ length--; /* byte was transmitted */
+
+ if (length > 0) /* more data to send? */
+ at91_twi_write(AT91_TWI_THR, *buf++);
+ } while (length);
+
+ /* Send Stop */
+ at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ * Note: We do not use Atmel's feature of storing the "internal device address".
+ * Instead the "internal device address" has to be written using a separate
+ * i2c message.
+ * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+ */
+static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+ int i, ret;
+
+ dev_dbg(&adap->dev, "at91_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);
+
+ at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+ | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+ 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;
+
+ /* Wait until transfer is finished */
+ if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+ dev_dbg(&adap->dev, "TXCOMP timeout\n");
+ return -ETIMEDOUT;
+ }
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+ return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 at91_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm at91_algorithm = {
+ .master_xfer = at91_xfer,
+ .functionality = at91_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit at91_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter;
+ struct resource *res;
+ int rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
+ return -EBUSY;
+
+ twi_base = ioremap(res->start, resource_size(res));
+ if (!twi_base) {
+ rc = -ENOMEM;
+ goto fail0;
+ }
+
+ twi_clk = clk_get(NULL, "twi_clk");
+ if (IS_ERR(twi_clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ rc = -ENODEV;
+ goto fail1;
+ }
+
+ adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ dev_err(&pdev->dev, "can't allocate inteface!\n");
+ rc = -ENOMEM;
+ goto fail2;
+ }
+ snprintf(adapter->name, sizeof(adapter->name), "AT91");
+ adapter->algo = &at91_algorithm;
+ adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = &pdev->dev;
+ /* adapter->id == 0 ... only one TWI controller for now */
+
+ platform_set_drvdata(pdev, adapter);
+
+ clk_enable(twi_clk); /* enable peripheral clock */
+ at91_twi_hwinit(); /* initialize TWI controller */
+
+ rc = i2c_add_numbered_adapter(adapter);
+ if (rc) {
+ dev_err(&pdev->dev, "Adapter %s registration failed\n",
+ adapter->name);
+ goto fail3;
+ }
+
+ dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+ return 0;
+
+fail3:
+ platform_set_drvdata(pdev, NULL);
+ kfree(adapter);
+ clk_disable(twi_clk);
+fail2:
+ clk_put(twi_clk);
+fail1:
+ iounmap(twi_base);
+fail0:
+ release_mem_region(res->start, resource_size(res));
+
+ return rc;
+}
+
+static int __devexit at91_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+ struct resource *res;
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ platform_set_drvdata(pdev, NULL);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(twi_base);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_disable(twi_clk); /* disable peripheral clock */
+ clk_put(twi_clk);
+
+ return rc;
+}
+
+#ifdef CONFIG_PM
+
+/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+
+static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ clk_disable(twi_clk);
+ return 0;
+}
+
+static int at91_i2c_resume(struct platform_device *pdev)
+{
+ return clk_enable(twi_clk);
+}
+
+#else
+#define at91_i2c_suspend NULL
+#define at91_i2c_resume NULL
+#endif
+
+static struct platform_driver at91_i2c_driver = {
+ .probe = at91_i2c_probe,
+ .remove = __devexit_p(at91_i2c_remove),
+ .suspend = at91_i2c_suspend,
+ .resume = at91_i2c_resume,
+ .driver = {
+ .name = "at91_i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(at91_i2c_driver);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-au1550.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-au1550.c
new file mode 100644
index 00000000..582d616d
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-au1550.c
@@ -0,0 +1,434 @@
+/*
+ * i2c-au1550.c: SMBus (i2c) adapter for Alchemy PSC interface
+ * Copyright (C) 2004 Embedded Edge, LLC
+ *
+ * 2.6 port by Matt Porter
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#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;
+ struct resource *ioarea;
+};
+
+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(15) | \
+ PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
+ PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
+ PSC_SMBTMR_SET_CH(15));
+
+ 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 __devinit
+i2c_au1550_probe(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv;
+ struct resource *r;
+ int ret;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ priv->ioarea = request_mem_region(r->start, resource_size(r),
+ pdev->name);
+ if (!priv->ioarea) {
+ ret = -EBUSY;
+ goto out_mem;
+ }
+
+ priv->psc_base = ioremap(r->start, resource_size(r));
+ if (!priv->psc_base) {
+ ret = -EIO;
+ goto out_map;
+ }
+ 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 == 0) {
+ platform_set_drvdata(pdev, priv);
+ return 0;
+ }
+
+ i2c_au1550_disable(priv);
+ iounmap(priv->psc_base);
+out_map:
+ release_resource(priv->ioarea);
+ kfree(priv->ioarea);
+out_mem:
+ kfree(priv);
+out:
+ return ret;
+}
+
+static int __devexit i2c_au1550_remove(struct platform_device *pdev)
+{
+ struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&priv->adap);
+ i2c_au1550_disable(priv);
+ iounmap(priv->psc_base);
+ release_resource(priv->ioarea);
+ kfree(priv->ioarea);
+ kfree(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",
+ .owner = THIS_MODULE,
+ .pm = AU1XPSC_SMBUS_PMOPS,
+ },
+ .probe = i2c_au1550_probe,
+ .remove = __devexit_p(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/ANDROID_3.4.5/drivers/i2c/busses/i2c-bfin-twi.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-bfin-twi.c
new file mode 100644
index 00000000..cdb59e5b
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-bfin-twi.c
@@ -0,0 +1,797 @@
+/*
+ * Blackfin On-Chip Two Wire Interface Driver
+ *
+ * Copyright 2005-2007 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+/* SMBus mode*/
+#define TWI_I2C_MODE_STANDARD 1
+#define TWI_I2C_MODE_STANDARDSUB 2
+#define TWI_I2C_MODE_COMBINED 3
+#define TWI_I2C_MODE_REPEAT 4
+
+struct bfin_twi_iface {
+ int irq;
+ spinlock_t lock;
+ char read_write;
+ u8 command;
+ u8 *transPtr;
+ int readNum;
+ int writeNum;
+ int cur_mode;
+ int manual_stop;
+ int result;
+ struct i2c_adapter adap;
+ struct completion complete;
+ struct i2c_msg *pmsg;
+ int msg_num;
+ int cur_msg;
+ u16 saved_clkdiv;
+ u16 saved_control;
+ void __iomem *regs_base;
+};
+
+
+#define DEFINE_TWI_REG(reg, off) \
+static inline u16 read_##reg(struct bfin_twi_iface *iface) \
+ { return bfin_read16(iface->regs_base + (off)); } \
+static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
+ { bfin_write16(iface->regs_base + (off), v); }
+
+DEFINE_TWI_REG(CLKDIV, 0x00)
+DEFINE_TWI_REG(CONTROL, 0x04)
+DEFINE_TWI_REG(SLAVE_CTL, 0x08)
+DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
+DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
+DEFINE_TWI_REG(MASTER_CTL, 0x14)
+DEFINE_TWI_REG(MASTER_STAT, 0x18)
+DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
+DEFINE_TWI_REG(INT_STAT, 0x20)
+DEFINE_TWI_REG(INT_MASK, 0x24)
+DEFINE_TWI_REG(FIFO_CTL, 0x28)
+DEFINE_TWI_REG(FIFO_STAT, 0x2C)
+DEFINE_TWI_REG(XMT_DATA8, 0x80)
+DEFINE_TWI_REG(XMT_DATA16, 0x84)
+DEFINE_TWI_REG(RCV_DATA8, 0x88)
+DEFINE_TWI_REG(RCV_DATA16, 0x8C)
+
+static const u16 pin_req[2][3] = {
+ {P_TWI0_SCL, P_TWI0_SDA, 0},
+ {P_TWI1_SCL, P_TWI1_SDA, 0},
+};
+
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
+ unsigned short twi_int_status)
+{
+ unsigned short mast_stat = read_MASTER_STAT(iface);
+
+ if (twi_int_status & XMTSERV) {
+ /* Transmit next data */
+ if (iface->writeNum > 0) {
+ SSYNC();
+ write_XMT_DATA8(iface, *(iface->transPtr++));
+ iface->writeNum--;
+ }
+ /* start receive immediately after complete sending in
+ * combine mode.
+ */
+ else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | MDIR | RSTART);
+ else if (iface->manual_stop)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg + 1 < iface->msg_num) {
+ if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | RSTART | MDIR);
+ else
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+ }
+ }
+ if (twi_int_status & RCVSERV) {
+ if (iface->readNum > 0) {
+ /* Receive next data */
+ *(iface->transPtr) = read_RCV_DATA8(iface);
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ /* Change combine mode into sub mode after
+ * read first data.
+ */
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ /* Get read number from first byte in block
+ * combine mode.
+ */
+ if (iface->readNum == 1 && iface->manual_stop)
+ iface->readNum = *iface->transPtr + 1;
+ }
+ iface->transPtr++;
+ iface->readNum--;
+ } else if (iface->manual_stop) {
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg + 1 < iface->msg_num) {
+ if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | RSTART | MDIR);
+ else
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+ }
+ }
+ if (twi_int_status & MERR) {
+ write_INT_MASK(iface, 0);
+ write_MASTER_STAT(iface, 0x3e);
+ write_MASTER_CTL(iface, 0);
+ iface->result = -EIO;
+
+ if (mast_stat & LOSTARB)
+ dev_dbg(&iface->adap.dev, "Lost Arbitration\n");
+ if (mast_stat & ANAK)
+ dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n");
+ if (mast_stat & DNAK)
+ dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n");
+ if (mast_stat & BUFRDERR)
+ dev_dbg(&iface->adap.dev, "Buffer Read Error\n");
+ if (mast_stat & BUFWRERR)
+ dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
+
+ /* Faulty slave devices, may drive SDA low after a transfer
+ * finishes. To release the bus this code generates up to 9
+ * extra clocks until SDA is released.
+ */
+
+ if (read_MASTER_STAT(iface) & SDASEN) {
+ int cnt = 9;
+ do {
+ write_MASTER_CTL(iface, SCLOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, 0);
+ udelay(6);
+ } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--);
+
+ write_MASTER_CTL(iface, SDAOVR | SCLOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, SDAOVR);
+ udelay(6);
+ write_MASTER_CTL(iface, 0);
+ }
+
+ /* If it is a quick transfer, only address without data,
+ * not an err, return 1.
+ */
+ if (iface->cur_mode == TWI_I2C_MODE_STANDARD &&
+ iface->transPtr == NULL &&
+ (twi_int_status & MCOMP) && (mast_stat & DNAK))
+ iface->result = 1;
+
+ complete(&iface->complete);
+ return;
+ }
+ if (twi_int_status & MCOMP) {
+ if ((read_MASTER_CTL(iface) & MEN) == 0 &&
+ (iface->cur_mode == TWI_I2C_MODE_REPEAT ||
+ iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
+ iface->result = -1;
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
+ } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ if (iface->readNum == 0) {
+ /* set the read number to 1 and ask for manual
+ * stop in block combine mode
+ */
+ iface->readNum = 1;
+ iface->manual_stop = 1;
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | (0xff << 6));
+ } else {
+ /* set the readd number in other
+ * combine mode.
+ */
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) &
+ (~(0xff << 6))) |
+ (iface->readNum << 6));
+ }
+ /* remove restart bit and enable master receive */
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) & ~RSTART);
+ } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg+1 < iface->msg_num) {
+ iface->cur_msg++;
+ iface->transPtr = iface->pmsg[iface->cur_msg].buf;
+ iface->writeNum = iface->readNum =
+ iface->pmsg[iface->cur_msg].len;
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface,
+ iface->pmsg[iface->cur_msg].addr);
+ if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface,
+ *(iface->transPtr++));
+ iface->writeNum--;
+ }
+ }
+
+ if (iface->pmsg[iface->cur_msg].len <= 255)
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) &
+ (~(0xff << 6))) |
+ (iface->pmsg[iface->cur_msg].len << 6));
+ else {
+ write_MASTER_CTL(iface,
+ (read_MASTER_CTL(iface) |
+ (0xff << 6)));
+ iface->manual_stop = 1;
+ }
+ /* remove restart bit and enable master receive */
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) & ~RSTART);
+ } else {
+ iface->result = 1;
+ write_INT_MASK(iface, 0);
+ write_MASTER_CTL(iface, 0);
+ }
+ }
+ complete(&iface->complete);
+}
+
+/* Interrupt handler */
+static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
+{
+ struct bfin_twi_iface *iface = dev_id;
+ unsigned long flags;
+ unsigned short twi_int_status;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ while (1) {
+ twi_int_status = read_INT_STAT(iface);
+ if (!twi_int_status)
+ break;
+ /* Clear interrupt status */
+ write_INT_STAT(iface, twi_int_status);
+ bfin_twi_handle_interrupt(iface, twi_int_status);
+ SSYNC();
+ }
+ spin_unlock_irqrestore(&iface->lock, flags);
+ return IRQ_HANDLED;
+}
+
+/*
+ * One i2c master transfer
+ */
+static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ struct i2c_msg *pmsg;
+ int rc = 0;
+
+ if (!(read_CONTROL(iface) & TWI_ENA))
+ return -ENXIO;
+
+ while (read_MASTER_STAT(iface) & BUSBUSY)
+ yield();
+
+ iface->pmsg = msgs;
+ iface->msg_num = num;
+ iface->cur_msg = 0;
+
+ pmsg = &msgs[0];
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&adap->dev, "10 bits addr not supported!\n");
+ return -EINVAL;
+ }
+
+ iface->cur_mode = TWI_I2C_MODE_REPEAT;
+ iface->manual_stop = 0;
+ iface->transPtr = pmsg->buf;
+ iface->writeNum = iface->readNum = pmsg->len;
+ iface->result = 0;
+ init_completion(&(iface->complete));
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface, pmsg->addr);
+
+ /* FIFO Initiation. Data in FIFO should be
+ * discarded before start a new operation.
+ */
+ write_FIFO_CTL(iface, 0x3);
+ SSYNC();
+ write_FIFO_CTL(iface, 0);
+ SSYNC();
+
+ if (pmsg->flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface, *(iface->transPtr++));
+ iface->writeNum--;
+ SSYNC();
+ }
+ }
+
+ /* clear int stat */
+ write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
+
+ /* Interrupt mask . Enable XMT, RCV interrupt */
+ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();
+
+ if (pmsg->len <= 255)
+ write_MASTER_CTL(iface, pmsg->len << 6);
+ else {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ }
+
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ SSYNC();
+
+ while (!iface->result) {
+ if (!wait_for_completion_timeout(&iface->complete,
+ adap->timeout)) {
+ iface->result = -1;
+ dev_err(&adap->dev, "master transfer timeout\n");
+ }
+ }
+
+ if (iface->result == 1)
+ rc = iface->cur_msg + 1;
+ else
+ rc = iface->result;
+
+ return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ return bfin_twi_do_master_xfer(adap, msgs, num);
+}
+
+/*
+ * One I2C SMBus transfer
+ */
+int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ int rc = 0;
+
+ if (!(read_CONTROL(iface) & TWI_ENA))
+ return -ENXIO;
+
+ while (read_MASTER_STAT(iface) & BUSBUSY)
+ yield();
+
+ iface->writeNum = 0;
+ iface->readNum = 0;
+
+ /* Prepare datas & select mode */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ iface->transPtr = NULL;
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (data == NULL)
+ iface->transPtr = NULL;
+ else {
+ if (read_write == I2C_SMBUS_READ)
+ iface->readNum = 1;
+ else
+ iface->writeNum = 1;
+ iface->transPtr = &data->byte;
+ }
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = &data->byte;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ iface->writeNum = 2;
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 0;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = data->block[0] + 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = data->block;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = data->block[0];
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = data->block[0];
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = (u8 *)&data->block[1];
+ break;
+ default:
+ return -1;
+ }
+
+ iface->result = 0;
+ iface->manual_stop = 0;
+ iface->read_write = read_write;
+ iface->command = command;
+ init_completion(&(iface->complete));
+
+ /* FIFO Initiation. Data in FIFO should be discarded before
+ * start a new operation.
+ */
+ write_FIFO_CTL(iface, 0x3);
+ SSYNC();
+ write_FIFO_CTL(iface, 0);
+
+ /* clear int stat */
+ write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
+
+ /* Set Transmit device address */
+ write_MASTER_ADDR(iface, addr);
+ SSYNC();
+
+ switch (iface->cur_mode) {
+ case TWI_I2C_MODE_STANDARDSUB:
+ write_XMT_DATA8(iface, iface->command);
+ write_INT_MASK(iface, MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ if (iface->writeNum + 1 <= 255)
+ write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
+ else {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ }
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ case TWI_I2C_MODE_COMBINED:
+ write_XMT_DATA8(iface, iface->command);
+ write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();
+
+ if (iface->writeNum > 0)
+ write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
+ else
+ write_MASTER_CTL(iface, 0x1 << 6);
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ default:
+ write_MASTER_CTL(iface, 0);
+ if (size != I2C_SMBUS_QUICK) {
+ /* Don't access xmit data register when this is a
+ * read operation.
+ */
+ if (iface->read_write != I2C_SMBUS_READ) {
+ if (iface->writeNum > 0) {
+ write_XMT_DATA8(iface,
+ *(iface->transPtr++));
+ if (iface->writeNum <= 255)
+ write_MASTER_CTL(iface,
+ iface->writeNum << 6);
+ else {
+ write_MASTER_CTL(iface,
+ 0xff << 6);
+ iface->manual_stop = 1;
+ }
+ iface->writeNum--;
+ } else {
+ write_XMT_DATA8(iface, iface->command);
+ write_MASTER_CTL(iface, 1 << 6);
+ }
+ } else {
+ if (iface->readNum > 0 && iface->readNum <= 255)
+ write_MASTER_CTL(iface,
+ iface->readNum << 6);
+ else if (iface->readNum > 255) {
+ write_MASTER_CTL(iface, 0xff << 6);
+ iface->manual_stop = 1;
+ } else
+ break;
+ }
+ }
+ write_INT_MASK(iface, MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ /* Master enable */
+ write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ break;
+ }
+ SSYNC();
+
+ while (!iface->result) {
+ if (!wait_for_completion_timeout(&iface->complete,
+ adap->timeout)) {
+ iface->result = -1;
+ dev_err(&adap->dev, "smbus transfer timeout\n");
+ }
+ }
+
+ rc = (iface->result >= 0) ? 0 : -1;
+
+ return rc;
+}
+
+/*
+ * Generic I2C SMBus transfer entrypoint
+ */
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ return bfin_twi_do_smbus_xfer(adap, addr, flags,
+ read_write, command, size, data);
+}
+
+/*
+ * Return what the adapter supports
+ */
+static u32 bfin_twi_functionality(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_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static struct i2c_algorithm bfin_twi_algorithm = {
+ .master_xfer = bfin_twi_master_xfer,
+ .smbus_xfer = bfin_twi_smbus_xfer,
+ .functionality = bfin_twi_functionality,
+};
+
+static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ iface->saved_clkdiv = read_CLKDIV(iface);
+ iface->saved_control = read_CONTROL(iface);
+
+ free_irq(iface->irq, iface);
+
+ /* Disable TWI */
+ write_CONTROL(iface, iface->saved_control & ~TWI_ENA);
+
+ return 0;
+}
+
+static int i2c_bfin_twi_resume(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ 0, pdev->name, iface);
+ if (rc) {
+ dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+ return -ENODEV;
+ }
+
+ /* Resume TWI interface clock as specified */
+ write_CLKDIV(iface, iface->saved_clkdiv);
+
+ /* Resume TWI */
+ write_CONTROL(iface, iface->saved_control);
+
+ return 0;
+}
+
+static int i2c_bfin_twi_probe(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface;
+ struct i2c_adapter *p_adap;
+ struct resource *res;
+ int rc;
+ unsigned int clkhilow;
+
+ iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
+ if (!iface) {
+ dev_err(&pdev->dev, "Cannot allocate memory\n");
+ rc = -ENOMEM;
+ goto out_error_nomem;
+ }
+
+ spin_lock_init(&(iface->lock));
+
+ /* Find and map our resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+ rc = -ENOENT;
+ goto out_error_get_res;
+ }
+
+ iface->regs_base = ioremap(res->start, resource_size(res));
+ if (iface->regs_base == NULL) {
+ dev_err(&pdev->dev, "Cannot map IO\n");
+ rc = -ENXIO;
+ goto out_error_ioremap;
+ }
+
+ iface->irq = platform_get_irq(pdev, 0);
+ if (iface->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ specified\n");
+ rc = -ENOENT;
+ goto out_error_no_irq;
+ }
+
+ p_adap = &iface->adap;
+ p_adap->nr = pdev->id;
+ strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
+ p_adap->algo = &bfin_twi_algorithm;
+ p_adap->algo_data = iface;
+ p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ p_adap->dev.parent = &pdev->dev;
+ p_adap->timeout = 5 * HZ;
+ p_adap->retries = 3;
+
+ rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
+ if (rc) {
+ dev_err(&pdev->dev, "Can't setup pin mux!\n");
+ goto out_error_pin_mux;
+ }
+
+ rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ 0, pdev->name, iface);
+ if (rc) {
+ dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+ rc = -ENODEV;
+ goto out_error_req_irq;
+ }
+
+ /* Set TWI internal clock as 10MHz */
+ write_CONTROL(iface, ((get_sclk() / 1000 / 1000 + 5) / 10) & 0x7F);
+
+ /*
+ * We will not end up with a CLKDIV=0 because no one will specify
+ * 20kHz SCL or less in Kconfig now. (5 * 1000 / 20 = 250)
+ */
+ clkhilow = ((10 * 1000 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) + 1) / 2;
+
+ /* Set Twi interface clock as specified */
+ write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
+
+ /* Enable TWI */
+ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
+ SSYNC();
+
+ rc = i2c_add_numbered_adapter(p_adap);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Can't add i2c adapter!\n");
+ goto out_error_add_adapter;
+ }
+
+ platform_set_drvdata(pdev, iface);
+
+ dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+ "regs_base@%p\n", iface->regs_base);
+
+ return 0;
+
+out_error_add_adapter:
+ free_irq(iface->irq, iface);
+out_error_req_irq:
+out_error_no_irq:
+ peripheral_free_list(pin_req[pdev->id]);
+out_error_pin_mux:
+ iounmap(iface->regs_base);
+out_error_ioremap:
+out_error_get_res:
+ kfree(iface);
+out_error_nomem:
+ return rc;
+}
+
+static int i2c_bfin_twi_remove(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&(iface->adap));
+ free_irq(iface->irq, iface);
+ peripheral_free_list(pin_req[pdev->id]);
+ iounmap(iface->regs_base);
+ kfree(iface);
+
+ return 0;
+}
+
+static struct platform_driver i2c_bfin_twi_driver = {
+ .probe = i2c_bfin_twi_probe,
+ .remove = i2c_bfin_twi_remove,
+ .suspend = i2c_bfin_twi_suspend,
+ .resume = i2c_bfin_twi_resume,
+ .driver = {
+ .name = "i2c-bfin-twi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_bfin_twi_init(void)
+{
+ return platform_driver_register(&i2c_bfin_twi_driver);
+}
+
+static void __exit i2c_bfin_twi_exit(void)
+{
+ platform_driver_unregister(&i2c_bfin_twi_driver);
+}
+
+subsys_initcall(i2c_bfin_twi_init);
+module_exit(i2c_bfin_twi_exit);
+
+MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-bfin-twi");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-cpm.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-cpm.c
new file mode 100644
index 00000000..c1e1096b
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-cpm.c
@@ -0,0 +1,731 @@
+/*
+ * 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
+ *
+ * Converted to of_platform_device. Renamed to i2c-cpm.c.
+ * (C) 2007,2008 Jochen Friedrich
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* 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 */
+};
+
+#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];
+ u32 txdma[CPM_MAXBD];
+ u32 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 = pmsg->addr << 1;
+ if (pmsg->flags & I2C_M_RD)
+ addr |= 1;
+
+ 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, i;
+ int tptr;
+ int rptr;
+ cbd_t __iomem *tbdf;
+ cbd_t __iomem *rbdf;
+
+ if (num > CPM_MAXBD)
+ return -EINVAL;
+
+ /* Check if we have any oversized READ requests */
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ if (pmsg->len >= CPM_MAX_READ)
+ return -EINVAL;
+ }
+
+ /* Reset to use first buffer */
+ out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
+ out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
+
+ tbdf = cpm->tbase;
+ rbdf = cpm->rbase;
+
+ tptr = 0;
+ rptr = 0;
+
+ 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,
+};
+
+static const struct i2c_adapter cpm_ops = {
+ .owner = THIS_MODULE,
+ .name = "i2c-cpm",
+ .algo = &cpm_i2c_algo,
+};
+
+static int __devinit 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 = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+ 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 __devinit 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;
+
+ dev_set_drvdata(&ofdev->dev, 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) {
+ dev_err(&ofdev->dev, "Unable to register with I2C\n");
+ goto out_shut;
+ }
+
+ dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
+ cpm->adap.name);
+
+ /*
+ * register OF I2C devices
+ */
+ of_i2c_register_devices(&cpm->adap);
+
+ return 0;
+out_shut:
+ cpm_i2c_shutdown(cpm);
+out_free:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(cpm);
+
+ return result;
+}
+
+static int __devexit cpm_i2c_remove(struct platform_device *ofdev)
+{
+ struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
+
+ i2c_del_adapter(&cpm->adap);
+
+ cpm_i2c_shutdown(cpm);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+ 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 = __devexit_p(cpm_i2c_remove),
+ .driver = {
+ .name = "fsl-i2c-cpm",
+ .owner = THIS_MODULE,
+ .of_match_table = cpm_i2c_match,
+ },
+};
+
+module_platform_driver(cpm_i2c_driver);
+
+MODULE_AUTHOR("Jochen Friedrich ");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-davinci.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 00000000..79b4bcb3
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,830 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define DAVINCI_I2C_MAX_TRIES 2
+#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \
+ 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_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)
+
+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 completion xfr_complete;
+ struct notifier_block freq_transition;
+#endif
+};
+
+/* 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)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+/* Generate a pulse on the i2c clock pin. */
+static void generic_i2c_clock_pulse(unsigned int scl_pin)
+{
+ u16 i;
+
+ if (scl_pin) {
+ /* Send high and low on the SCL line */
+ for (i = 0; i < 9; i++) {
+ gpio_set_value(scl_pin, 0);
+ udelay(20);
+ gpio_set_value(scl_pin, 1);
+ udelay(20);
+ }
+ }
+}
+
+/* This routine does i2c bus recovery as specified in the
+ * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
+ */
+static void i2c_recover_bus(struct davinci_i2c_dev *dev)
+{
+ u32 flag = 0;
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+
+ dev_err(dev->dev, "initiating i2c bus recovery\n");
+ /* Send NACK to the slave */
+ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ flag |= DAVINCI_I2C_MDR_NACK;
+ /* write the data into mode register */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+ if (pdata)
+ generic_i2c_clock_pulse(pdata->scl_pin);
+ /* Send STOP */
+ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ flag |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+}
+
+static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
+ int val)
+{
+ 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->dev->platform_data;
+ u16 psc;
+ u32 clk;
+ u32 d;
+ u32 clkh;
+ u32 clkl;
+ u32 input_clock = clk_get_rate(dev->clk);
+
+ /* 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
+ */
+
+ /* get minimum of 7 MHz clock, but max of 12 MHz */
+ psc = (input_clock / 7000000) - 1;
+ if ((input_clock / (psc + 1)) > 12000000)
+ psc++; /* better to run under spec than over */
+ d = (psc >= 2) ? 5 : 7 - psc;
+
+ clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - (d << 1);
+ clkh = clk >> 1;
+ clkl = clk - clkh;
+
+ 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->dev->platform_data;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+
+ /* 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, 0x08);
+
+ 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;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
+ char allow_sleep)
+{
+ unsigned long timeout;
+ static u16 to_cnt;
+
+ timeout = jiffies + dev->adapter.timeout;
+ while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
+ & DAVINCI_I2C_STR_BB) {
+ if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev,
+ "timeout waiting for bus ready\n");
+ to_cnt++;
+ return -ETIMEDOUT;
+ } else {
+ to_cnt = 0;
+ i2c_recover_bus(dev);
+ i2c_davinci_init(dev);
+ }
+ }
+ if (allow_sleep)
+ schedule_timeout(1);
+ }
+
+ 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->dev->platform_data;
+ u32 flag;
+ u16 w;
+ int r;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+ /* 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);
+
+ INIT_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);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_recover_bus(dev);
+ i2c_davinci_init(dev);
+ 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.
+ * A signal may have aborted the transfer.
+ */
+ if (r >= 0) {
+ dev_err(dev->dev, "abnormal termination buf_len=%i\n",
+ dev->buf_len);
+ r = -EREMOTEIO;
+ }
+ dev->terminate = 1;
+ wmb();
+ dev->buf_len = 0;
+ }
+ if (r < 0)
+ return r;
+
+ /* 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;
+ if (stop) {
+ 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 = i2c_davinci_wait_bus_not_busy(dev, 1);
+ if (ret < 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return ret;
+ }
+
+ 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)
+ return ret;
+ }
+
+#ifdef CONFIG_CPU_FREQ
+ complete(&dev->xfr_complete);
+#endif
+
+ return num;
+}
+
+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;
+
+ 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);
+ if (val == CPUFREQ_PRECHANGE) {
+ wait_for_completion(&dev->xfr_complete);
+ davinci_i2c_reset_ctrl(dev, 0);
+ } else if (val == CPUFREQ_POSTCHANGE) {
+ i2c_davinci_calc_clk_dividers(dev);
+ davinci_i2c_reset_ctrl(dev, 1);
+ }
+
+ 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 struct i2c_algorithm i2c_davinci_algo = {
+ .master_xfer = i2c_davinci_xfer,
+ .functionality = i2c_davinci_func,
+};
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, resource_size(mem),
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ init_completion(&dev->cmd_complete);
+#ifdef CONFIG_CPU_FREQ
+ init_completion(&dev->xfr_complete);
+#endif
+ dev->dev = get_device(&pdev->dev);
+ dev->irq = irq->start;
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ r = -ENODEV;
+ goto err_free_mem;
+ }
+ clk_enable(dev->clk);
+
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (!dev->base) {
+ r = -EBUSY;
+ goto err_mem_ioremap;
+ }
+
+ i2c_davinci_init(dev);
+
+ r = request_irq(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_free_irq;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ 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->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ iounmap(dev->base);
+err_mem_ioremap:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ i2c_davinci_cpufreq_deregister(dev);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+ free_irq(dev->irq, dev);
+ iounmap(dev->base);
+ kfree(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int davinci_i2c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(i2c_dev, 0);
+ clk_disable(i2c_dev->clk);
+
+ return 0;
+}
+
+static int davinci_i2c_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ clk_enable(i2c_dev->clk);
+ /* 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,
+};
+
+#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",
+ .owner = THIS_MODULE,
+ .pm = davinci_i2c_pm_ops,
+ },
+};
+
+/* 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/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.c
new file mode 100644
index 00000000..df879924
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.c
@@ -0,0 +1,705 @@
+/*
+ * 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.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "i2c-designware-core.h"
+
+/*
+ * Registers offset
+ */
+#define DW_IC_CON 0x0
+#define DW_IC_TAR 0x4
+#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_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_TX_ABRT_SOURCE 0x80
+#define DW_IC_COMP_PARAM_1 0xf4
+#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_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
+ DW_IC_INTR_TX_EMPTY | \
+ DW_IC_INTR_TX_ABRT | \
+ DW_IC_INTR_STOP_DET)
+
+#define DW_IC_STATUS_ACTIVITY 0x1
+
+#define DW_IC_ERR_TX_ABRT 0x1
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE 0x0
+#define STATUS_WRITE_IN_PROGRESS 0x1
+#define STATUS_READ_IN_PROGRESS 0x2
+
+#define TIMEOUT 20 /* ms */
+
+/*
+ * 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 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_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)
+
+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",
+};
+
+u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+{
+ u32 value = readl(dev->base + offset);
+
+ if (dev->swab)
+ return swab32(value);
+ else
+ return value;
+}
+
+void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+{
+ if (dev->swab)
+ b = swab32(b);
+
+ writel(b, dev->base + offset);
+}
+
+static 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 + 5000) / 10000 - 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) + 5000) / 10000 - 3 + offset;
+}
+
+static 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) + 5000) / 10000) - 1 + offset;
+}
+
+/**
+ * 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.
+ */
+int i2c_dw_init(struct dw_i2c_dev *dev)
+{
+ u32 input_clock_khz;
+ u32 hcnt, lcnt;
+ u32 reg;
+
+ input_clock_khz = dev->get_clk_rate_khz(dev);
+
+ /* Configure register endianess access */
+ reg = dw_readl(dev, DW_IC_COMP_TYPE);
+ if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
+ dev->swab = 1;
+ reg = DW_IC_COMP_TYPE_VALUE;
+ }
+
+ if (reg != DW_IC_COMP_TYPE_VALUE) {
+ dev_err(dev->dev, "Unknown Synopsys component type: "
+ "0x%08x\n", reg);
+ return -ENODEV;
+ }
+
+ /* Disable the adapter */
+ dw_writel(dev, 0, DW_IC_ENABLE);
+
+ /* set standard and fast speed deviders for high/low periods */
+
+ /* Standard-mode */
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 40, /* tHD;STA = tHIGH = 4.0 us */
+ 3, /* tf = 0.3 us */
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 47, /* tLOW = 4.7 us */
+ 3, /* tf = 0.3 us */
+ 0); /* No offset */
+ dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
+ dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ /* Fast-mode */
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 6, /* tHD;STA = tHIGH = 0.6 us */
+ 3, /* tf = 0.3 us */
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 13, /* tLOW = 1.3 us */
+ 3, /* tf = 0.3 us */
+ 0); /* No offset */
+ dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+ dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ /* Configure Tx/Rx FIFO threshold levels */
+ dw_writel(dev, dev->tx_fifo_depth - 1, 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);
+ return 0;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static 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");
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ return 0;
+}
+
+static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+{
+ struct i2c_msg *msgs = dev->msgs;
+ u32 ic_con;
+
+ /* Disable the adapter */
+ dw_writel(dev, 0, DW_IC_ENABLE);
+
+ /* set the slave (target) address */
+ dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR);
+
+ /* 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;
+ else
+ ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+ dw_writel(dev, ic_con, DW_IC_CON);
+
+ /* Enable the adapter */
+ dw_writel(dev, 1, DW_IC_ENABLE);
+
+ /* Enable interrupts */
+ dw_writel(dev, DW_IC_INTR_DEFAULT_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.
+ */
+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;
+
+ intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+ for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
+ /*
+ * 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 (msgs[dev->msg_write_idx].len == 0) {
+ dev_err(dev->dev,
+ "%s: invalid message length\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;
+ }
+
+ 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) {
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+ dw_writel(dev, 0x100, DW_IC_DATA_CMD);
+ rx_limit--;
+ } else
+ dw_writel(dev, *buf++, DW_IC_DATA_CMD);
+ tx_limit--; buf_len--;
+ }
+
+ dev->tx_buf = buf;
+ dev->tx_buf_len = buf_len;
+
+ if (buf_len > 0) {
+ /* 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 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--)
+ *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+
+ 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;
+ }
+}
+
+static 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;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_dw_xfer_msg
+ */
+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);
+
+ mutex_lock(&dev->lock);
+ pm_runtime_get_sync(dev->dev);
+
+ INIT_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;
+
+ 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 */
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+ if (ret == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_dw_init(dev);
+ ret = -ETIMEDOUT;
+ goto done;
+ } else if (ret < 0)
+ goto done;
+
+ if (dev->msg_err) {
+ ret = dev->msg_err;
+ goto done;
+ }
+
+ /* no error */
+ if (likely(!dev->cmd_err)) {
+ /* Disable the adapter */
+ dw_writel(dev, 0, DW_IC_ENABLE);
+ 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;
+ }
+ ret = -EIO;
+
+done:
+ pm_runtime_put(dev->dev);
+ mutex_unlock(&dev->lock);
+
+ return ret;
+}
+
+u32 i2c_dw_func(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ return dev->functionality;
+}
+
+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 interrupt
+ * occurs.
+ */
+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, "%s: %s enabled= 0x%x stat=0x%x\n", __func__,
+ dev->adapter.name, enabled, stat);
+ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+ return IRQ_NONE;
+
+ 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);
+
+ return IRQ_HANDLED;
+}
+
+void i2c_dw_enable(struct dw_i2c_dev *dev)
+{
+ /* Enable the adapter */
+ dw_writel(dev, 1, DW_IC_ENABLE);
+}
+
+u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
+{
+ return dw_readl(dev, DW_IC_ENABLE);
+}
+
+void i2c_dw_disable(struct dw_i2c_dev *dev)
+{
+ /* Disable controller */
+ dw_writel(dev, 0, DW_IC_ENABLE);
+
+ /* Disable all interupts */
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ dw_readl(dev, DW_IC_CLR_INTR);
+}
+
+void i2c_dw_clear_int(struct dw_i2c_dev *dev)
+{
+ 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);
+}
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.h b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.h
new file mode 100644
index 00000000..02d1a2dd
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-core.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+
+#define DW_IC_CON_MASTER 0x1
+#define DW_IC_CON_SPEED_STD 0x2
+#define DW_IC_CON_SPEED_FAST 0x4
+#define DW_IC_CON_10BITADDR_MASTER 0x10
+#define DW_IC_CON_RESTART_EN 0x20
+#define DW_IC_CON_SLAVE_DISABLE 0x40
+
+
+/**
+ * struct dw_i2c_dev - private i2c-designware data
+ * @dev: driver model device node
+ * @base: IO registers pointer
+ * @cmd_complete: tx completion indicator
+ * @lock: protect this struct and IO registers
+ * @clk: input reference clock
+ * @cmd_err: run time hadware error code
+ * @msgs: points to an array of messages currently being transfered
+ * @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
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
+ */
+struct dw_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct mutex lock;
+ struct clk *clk;
+ 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;
+ int swab;
+ struct i2c_adapter adapter;
+ u32 functionality;
+ u32 master_cfg;
+ unsigned int tx_fifo_depth;
+ unsigned int rx_fifo_depth;
+};
+
+extern u32 dw_readl(struct dw_i2c_dev *dev, int offset);
+extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
+extern int i2c_dw_init(struct dw_i2c_dev *dev);
+extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num);
+extern u32 i2c_dw_func(struct i2c_adapter *adap);
+extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
+extern void i2c_dw_enable(struct dw_i2c_dev *dev);
+extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable(struct dw_i2c_dev *dev);
+extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
+extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-pcidrv.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-pcidrv.c
new file mode 100644
index 00000000..00e8f213
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -0,0 +1,391 @@
+/*
+ * 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 Intel 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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "i2c-designware-core.h"
+
+#define DRIVER_NAME "i2c-designware-pci"
+
+enum dw_pci_ctl_id_t {
+ moorestown_0,
+ moorestown_1,
+ moorestown_2,
+
+ medfield_0,
+ medfield_1,
+ medfield_2,
+ medfield_3,
+ medfield_4,
+ medfield_5,
+};
+
+struct dw_pci_controller {
+ u32 bus_num;
+ u32 bus_cfg;
+ u32 tx_fifo_depth;
+ u32 rx_fifo_depth;
+ u32 clk_khz;
+};
+
+#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
+ DW_IC_CON_SLAVE_DISABLE | \
+ DW_IC_CON_RESTART_EN)
+
+static struct dw_pci_controller dw_pci_controllers[] = {
+ [moorestown_0] = {
+ .bus_num = 0,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [moorestown_1] = {
+ .bus_num = 1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [moorestown_2] = {
+ .bus_num = 2,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_0] = {
+ .bus_num = 0,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_1] = {
+ .bus_num = 1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_2] = {
+ .bus_num = 2,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_3] = {
+ .bus_num = 3,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_4] = {
+ .bus_num = 4,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+ [medfield_5] = {
+ .bus_num = 5,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
+ },
+};
+static struct i2c_algorithm i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+};
+
+static int i2c_dw_pci_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+ int err;
+
+
+ i2c_dw_disable(i2c);
+
+ err = pci_save_state(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "pci_save_state failed\n");
+ return err;
+ }
+
+ err = pci_set_power_state(pdev, PCI_D3hot);
+ if (err) {
+ dev_err(&pdev->dev, "pci_set_power_state failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int i2c_dw_pci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+ int err;
+ u32 enabled;
+
+ enabled = i2c_dw_is_enabled(i2c);
+ if (enabled)
+ return 0;
+
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err) {
+ dev_err(&pdev->dev, "pci_set_power_state() failed\n");
+ return err;
+ }
+
+ pci_restore_state(pdev);
+
+ i2c_dw_init(i2c);
+ return 0;
+}
+
+static int i2c_dw_pci_runtime_idle(struct device *dev)
+{
+ int err = pm_schedule_suspend(dev, 500);
+ dev_dbg(dev, "runtime_idle called\n");
+
+ if (err != 0)
+ return 0;
+ return -EBUSY;
+}
+
+static const struct dev_pm_ops i2c_dw_pm_ops = {
+ .resume = i2c_dw_pci_resume,
+ .suspend = i2c_dw_pci_suspend,
+ SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
+ i2c_dw_pci_runtime_idle)
+};
+
+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return dev->controller->clk_khz;
+}
+
+static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev,
+const struct pci_device_id *id)
+{
+ struct dw_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ unsigned long start, len;
+ void __iomem *base;
+ int r;
+ struct dw_pci_controller *controller;
+
+ if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+ printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n",
+ id->driver_data);
+ return -EINVAL;
+ }
+
+ controller = &dw_pci_controllers[id->driver_data];
+
+ r = pci_enable_device(pdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
+ r);
+ goto exit;
+ }
+
+ /* Determine the address of the I2C area */
+ start = pci_resource_start(pdev, 0);
+ len = pci_resource_len(pdev, 0);
+ if (!start || len == 0) {
+ dev_err(&pdev->dev, "base address not set\n");
+ r = -ENODEV;
+ goto exit;
+ }
+
+ r = pci_request_region(pdev, 0, DRIVER_NAME);
+ if (r) {
+ dev_err(&pdev->dev, "failed to request I2C region "
+ "0x%lx-0x%lx\n", start,
+ (unsigned long)pci_resource_end(pdev, 0));
+ goto exit;
+ }
+
+ base = ioremap_nocache(start, len);
+ if (!base) {
+ dev_err(&pdev->dev, "I/O memory remapping failed\n");
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+
+ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ init_completion(&dev->cmd_complete);
+ mutex_init(&dev->lock);
+ dev->clk = NULL;
+ dev->controller = controller;
+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+ dev->base = base;
+ dev->dev = get_device(&pdev->dev);
+ dev->functionality =
+ I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+ dev->master_cfg = controller->bus_cfg;
+
+ pci_set_drvdata(pdev, dev);
+
+ dev->tx_fifo_depth = controller->tx_fifo_depth;
+ dev->rx_fifo_depth = controller->rx_fifo_depth;
+ r = i2c_dw_init(dev);
+ if (r)
+ goto err_iounmap;
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = 0;
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = controller->bus_num;
+ snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
+ adap->nr);
+
+ r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_iounmap;
+ }
+
+ i2c_dw_disable_int(dev);
+ i2c_dw_clear_int(dev);
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(pdev->irq, dev);
+err_iounmap:
+ iounmap(dev->base);
+ pci_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ pci_release_region(pdev, 0);
+exit:
+ return r;
+}
+
+static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
+{
+ struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
+
+ i2c_dw_disable(dev);
+ pm_runtime_forbid(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+
+ pci_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ free_irq(dev->irq, dev);
+ kfree(dev);
+ pci_release_region(pdev, 0);
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("i2c_designware-pci");
+
+static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+ /* Moorestown */
+ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
+ { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
+ { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
+ /* Medfield */
+ { PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
+ { PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
+ { PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
+ { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
+ { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
+ { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
+ { 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 = __devexit_p(i2c_dw_pci_remove),
+ .driver = {
+ .pm = &i2c_dw_pm_ops,
+ },
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+ return pci_register_driver(&dw_i2c_driver);
+}
+module_init(dw_i2c_init_driver);
+
+static void __exit dw_i2c_exit_driver(void)
+{
+ pci_unregister_driver(&dw_i2c_driver);
+}
+module_exit(dw_i2c_exit_driver);
+
+MODULE_AUTHOR("Baruch Siach ");
+MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-platdrv.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-platdrv.c
new file mode 100644
index 00000000..4ba589ab
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "i2c-designware-core.h"
+
+static struct i2c_algorithm i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+};
+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return clk_get_rate(dev->clk)/1000;
+}
+
+static int __devinit dw_i2c_probe(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *ioarea;
+ int irq, r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return irq; /* -ENXIO */
+ }
+
+ ioarea = request_mem_region(mem->start, resource_size(mem),
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ init_completion(&dev->cmd_complete);
+ mutex_init(&dev->lock);
+ dev->dev = get_device(&pdev->dev);
+ dev->irq = irq;
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+
+ if (IS_ERR(dev->clk)) {
+ r = -ENODEV;
+ goto err_free_mem;
+ }
+ clk_enable(dev->clk);
+
+ dev->functionality =
+ I2C_FUNC_I2C |
+ I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+ dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (dev->base == NULL) {
+ dev_err(&pdev->dev, "failure mapping io resources\n");
+ r = -EBUSY;
+ goto err_unuse_clocks;
+ }
+ {
+ u32 param1 = i2c_dw_read_comp_param(dev);
+
+ dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
+ dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
+ }
+ r = i2c_dw_init(dev);
+ if (r)
+ goto err_iounmap;
+
+ i2c_dw_disable_int(dev);
+ r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_iounmap;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
+ sizeof(adap->name));
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+ of_i2c_register_devices(adap);
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_iounmap:
+ iounmap(dev->base);
+err_unuse_clocks:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, resource_size(mem));
+
+ return r;
+}
+
+static int __devexit dw_i2c_remove(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ i2c_dw_disable(dev);
+ free_irq(dev->irq, dev);
+ kfree(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ 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
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_designware");
+
+static struct platform_driver dw_i2c_driver = {
+ .remove = __devexit_p(dw_i2c_remove),
+ .driver = {
+ .name = "i2c_designware",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(dw_i2c_of_match),
+ },
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+ return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+}
+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 ");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-diolan-u2c.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-diolan-u2c.c
new file mode 100644
index 00000000..7eb19a52
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -0,0 +1,522 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DRIVER_NAME "i2c-diolan-u2c"
+
+#define USB_VENDOR_ID_DIOLAN 0x0abf
+#define USB_DEVICE_ID_DIOLAN_U2C 0x3370
+
+#define DIOLAN_OUT_EP 0x02
+#define DIOLAN_IN_EP 0x84
+
+/* 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 */
+ 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, DIOLAN_OUT_EP),
+ 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,
+ DIOLAN_IN_EP),
+ 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, DIOLAN_IN_EP),
+ 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;
+ }
+ if (pmsg->flags & I2C_M_RD) {
+ ret =
+ diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1);
+ if (ret < 0)
+ goto abort;
+ 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 {
+ ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1);
+ if (ret < 0)
+ goto abort;
+ for (j = 0; j < pmsg->len; j++) {
+ ret = diolan_i2c_put_byte_ack(dev,
+ pmsg->buf[j]);
+ if (ret < 0)
+ goto abort;
+ }
+ }
+ }
+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 i2c_diolan_u2c *dev;
+ int ret;
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "no memory for device state\n");
+ ret = -ENOMEM;
+ 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);
+
+ /* 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) {
+ dev_err(&interface->dev, "failed to add I2C adapter\n");
+ 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 ");
+MODULE_DESCRIPTION(DRIVER_NAME " driver");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-eg20t.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-eg20t.c
new file mode 100644
index 00000000..c811289b
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/i2c/busses/i2c-eg20t.c
@@ -0,0 +1,1068 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include