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)"
- depends on PCI
- 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
- Tolapai
- ICH10
- 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
- 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 SMBus interface"
- depends on SOC_AU1550 || SOC_AU1200
- help
- If you say yes to this option, support will be included for the
- Au1550 and Au1200 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
- tristate "Synopsys DesignWare"
- 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.
-
-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_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/52xx/86xx"
- depends on PPC32
- help
- If you say yes to this option, support will be included for the
- built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx/MPC8641 family processors. The driver may also work on 52xx
- family processors, though interrupts are known not to work.
-
- 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_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_PNX
- tristate "I2C bus support for Philips PNX targets"
- depends on ARCH_PNX4008
- 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_PXA
- tristate "Intel PXA2XX I2C adapter"
- depends on ARCH_PXA || ARCH_MMP
- 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_SLAVE
- bool "Intel PXA2XX I2C Slave comms support"
- depends on I2C_PXA
- help
- Support I2C slave mode communications on the PXA I2C bus. This
- is necessary for systems where the PXA may be a target on the
- I2C bus.
-
-config I2C_S3C2410
- tristate "S3C2410 I2C Driver"
- depends on ARCH_S3C2410 || ARCH_S3C64XX
- help
- Say Y here to include support for I2C controller in the
- Samsung S3C2410 based System-on-Chip devices.
-
-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
- 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_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_VERSATILE
- tristate "ARM Versatile/Realview I2C bus support"
- depends on ARCH_VERSATILE || ARCH_REALVIEW
- 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.
-
-comment "External I2C/SMBus adapter drivers"
-
-config I2C_PARPORT
- tristate "Parallel port adapter"
- depends on PARPORT
- select I2C_ALGOBIT
- 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
- 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 "Graphics adapter I2C/DDC channel drivers"
- depends on PCI
-
-config I2C_VOODOO3
- tristate "Voodoo 3 (DEPRECATED)"
- depends on PCI
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the
- Voodoo 3 I2C interface. This driver is deprecated and you should
- use the tdfxfb driver instead, which additionally provides
- framebuffer support.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-voodoo3.
-
-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 && 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_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_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 <file:Documentation/i2c/i2c-stub>.
-
- 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.
+config I2C_RK2818
+ tristate "RK2818 i2c interface (I2C)"
+ depends on ARCH_RK2818
+ help
+ This supports the use of the I2C interface on rk2818
+ processors.
+
+ 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.
endmenu
--- /dev/null
+/*
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <mach/i2c.h>
+#include <asm/io.h>
+
+#define RK2818_I2C_TIMEOUT (msecs_to_jiffies(500))
+
+enum rk2818_error {
+ RK2818_ERROR_NONE = 0,
+ RK2818_ERROR_ARBITR_LOSE,
+ RK2818_ERROR_UNKNOWN
+};
+
+enum rk2818_event {
+ RK2818_EVENT_NONE = 0,
+ /* master has received ack(MTX mode)
+ means that data has been sent to slave.
+ */
+ RK2818_EVENT_MTX_RCVD_ACK,
+ /* master needs to send ack to slave(MRX mode)
+ means that data has been received from slave.
+ */
+ RK2818_EVENT_MRX_NEED_ACK,
+ RK2818_EVENT_MAX
+};
+
+struct rk2818_i2c_data {
+ struct device *dev;
+ struct i2c_adapter adap;
+ void __iomem *regs;
+ struct resource *ioarea;
+
+ unsigned int suspended:1;
+ unsigned long scl_rate;
+ struct clk *clk;
+
+ unsigned int irq;
+
+ spinlock_t cmd_lock;
+ struct completion cmd_complete;
+ enum rk2818_event cmd_event;
+ enum rk2818_error cmd_err;
+
+ unsigned int msg_idx;
+ unsigned int msg_num;
+};
+
+static int rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c);
+
+static inline void rk2818_i2c_disable_irqs(struct rk2818_i2c_data *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + I2C_IER);
+ writel(tmp & IRQ_ALL_DISABLE, i2c->regs + I2C_IER);
+}
+static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c)
+{
+ unsigned long tmp;
+
+ tmp = readl(i2c->regs + I2C_IER);
+ writel(tmp | IRQ_MST_ENABLE, i2c->regs + I2C_IER);
+}
+
+/* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */
+static unsigned long rk2818_i2c_calcdivisor(unsigned long pclk,
+ unsigned long scl_rate,
+ unsigned long *real_rate,
+ unsigned int *rem, unsigned int *exp)
+{
+ unsigned int calc_rem = pclk / (5 * scl_rate);
+ unsigned int calc_exp;
+
+ for(calc_exp = 0; calc_exp < I2CCDVR_EXP_MAX; calc_exp++)
+ {
+ if(calc_rem < I2CCDVR_REM_MAX)
+ {
+ calc_exp--;
+ break;
+ }
+ calc_rem = calc_rem >> 1;
+ }
+ if(calc_rem >= I2CCDVR_REM_MAX)
+ return -1;
+ *rem = calc_rem;
+ *exp = calc_exp;
+
+ *real_rate = pclk/(5 * (calc_rem + 1) * (1 <<(calc_exp +1)));
+ return 0;
+}
+/* set i2c bus scl rate */
+static unsigned long rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c)
+{
+ struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data;
+ unsigned int rem = 0, exp = 0;
+ unsigned long scl_rate, real_rate = 0, tmp, pclk;
+ int ret = 0;
+ struct clk *arm_pclk;
+
+ arm_pclk = clk_get_parent(i2c->clk);
+ if(IS_ERR(arm_pclk))
+ {
+ dev_err(i2c->dev, "cannot get pclk\n");
+ ret = -ENOENT;
+ }
+ pclk = clk_get_rate(arm_pclk);
+
+ dev_dbg(i2c->dev, "pdata desired clkrate %lu\n", pdata->scl_rate);
+
+ scl_rate = pdata->scl_rate ? pdata->scl_rate : 100000;
+
+ ret = rk2818_i2c_calcdivisor(pclk, scl_rate, &real_rate, &rem, &exp);
+
+ if (ret < 0)
+ {
+ dev_err(i2c->dev,
+ "Unable to achieve desired clkrate %luHz.", scl_rate);
+ return -EINVAL;
+ }
+
+
+ tmp = readl(i2c->regs + I2C_OPR);
+ tmp |= exp;
+ tmp |= rem<<I2CCDVR_EXP_BITS;
+ writel(tmp, i2c->regs + I2C_OPR);
+ dev_dbg(i2c->dev, " Scl real rate is %lu\n", real_rate);
+
+ return ret;
+}
+static int rk2818_event_occurred(struct rk2818_i2c_data *i2c)
+{
+ unsigned long isr, lsr;
+
+ isr = readl(i2c->regs + I2C_ISR);
+ lsr = readl(i2c->regs + I2C_LSR);
+ if(isr & I2C_ISR_ARBITR_LOSE)
+ {
+ isr &= ~I2C_ISR_ARBITR_LOSE;
+ writel(isr, i2c->regs + I2C_ISR);
+ i2c->cmd_err = RK2818_ERROR_ARBITR_LOSE;
+ return 1;
+ }
+
+ switch(i2c->cmd_event)
+ {
+ case RK2818_EVENT_MTX_RCVD_ACK:
+ if(isr & I2C_ISR_MTX_RCVD_ACK)
+ {
+ isr &= ~I2C_ISR_MTX_RCVD_ACK;
+ writel(isr, i2c->regs + I2C_ISR);
+ return 1;
+ }
+ break;
+ case RK2818_EVENT_MRX_NEED_ACK:
+ if(isr & I2C_ISR_MRX_NEED_ACK)
+ {
+ isr &= ~I2C_ISR_MRX_NEED_ACK;
+ writel(isr, i2c->regs + I2C_ISR);
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+ i2c->cmd_err = RK2818_ERROR_UNKNOWN;
+ dev_err(i2c->dev,"Unhandled interrupt!\n");
+ return 0;
+}
+
+static irqreturn_t rk2818_i2c_irq(int irq, void *data)
+{
+ struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)data;
+ int res;
+ rk2818_i2c_disable_irqs(i2c);
+ spin_lock(&i2c->cmd_lock);
+ res = rk2818_event_occurred(i2c);
+ if(res || i2c->cmd_err != RK2818_ERROR_NONE)
+ complete(&i2c->cmd_complete);
+ spin_unlock(&i2c->cmd_lock);
+
+ return IRQ_HANDLED;
+}
+
+static int rk2818_wait_event(struct rk2818_i2c_data *i2c,
+ enum rk2818_event mr_event)
+{
+ int ret = 0;
+ if(unlikely(irqs_disabled()))
+ {
+ dev_err(i2c->dev, "irqs are disabled on this system!\n");
+ return -EIO;
+ }
+ spin_lock_irq(&i2c->cmd_lock);
+ i2c->cmd_err = RK2818_ERROR_NONE;
+ i2c->cmd_event = mr_event;
+
+ init_completion(&i2c->cmd_complete);
+
+ spin_unlock_irq(&i2c->cmd_lock);
+
+ rk2818_i2c_enable_irqs(i2c);
+ ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete,
+ RK2818_I2C_TIMEOUT);
+
+ if(ret < 0)
+ {
+ dev_err(i2c->dev, "wait_for_completion_interruptible_timeout(): "
+ "retrun %d waiting for event %04x\n", ret,
+ mr_event);
+ return ret;
+ }
+ if(ret == 0)
+ {
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int rk2818_wait_while_busy(struct rk2818_i2c_data *i2c)
+{
+ unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT;
+ unsigned long lsr;
+ dev_dbg(i2c->dev,"wait_while_busy");
+ while(!time_after(jiffies, timeout))
+ {
+ lsr = readl(i2c->regs + I2C_LSR);
+ if(!(lsr & I2C_LSR_BUSY))
+ return 0;
+ udelay(100);
+ }
+ return -ETIMEDOUT;
+}
+
+static int rk2818_send_address(struct rk2818_i2c_data *i2c,
+ struct i2c_msg *msg)
+{
+ unsigned long addr_1st;
+ unsigned long addr_2nd;
+ unsigned long conr = readl(i2c->regs + I2C_CONR);
+ int ret = 0;
+ /*
+ if(msg->flags & I2C_M_TEN)
+ addr_1st = (0xf0 | (((unsigned long) msg->addr & 0x300) >> 7)) & 0xff;
+ else
+ */
+ addr_1st = ((msg->addr << 1) & 0xff);
+ if (msg->flags & I2C_M_RD)
+ addr_1st |= 0x01;
+ else
+ addr_1st &= (~0x01);
+
+ conr |= I2C_CONR_MTX_MODE;
+ conr &= I2C_CONR_ACK;
+ writel(conr, i2c->regs + I2C_CONR);
+ dev_info(i2c->dev, "send addr: %lx\n", addr_1st);
+ writel(addr_1st, i2c->regs + I2C_MTXR);
+ if(i2c->msg_idx == 0)
+ {
+ ret = rk2818_wait_while_busy(i2c);
+ if(ret != 0)
+ {
+ dev_err(i2c->dev, "send addr:wait_while_busy\n");
+ conr = readl(i2c->regs + I2C_CONR);
+ conr |= I2C_CONR_NAK;
+ writel(conr, i2c->regs + I2C_CONR);
+ writel(I2C_LCMR_STOP, i2c->regs + I2C_LCMR);
+ return ret;
+ }
+ }
+ writel(I2C_LCMR_START, i2c->regs + I2C_LCMR);
+ /*
+ if(msg->flags & I2C_M_TEN)
+ {
+ ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK);
+ if(ret != 0)
+ {
+ return ret;
+ }
+ addr_2nd = msg->addr & 0xff;
+ writel(addr_2nd, i2c->regs + I2C_MTXR);
+ writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+ if (msg->flags & I2C_M_RD)
+ {
+ ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK);
+ if(ret != 0)
+ {
+ return ret;
+ }
+
+ writel(addr_1st, i2c->regs + I2C_MTXR);
+ writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+ }
+
+ }
+ */
+ ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK);
+ if(ret != 0)
+ dev_err(i2c->dev, "send addr:wait ack timeout\n");
+ return ret;
+}
+
+static int rk2818_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
+
+ int ret, i;
+ unsigned long conr = readl(i2c->regs + I2C_CONR);
+ conr |= I2C_CONR_MPORT_ENABLE;
+ writel(conr, i2c->regs + I2C_CONR);
+ if(msg->len == 0)
+ {
+ ret = -EINVAL;
+ goto exit_disable;
+ }
+
+ clk_enable(i2c->clk);
+ if(msg->scl_rate)
+ i2c->scl_rate = msg->scl_rate;
+ rk2818_i2c_clockrate(i2c);
+
+ ret = rk2818_send_address(i2c, msg);
+ if(ret != 0)
+ {
+ dev_err(i2c->dev, "send addr error\n");
+ goto exit_disable;
+ }
+ if(msg->flags & I2C_M_RD)
+ {
+ conr = readl(i2c->regs + I2C_CONR);
+ conr &= I2C_CONR_MRX_MODE;
+ writel(conr, i2c->regs + I2C_CONR);
+
+ for(i = 0; i < msg->len; i++)
+ {
+ writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+ ret = rk2818_wait_event(i2c, RK2818_EVENT_MRX_NEED_ACK);
+ if(ret != 0)
+ {
+ dev_err(i2c->dev, "read data timeout\n");
+ goto exit_disable;
+ }
+ msg->buf[i] = (uint8_t)readl(i2c->regs + I2C_MRXR);
+ dev_info(i2c->dev, "receive data=%u\n",msg->buf[i]);
+ if(i == msg->len - 1)
+ {
+ conr = readl(i2c->regs + I2C_CONR);
+ conr &= I2C_CONR_ACK;
+ writel(conr, i2c->regs + I2C_CONR);
+ }
+ }
+ }
+ else
+ {
+ conr = readl(i2c->regs + I2C_CONR);
+ conr |= I2C_CONR_MTX_MODE;
+ writel(conr, i2c->regs + I2C_CONR);
+ for(i = 0; i < msg->len; i++)
+ {
+ writel(msg->buf[i], i2c->regs + I2C_MTXR);
+ dev_info(i2c->dev, "send data =%u\n", msg->buf[i]);
+ conr = readl(i2c->regs + I2C_CONR);
+ conr |= I2C_CONR_NAK;
+ writel(conr, i2c->regs + I2C_CONR);
+ writel(I2C_LCMR_RESUME, i2c->regs + I2C_LCMR);
+
+ ret = rk2818_wait_event(i2c, RK2818_EVENT_MTX_RCVD_ACK);
+ if(ret != 0)
+ {
+ dev_err(i2c->dev, "send data timeout\n");
+ goto exit_disable;
+ }
+ }
+
+ }
+ if(i == msg->len)
+ {
+ conr = readl(i2c->regs + I2C_CONR);
+ conr |= I2C_CONR_NAK;
+ writel(conr, i2c->regs + I2C_CONR);
+ if(msg->flags & I2C_M_TEN)
+ writel(I2C_LCMR_START|I2C_LCMR_RESUME , i2c->regs + I2C_LCMR);
+ else
+ writel(I2C_LCMR_STOP|I2C_LCMR_RESUME , i2c->regs + I2C_LCMR);
+ if(i2c->msg_idx >= i2c->msg_num - 1)
+ {
+ ret = rk2818_wait_while_busy(i2c);
+
+ if(ret != 0)
+ {
+ dev_err(i2c->dev, "tx success wait bus busy time out\n");
+ return ret;
+ }
+ }
+ }
+exit_disable:
+ conr = readl(i2c->regs + I2C_CONR);
+ conr &= I2C_CONR_MPORT_DISABLE;
+ writel(conr, i2c->regs + I2C_CONR);
+ clk_disable(i2c->clk);
+ return ret;
+
+}
+
+static int rk2818_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ int ret = -1;
+ int i,retry;
+ struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)adap->algo_data;
+
+ if(i2c->suspended ==1)
+ return -EIO;
+ i2c->scl_rate = msgs[0].scl_rate;
+ ret = rk2818_i2c_init_hw(i2c);
+ if(ret < 0)
+ return ret;
+ i2c->msg_num = num;
+ for (i = 0; i < num; i++)
+ {
+ i2c->msg_idx = i;
+ for(retry = 0; retry < adap->retries; retry ++)
+ {
+ ret = rk2818_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if(ret == 0)
+ break;
+ }
+ if (ret != 0)
+ {
+ num = ret;
+ dev_err(i2c->dev, "rk2818_xfer_msg error, ret = %d\n", ret);
+ break;
+ }
+ }
+ return num;
+}
+
+static u32 rk2818_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm rk2818_i2c_algorithm = {
+ .master_xfer = rk2818_i2c_xfer,
+ .functionality = rk2818_i2c_func,
+};
+
+
+
+#ifdef CONFIG_CPU_FREQ
+
+#define freq_to_i2c(_n) container_of(_n, struct rk2818_i2c, freq_transition)
+
+static int rk2818_i2c_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct rk2818_i2c_data *i2c = freq_to_i2c(nb);
+ unsigned long flags;
+ int delta_f;
+ int ret = 0;
+
+ delta_f = clk_get_rate(i2c->clk) - i2c->scl_rate;
+
+ if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
+ (val == CPUFREQ_PRECHANGE && delta_f > 0))
+ {
+ spin_lock_irqsave(&i2c->lock, flags);
+ ret = rk2818_i2c_clockrate(i2c);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+ }
+
+ return ret;
+}
+
+static inline int rk2818_i2c_register_cpufreq(struct rk2818_i2c_data *i2c)
+{
+ i2c->freq_transition.notifier_call = rk2818_i2c_cpufreq_transition;
+
+ return cpufreq_register_notifier(&i2c->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void rk2818_i2c_deregister_cpufreq(struct rk2818_i2c_data *i2c)
+{
+ cpufreq_unregister_notifier(&i2c->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int rk2818_i2c_register_cpufreq(struct rk2818_i2c_data *i2c)
+{
+ return 0;
+}
+
+static inline void rk2818_i2c_unregister_cpufreq(struct rk2818_i2c_data *i2c)
+{
+ return;
+}
+#endif
+
+
+static int rk2818_i2c_init_hw(struct rk2818_i2c_data *i2c)
+{
+ unsigned long lcmr = 0x00000000;
+
+ unsigned long opr = readl(i2c->regs + I2C_OPR);
+ opr |= I2C_OPR_RESET_STATUS;
+ writel(opr, i2c->regs + I2C_OPR);
+
+ writel(lcmr, i2c->regs + I2C_LCMR);
+
+ rk2818_i2c_disable_irqs(i2c);
+
+ if (rk2818_i2c_clockrate(i2c) < 0) {
+ dev_err(i2c->dev, "cannot meet bus clkrate required\n");
+ return -EINVAL;
+ }
+
+ opr = readl(i2c->regs + I2C_OPR);
+ //opr &= ~I2C_OPR_RESET_STATUS;
+ opr |= I2C_OPR_CORE_ENABLE;
+ writel(opr, i2c->regs + I2C_OPR);
+
+ return 0;
+}
+
+
+static int rk2818_i2c_probe(struct platform_device *pdev)
+{
+ struct rk2818_i2c_data *i2c;
+ struct rk2818_i2c_platform_data *pdata;
+ struct resource *res;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+ i2c = kzalloc(sizeof(struct rk2818_i2c_data), GFP_KERNEL);
+ if (!i2c)
+ {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ strlcpy(i2c->adap.name, "rk2818_i2c", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &rk2818_i2c_algorithm;
+ i2c->adap.class = I2C_CLASS_HWMON;
+ spin_lock_init(&i2c->cmd_lock);
+
+ i2c->dev = &pdev->dev;
+
+ i2c->clk = clk_get(&pdev->dev, pdata->clk_id);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ ret = -ENOENT;
+ goto err_noclk;
+ }
+
+ dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
+ clk_enable(i2c->clk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err_clk;
+ }
+
+ i2c->ioarea = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+
+ if (i2c->ioarea == NULL) {
+ dev_err(&pdev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err_clk;
+ }
+
+ i2c->regs = ioremap(res->start, res->end - res->start + 1);
+
+ if (i2c->regs == NULL) {
+ dev_err(&pdev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_ioarea;
+ }
+
+ dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+ i2c->regs, i2c->ioarea, res);
+
+ i2c->adap.algo_data = i2c;
+ i2c->adap.retries = 4;
+ i2c->adap.dev.parent = &pdev->dev;
+
+ if(pdata->cfg_gpio)
+ pdata->cfg_gpio(pdev);
+ ret = rk2818_i2c_init_hw(i2c);
+ if (ret != 0)
+ goto err_iomap;
+
+ i2c->irq = ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ goto err_iomap;
+ }
+
+ ret = request_irq(i2c->irq, rk2818_i2c_irq, IRQF_DISABLED,
+ dev_name(&pdev->dev), i2c);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ goto err_iomap;
+ }
+
+ ret = rk2818_i2c_register_cpufreq(i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+ goto err_irq;
+ }
+
+ i2c->adap.nr = pdata->bus_num;
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+ goto err_cpufreq;
+ }
+
+ platform_set_drvdata(pdev, i2c);
+
+ dev_dbg(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev));
+ return 0;
+
+ err_cpufreq:
+ rk2818_i2c_unregister_cpufreq(i2c);
+
+ err_irq:
+ free_irq(i2c->irq, i2c);
+
+ err_iomap:
+ iounmap(i2c->regs);
+
+ err_ioarea:
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+
+ err_clk:
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ err_noclk:
+ kfree(i2c);
+ return ret;
+}
+
+
+static int rk2818_i2c_remove(struct platform_device *pdev)
+{
+ struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
+
+ rk2818_i2c_unregister_cpufreq(i2c);
+
+ i2c_del_adapter(&i2c->adap);
+ free_irq(i2c->irq, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->regs);
+
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+ kfree(i2c);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rk2818_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
+
+ i2c->suspended = 1;
+ return 0;
+}
+static int rk2818_i2c_resume(struct platform_device *pdev)
+{
+ struct rk2818_i2c_data *i2c = platform_get_drvdata(pdev);
+
+ i2c->suspended = 0;
+ rk2818_i2c_init_hw(i2c);
+
+ return 0;
+}
+#else
+#define rk2818_i2c_suspend NULL
+#define rk2818_i2c_resume NULL
+#endif
+
+
+static struct platform_driver rk2818_i2c_driver = {
+ .probe = rk2818_i2c_probe,
+ .remove = rk2818_i2c_remove,
+ .suspend = rk2818_i2c_suspend,
+ .resume = rk2818_i2c_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rk2818_i2c",
+ },
+};
+
+static int __init rk2818_i2c_adap_init(void)
+{
+ return platform_driver_register(&rk2818_i2c_driver);
+}
+
+static void __exit rk2818_i2c_adap_exit(void)
+{
+ platform_driver_unregister(&rk2818_i2c_driver);
+}
+
+subsys_initcall(rk2818_i2c_adap_init);
+module_exit(rk2818_i2c_adap_exit);
+
+MODULE_DESCRIPTION("RK2818 I2C Bus driver");
+MODULE_AUTHOR("Rock-chips, <www.rock-chips.com>");
+MODULE_LICENSE("GPL");