From 99e8fe779d7ee9e7087131834d8daed99a7f0278 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E6=9F=AF=E9=A3=9E=E9=9B=84?= Date: Tue, 11 May 2010 14:07:00 +0000 Subject: [PATCH] add i2c --- drivers/i2c/busses/Kconfig | 785 +------------------------------- drivers/i2c/busses/Makefile | 74 +-- drivers/i2c/busses/i2c-rk2818.c | 755 ++++++++++++++++++++++++++++++ 3 files changed, 768 insertions(+), 846 deletions(-) create mode 100755 drivers/i2c/busses/i2c-rk2818.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e8fe7f169e25..b8a36ab4d3dc 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -4,778 +4,17 @@ 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 . - - 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 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ff937ac69f5b..479f8a8ed714 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -1,79 +1,7 @@ # # 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 - -# Embebbed 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) += i2c-designware.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_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_OCORES) += i2c-ocores.o -obj-$(CONFIG_I2C_OMAP) += i2c-omap.o -obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o -obj-$(CONFIG_I2C_PNX) += i2c-pnx.o -obj-$(CONFIG_I2C_PXA) += i2c-pxa.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_STU300) += i2c-stu300.o -obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o - -# External I2C/SMBus adapter drivers -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 - -# Graphics adapter I2C/DDC channel drivers -obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.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_PCA_PLATFORM) += i2c-pca-platform.o -obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.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 +obj-$(CONFIG_I2C_RK2818) += i2c-rk2818.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/busses/i2c-rk2818.c b/drivers/i2c/busses/i2c-rk2818.c new file mode 100755 index 000000000000..5c6902f9fa86 --- /dev/null +++ b/drivers/i2c/busses/i2c-rk2818.c @@ -0,0 +1,755 @@ +/* + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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<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, "); +MODULE_LICENSE("GPL"); -- 2.34.1