[Armadeus-commitlog] SF.net SVN: armadeus: [788] branches/apf2/buildroot/target/device/armadeus
Brought to you by:
sszy
|
From: <ar...@us...> - 2008-04-03 06:43:18
|
Revision: 788
http://armadeus.svn.sourceforge.net/armadeus/?rev=788&view=rev
Author: artemys
Date: 2008-04-02 23:43:24 -0700 (Wed, 02 Apr 2008)
Log Message:
-----------
[LINUX] Add i.MX27 Framebuffer & I2C/SPI drivers (I2C/SPI not functionnal yet)
Modified Paths:
--------------
branches/apf2/buildroot/target/device/armadeus/apf27/linux-2.6.25-rc7.config
Added Paths:
-----------
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/230-apf27-pengu-mx2_devices_full.diff
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/231-apf27-pengu-mxc_i2c_driver.diff
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/232-apf27-pengu-imx27_spi_driver.diff
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/233-apf27-pengu-mx2_framebuffer_beta.diff
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/234-apf27-pengu-mc13783_touch.not_used
branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/235-apf27-pengu-make_pcm038_full_featured.diff
Modified: branches/apf2/buildroot/target/device/armadeus/apf27/linux-2.6.25-rc7.config
===================================================================
--- branches/apf2/buildroot/target/device/armadeus/apf27/linux-2.6.25-rc7.config 2008-04-02 15:08:36 UTC (rev 787)
+++ branches/apf2/buildroot/target/device/armadeus/apf27/linux-2.6.25-rc7.config 2008-04-03 06:43:24 UTC (rev 788)
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.25-rc7
-# Tue Apr 1 17:39:25 2008
+# Wed Apr 2 22:41:47 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -430,8 +430,6 @@
#
# Self-contained MTD device drivers
#
-# CONFIG_MTD_DATAFLASH is not set
-# CONFIG_MTD_M25P80 is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
@@ -484,7 +482,6 @@
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
-# CONFIG_ENC28J60 is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -530,7 +527,6 @@
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
@@ -577,59 +573,13 @@
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
-CONFIG_I2C=y
-CONFIG_I2C_BOARDINFO=y
-# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C is not set
#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_SIMTEC is not set
-# CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
# SPI support
#
-CONFIG_SPI=y
-CONFIG_SPI_MASTER=y
-
-#
-# SPI Master Controller Drivers
-#
-CONFIG_SPI_BITBANG=y
-
-#
-# SPI Protocol Masters
-#
-# CONFIG_SPI_AT25 is not set
-# CONFIG_SPI_SPIDEV is not set
-# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
@@ -659,8 +609,6 @@
# CONFIG_VIDEO_ADV_DEBUG is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
# CONFIG_VIDEO_VIVI is not set
-# CONFIG_VIDEO_SAA5246A is not set
-# CONFIG_VIDEO_SAA5249 is not set
# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DVB_CORE is not set
# CONFIG_DAB is not set
@@ -673,9 +621,9 @@
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
@@ -691,6 +639,13 @@
#
# Frame buffer hardware drivers
#
+CONFIG_FB_MXC=y
+
+#
+# MXC framebuffer options
+#
+CONFIG_FB_MXC_SYNC_PANEL=y
+# CONFIG_FB_MXC_OVERLAY is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
@@ -719,7 +674,10 @@
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
-# CONFIG_LOGO is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
#
# Sound
@@ -745,26 +703,8 @@
# CONFIG_RTC_DRV_TEST is not set
#
-# I2C RTC drivers
-#
-# CONFIG_RTC_DRV_DS1307 is not set
-# CONFIG_RTC_DRV_DS1374 is not set
-# CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_MAX6900 is not set
-# CONFIG_RTC_DRV_RS5C372 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
-# CONFIG_RTC_DRV_X1205 is not set
-CONFIG_RTC_DRV_PCF8563=y
-# CONFIG_RTC_DRV_PCF8583 is not set
-# CONFIG_RTC_DRV_M41T80 is not set
-# CONFIG_RTC_DRV_S35390A is not set
-
-#
# SPI RTC drivers
#
-# CONFIG_RTC_DRV_MAX6902 is not set
-# CONFIG_RTC_DRV_R9701 is not set
-# CONFIG_RTC_DRV_RS5C348 is not set
#
# Platform RTC drivers
Added: branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/230-apf27-pengu-mx2_devices_full.diff
===================================================================
--- branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/230-apf27-pengu-mx2_devices_full.diff (rev 0)
+++ branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/230-apf27-pengu-mx2_devices_full.diff 2008-04-03 06:43:24 UTC (rev 788)
@@ -0,0 +1,764 @@
+Subject: [@num@/@total@] i.MX2 family: Devices support
+From: Juergen Beisert <j.b...@pe...>
+
+This patch expands the known devices on i.MX21/i.MX27 procesors.
+
+New devices are:
+
+ - spi
+ - i2c
+ - watchdog
+ - framebuffer
+
+Note: This is for development. Not for mainline yet.
+
+Signed-off-by: Juergen Beisert <j.b...@pe...>
+
+---
+
+ arch/arm/mach-mx2/devices.c | 316 +++++++++++++++++++++++++++++++-
+ arch/arm/mach-mx2/devices.h | 14 +
+ include/asm-arm/arch-mxc/imx_fb.h | 81 ++++++++
+ include/asm-arm/arch-mxc/imx_i2c.h | 83 ++++++++
+ include/asm-arm/arch-mxc/imx_spi.h | 145 ++++++++++++++
+ include/asm-arm/arch-mxc/imx_watchdog.h | 44 ++++
+ 6 files changed, 677 insertions(+), 6 deletions(-)
+
+Index: include/asm-arm/arch-mxc/imx_watchdog.h
+===================================================================
+--- /dev/null
++++ linux/include/asm-arm/arch-mxc/imx_watchdog.h
+@@ -0,0 +1,44 @@
++/*
++ * imx_watchdog.h
++ *
++ * Copyright (C) 2008 Juergen Beisert (ke...@pe...)
++ *
++ * 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.
++ */
++
++/*
++ * Watchdog register definition for:
++ * - i.MX21
++ * - i.MX27
++ */
++
++/* for direct access, note: All registers are 16 bit wide */
++#define IMX_WCR_REG(x) (*(volatile unsigned short __force*)(x))
++#define IMX_WSR_REG(x) (*(volatile unsigned short __force*)((x) + 2))
++#define IMX_WRSR_REG(x) (*(volatile unsigned short __force*)((x) + 4))
++
++/* for drivers usage */
++#define IMX_WCR 0
++#define IMX_WSR 2
++#define IMX_WRSR 4
++
++/* Bit definitions */
++#define IMX_WCR_WT_SHIFT 8
++#define IMX_WCR_WT_MASK 0xFF00
++#define IMX_WCR_WDA (1<<5)
++#define IMX_WCR_SRS (1<<4)
++#define IMX_WCR_WRE (1<<3)
++#define IMX_WCR_WDE (1<<2)
++#define IMX_WCR_WDBG (1<<1)
++#define IMX_WCR_WDZST (1<<0)
+Index: include/asm-arm/arch-mxc/imx_i2c.h
+===================================================================
+--- /dev/null
++++ linux/include/asm-arm/arch-mxc/imx_i2c.h
+@@ -0,0 +1,83 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, ke...@pe...
++ *
++ * 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.
++ */
++
++#ifndef __ASM_ARCH_MXC_I2C_H__
++#define __ASM_ARCH_MXC_I2C_H__
++
++struct imx_i2c_platform_data {
++ u32 i2c_clk;
++ int (*init)(struct platform_device *pdev);
++ int (*exit)(struct platform_device *pdev);
++};
++
++int mxc_init_i2c(int id, struct imx_i2c_platform_data *data);
++
++/*
++ * This file contains the I2C chip level configuration details.
++ *
++ * It also contains the API function that other drivers can use to read/write
++ * to the I2C device registers.
++ */
++
++/*
++ * This defines the string used to identify MXC I2C Bus drivers
++ */
++#define MXC_ADAPTER_NAME "MXC I2C Adapter"
++
++#define MXC_I2C_FLAG_READ 0x01 /* if set, is read; else is write */
++#define MXC_I2C_FLAG_POLLING 0x02 /* if set, is polling mode; else is interrupt mode */
++
++int mxc_i2c_read(int bus_id, unsigned int addr, char *reg, int reg_len,
++ char *buf, int num);
++
++int mxc_i2c_write(int bus_id, unsigned int addr, char *reg, int reg_len,
++ char *buf, int num);
++
++int mxc_i2c_polling_read(int bus_id, unsigned int addr, char *reg, int reg_len,
++ char *buf, int num);
++
++int mxc_i2c_polling_write(int bus_id, unsigned int addr, char *reg, int reg_len,
++ char *buf, int num);
++
++/* FIXME: This should be in a generic register file */
++
++/* Address offsets of the I2C registers */
++#define MXC_IADR 0x00 /* Address Register */
++#define MXC_IFDR 0x04 /* Freq div register */
++#define MXC_I2CR 0x08 /* Control regsiter */
++#define MXC_I2SR 0x0C /* Status register */
++#define MXC_I2DR 0x10 /* Data I/O register */
++
++/* Bit definitions of I2CR */
++#define MXC_I2CR_IEN 0x0080
++#define MXC_I2CR_IIEN 0x0040
++#define MXC_I2CR_MSTA 0x0020
++#define MXC_I2CR_MTX 0x0010
++#define MXC_I2CR_TXAK 0x0008
++#define MXC_I2CR_RSTA 0x0004
++
++/* Bit definitions of I2SR */
++#define MXC_I2SR_ICF 0x0080
++#define MXC_I2SR_IAAS 0x0040
++#define MXC_I2SR_IBB 0x0020
++#define MXC_I2SR_IAL 0x0010
++#define MXC_I2SR_SRW 0x0004
++#define MXC_I2SR_IIF 0x0002
++#define MXC_I2SR_RXAK 0x0001
++
++#endif /* __ASM_ARCH_MXC_I2C_H__ */
+Index: include/asm-arm/arch-mxc/imx_spi.h
+===================================================================
+--- /dev/null
++++ linux/include/asm-arm/arch-mxc/imx_spi.h
+@@ -0,0 +1,145 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, ke...@pe...
++ *
++ * 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.
++ */
++
++#ifndef __MXC_SPI_MX27_H__
++#define __MXC_SPI_MX27_H__
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++
++/*
++ * This structure is used to define the SPI master controller's platform
++ * data. It includes the SPI bus number and the maximum number of
++ * slaves/chips it supports.
++ */
++struct mxc_spi_master {
++ unsigned int bus_num; /* bus number. */
++ unsigned int maxchipselect; /* number of chip selects. */
++ unsigned int spi_version; /* CSPI Hardware Version. */
++
++ int (*init)(struct platform_device *pdev);
++ int (*exit)(struct platform_device *pdev);
++};
++
++int mxc_init_spi(int id, struct mxc_spi_master *master);
++
++#define MXC_CSPIRXDATA 0x00
++#define MXC_CSPITXDATA 0x04
++#define MXC_CSPICTRL 0x08
++#define MXC_CSPIINT 0x0C
++#define MXC_CSPIDMA 0x18
++#define MXC_CSPISTAT 0x0C
++#define MXC_CSPIPERIOD 0x14
++#define MXC_CSPITEST 0x10
++#define MXC_CSPIRESET 0x1C
++
++#define MXC_CSPICTRL_ENABLE (1 << 10)
++#define MXC_CSPICTRL_DISABLE 0x0
++#define MXC_CSPICTRL_MASTER (1 << 11)
++#define MXC_CSPICTRL_SLAVE 0x0
++#define MXC_CSPICTRL_XCH (1 << 9)
++#define MXC_CSPICTRL_LOWPOL (1 << 5)
++#define MXC_CSPICTRL_HIGHPOL 0x0
++#define MXC_CSPICTRL_PHA (1 << 6)
++#define MXC_CSPICTRL_NOPHA 0x0
++#define MXC_CSPICTRL_SSCTL (1 << 7)
++#define MXC_CSPICTRL_HIGHSSPOL (1 << 8)
++#define MXC_CSPICTRL_LOWSSPOL 0x0
++#define MXC_CSPICTRL_CSMASK 0x3
++#define MXC_CSPICTRL_MAXDATRATE 0x10
++#define MXC_CSPICTRL_DATAMASK 0x1F
++#define MXC_CSPICTRL_DATASHIFT 14
++/* This adjustment in the shift is valid only for even states only(i.e. divide
++ ratio of 2). SDHC_SPIEN is not set by default. If SDHC_SPIEN bit is set in
++ MXC_CSPICTRL, then divide ratio is 3, this shift adjustment is invalid. */
++#define MXC_CSPICTRL_ADJUST_SHIFT(x) ((x) = ((x) - 1) * 2)
++
++#define MXC_CSPICTRL_CSSHIFT_0_7 12
++#define MXC_CSPICTRL_BCSHIFT_0_7 20
++#define MXC_CSPICTRL_BCMASK_0_7 0xFFF
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_7 8
++
++#define MXC_CSPICTRL_CSSHIFT_0_5 12
++#define MXC_CSPICTRL_BCSHIFT_0_5 20
++#define MXC_CSPICTRL_BCMASK_0_5 0xFFF
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_5 8
++
++#define MXC_CSPICTRL_CSSHIFT_0_4 24
++#define MXC_CSPICTRL_BCSHIFT_0_4 8
++#define MXC_CSPICTRL_BCMASK_0_4 0x1F
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_4 20
++
++#define MXC_CSPICTRL_CSSHIFT_0_0 19
++#define MXC_CSPICTRL_BCSHIFT_0_0 0
++#define MXC_CSPICTRL_BCMASK_0_0 0x1F
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_0 12
++
++#define MXC_CSPIINT_IRQSHIFT_0_7 8
++#define MXC_CSPIINT_IRQSHIFT_0_5 9
++#define MXC_CSPIINT_IRQSHIFT_0_4 9
++#define MXC_CSPIINT_IRQSHIFT_0_0 18
++#define MXC_CSPIINT_TEEN (1 << 9)
++#define MXC_CSPIINT_THEN (1 << 10)
++#define MXC_CSPIINT_TFEN (1 << 11)
++#define MXC_CSPIINT_RREN (1 << 13)
++#define MXC_CSPIINT_RHEN (1 << 14)
++#define MXC_CSPIINT_RFEN (1 << 15)
++#define MXC_CSPIINT_ROEN (1 << 16)
++#define MXC_CSPIINT_TCEN_0_7 (1 << 7)
++#define MXC_CSPIINT_TCEN_0_5 (1 << 8)
++#define MXC_CSPIINT_TCEN_0_4 (1 << 8)
++#define MXC_CSPIINT_TCEN_0_0 (1 << 12)
++#define MXC_CSPIINT_BOEN_0_7 0
++#define MXC_CSPIINT_BOEN_0_5 (1 << 7)
++#define MXC_CSPIINT_BOEN_0_4 (1 << 7)
++#define MXC_CSPIINT_BOEN_0_0 (1 << 17)
++
++#define MXC_CSPISTAT_TE (1 << 0)
++#define MXC_CSPISTAT_TH (1 << 1)
++#define MXC_CSPISTAT_TF (1 << 2)
++#define MXC_CSPISTAT_RR (1 << 3)
++#define MXC_CSPISTAT_RH (1 << 4)
++#define MXC_CSPISTAT_RF (1 << 5)
++#define MXC_CSPISTAT_RO (1 << 6)
++#define MXC_CSPISTAT_TC_0_7 (1 << 7)
++#define MXC_CSPISTAT_TC_0_5 (1 << 8)
++#define MXC_CSPISTAT_TC_0_4 (1 << 8)
++#define MXC_CSPISTAT_TC_0_0 (1 << 3)
++#define MXC_CSPISTAT_BO_0_7 0
++#define MXC_CSPISTAT_BO_0_5 (1 << 7)
++#define MXC_CSPISTAT_BO_0_4 (1 << 7)
++#define MXC_CSPISTAT_BO_0_0 (1 << 8)
++
++#define MXC_CSPIPERIOD_32KHZ (1 << 15)
++
++#define MXC_CSPITEST_LBC (1 << 14)
++
++/*
++ * This structure contains information that differs with
++ * SPI master controller hardware version
++ */
++struct mxc_spi_unique_def {
++ unsigned int intr_bit_shift; /* Width of valid bits in MXC_CSPIINT. */
++ unsigned int cs_shift; /* Chip Select shift. */
++ unsigned int bc_shift; /* Bit count shift. */
++ unsigned int bc_mask; /* Bit count mask. */
++ unsigned int drctrl_shift; /* Data Control shift. */
++ unsigned int xfer_complete; /* Transfer Complete shift. */
++ unsigned int bc_overflow; /* Bit counnter overflow shift. */
++};
++#endif //__MXC_SPI_MX27_H__
+Index: arch/arm/mach-mx2/devices.c
+===================================================================
+--- linux/arch/arm/mach-mx2/devices.c.orig
++++ linux/arch/arm/mach-mx2/devices.c
+@@ -29,9 +29,149 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
++#include <asm/arch/imx_spi.h>
++#include <asm/arch/imx_i2c.h>
++#include <asm/arch/imx_fb.h>
++#include <linux/spi/spi.h>
+
+ #include <asm/hardware.h>
+
++struct platform_device mxc_w1_device = {
++ .name = "mxc_w1",
++ .id = 0
++};
++
++struct platform_device mxc_rtc_device = {
++ .name = "mxc_rtc",
++ .id = 0,
++};
++
++#if 0
++/* FIXME: declaration of struct mxc_mmc_platform_data missing in patch */
++/* MMC device data */
++extern unsigned int sdhc_get_card_det_status(struct device *dev);
++extern int sdhc_init_card_det(int id);
++
++struct mxc_mmc_platform_data mmc_data = {
++ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30,
++ .min_clk = 150000,
++ .max_clk = 25000000,
++ .card_inserted_state = 0,
++ .status = sdhc_get_card_det_status,
++};
++
++/*
++ * Resource definition for the SDHC1
++ */
++static struct resource mxc_sdhc1_resources[] = {
++ [0] = {
++ .start = SDHC1_BASE_ADDR,
++ .end = SDHC1_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_SDHC1,
++ .end = INT_SDHC1,
++ .flags = IORESOURCE_IRQ,
++ },
++ [2] = {
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_IRQ,
++ },
++ [3] = {
++ .start = MXC_SDIO1_CARD_IRQ,
++ .end = MXC_SDIO1_CARD_IRQ,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++/* Device Definition for MXC SDHC1 */
++struct platform_device mxc_sdhc1_device = {
++ .name = "mxcmci",
++ .id = 0,
++ .dev = {
++ .platform_data = &mmc_data,
++ },
++ .num_resources = ARRAY_SIZE(mxc_sdhc1_resources),
++ .resource = mxc_sdhc1_resources,
++};
++
++/*
++ * Resource definition for the SDHC2
++ */
++static struct resource mxc_sdhc2_resources[] = {
++ [0] = {
++ .start = SDHC2_BASE_ADDR,
++ .end = SDHC2_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_SDHC2,
++ .end = INT_SDHC2,
++ .flags = IORESOURCE_IRQ,
++ },
++ [2] = {
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_IRQ,
++ },
++ [3] = {
++ .start = MXC_SDIO2_CARD_IRQ,
++ .end = MXC_SDIO2_CARD_IRQ,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++/* Device Definition for MXC SDHC2 */
++struct platform_device mxc_sdhc2_device = {
++ .name = "mxcmci",
++ .id = 1,
++ .dev = {
++ .platform_data = &mmc_data,
++ },
++ .num_resources = ARRAY_SIZE(mxc_sdhc2_resources),
++ .resource = mxc_sdhc2_resources,
++};
++
++/*
++ * Resource definition for the SDHC3
++ */
++static struct resource mxc_sdhc3_resources[] = {
++ [0] = {
++ .start = SDHC3_BASE_ADDR,
++ .end = SDHC3_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_SDHC3,
++ .end = INT_SDHC3,
++ .flags = IORESOURCE_IRQ,
++ },
++ [2] = {
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_IRQ,
++ },
++ [3] = {
++ .start = MXC_SDIO3_CARD_IRQ,
++ .end = MXC_SDIO3_CARD_IRQ,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++/* Device Definition for MXC SDHC3 */
++struct platform_device mxc_sdhc3_device = {
++ .name = "mxcmci",
++ .id = 2,
++ .dev = {
++ .platform_data = &mmc_data,
++ },
++ .num_resources = ARRAY_SIZE(mxc_sdhc3_resources),
++ .resource = mxc_sdhc3_resources,
++};
++#endif
++
+ /*
+ * Resource definition for the MXC IrDA
+ */
+@@ -56,6 +196,85 @@
+ .resource = mxc_irda_resources,
+ };
+
++/* Platform Data for MXC VPU */
++struct platform_device mxc_vpu_device = {
++ .name = "mxc_vpu",
++ .id = 0,
++};
++
++/*
++ * SPI master controller
++ *
++ * - i.MX1: 2 channel (slighly different register setting)
++ * - i.MX21: 2 channel
++ * - i.MX27: 3 channel
++ */
++static struct resource imx_spi_0_resources[] = {
++ [0] = {
++ .start = CSPI1_BASE_ADDR,
++ .end = CSPI1_BASE_ADDR + 0x1F,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_CSPI1,
++ .end = INT_CSPI1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct resource imx_spi_1_resources[] = {
++ [0] = {
++ .start = CSPI2_BASE_ADDR,
++ .end = CSPI2_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_CSPI2,
++ .end = INT_CSPI2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct resource imx_spi_2_resources[] = {
++ [0] = {
++ .start = CSPI3_BASE_ADDR,
++ .end = CSPI3_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_CSPI3,
++ .end = INT_CSPI3,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device imx_spi_devices[] = {
++ {
++ .name = "mxc_spi",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(imx_spi_0_resources),
++ .resource = imx_spi_0_resources,
++ }, {
++ .name = "mxc_spi",
++ .id = 1,
++ .num_resources = ARRAY_SIZE(imx_spi_1_resources),
++ .resource = imx_spi_1_resources,
++ }
++};
++
++int mxc_init_spi(int id, struct mxc_spi_master *master)
++{
++ imx_spi_devices[id].dev.platform_data = master;
++ return platform_device_register(&imx_spi_devices[id]);
++}
++
++struct platform_device imx_spi_2_device = {
++ .name = "mxc_spi",
++ .id = 2,
++ .num_resources = ARRAY_SIZE(imx_spi_2_resources),
++ .resource = imx_spi_2_resources,
++};
++
+ /*
+ * General Purpose Timer
+ * - i.MX1: 2 timer (slighly different register handling)
+@@ -167,6 +386,59 @@
+ };
+ #endif
+
++/* I2C channel #1 */
++static struct resource imx_i2c_1_resources[] = {
++ [0] = {
++ .start = I2C_BASE_ADDR,
++ .end = I2C_BASE_ADDR + 0x0F,
++ .flags = IORESOURCE_MEM
++ },
++ [1] = {
++ .start = INT_I2C,
++ .end = INT_I2C,
++ .flags = IORESOURCE_IRQ
++ }
++};
++
++#ifdef CONFIG_MACH_MX27
++static struct resource imx_i2c_2_resources[] = {
++ [0] = {
++ .start = I2C2_BASE_ADDR,
++ .end = I2C2_BASE_ADDR + 0x0F,
++ .flags = IORESOURCE_MEM
++ },
++ [1] = {
++ .start = INT_I2C2,
++ .end = INT_I2C2,
++ .flags = IORESOURCE_IRQ
++ }
++};
++
++#endif
++
++struct platform_device imx_i2c_devices[] = {
++ {
++ .name = "imx_i2c",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(imx_i2c_1_resources),
++ .resource = imx_i2c_1_resources
++ },
++#ifdef CONFIG_MACH_MX27
++ {
++ .name = "imx_i2c",
++ .id = 1,
++ .num_resources = ARRAY_SIZE(imx_i2c_2_resources),
++ .resource = imx_i2c_2_resources
++ }
++#endif
++};
++
++int mxc_init_i2c(int id, struct imx_i2c_platform_data *data)
++{
++ imx_i2c_devices[id].dev.platform_data = data;
++ return platform_device_register(&imx_i2c_devices[id]);
++}
++
+ /*
+ * Watchdog:
+ * - i.MX1
+@@ -187,3 +459,33 @@
+ .num_resources = ARRAY_SIZE(mxc_wdt_resources),
+ .resource = mxc_wdt_resources,
+ };
++static struct resource mxc_fb[] = {
++ {
++ .start = LCDC_BASE_ADDR,
++ .end = LCDC_BASE_ADDR + 0xFFF,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = INT_LCDC,
++ .end = INT_LCDC,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++/* mxc lcd driver */
++struct platform_device mxc_fb_device = {
++ .name = "mxc_sdc_fb",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mxc_fb),
++ .resource = mxc_fb,
++ .dev = {
++ .platform_data = NULL, /* no default video mode */
++ .coherent_dma_mask = 0xFFFFFFFF,
++ },
++};
++
++int mxc_init_fb(struct mxc_fb_platform_data *pdata)
++{
++ mxc_fb_device.dev.platform_data = pdata;
++ return platform_device_register(&mxc_fb_device);
++}
+Index: arch/arm/mach-mx2/devices.h
+===================================================================
+--- linux/arch/arm/mach-mx2/devices.h.orig
++++ linux/arch/arm/mach-mx2/devices.h
+@@ -15,7 +15,14 @@
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
++extern struct platform_device mxc_sdhc1_device;
++extern struct platform_device mxc_sdhc2_device;
++extern struct platform_device mxc_sdhc3_device;
+ extern struct platform_device mxc_irda_device;
++extern struct platform_device mxc_vpu_device;
++extern struct platform_device imx_spi_0_device;
++extern struct platform_device imx_spi_1_device;
++extern struct platform_device imx_spi_2_device;
+ extern struct platform_device mxc_gpt0;
+ extern struct platform_device mxc_gpt1;
+ extern struct platform_device mxc_gpt2;
+@@ -24,4 +31,11 @@ extern struct platform_device mxc_gpt3;
+ extern struct platform_device mxc_gpt4;
+ extern struct platform_device mxc_gpt5;
+ #endif
++extern struct platform_device imx_i2c_1_device;
++#ifdef CONFIG_MACH_MX27
++extern struct platform_device imx_i2c_2_device;
++#endif
+ extern struct platform_device mxc_wdt;
++extern struct platform_device mxc_fb_device;
++
++
+Index: include/asm-arm/arch-mxc/imx_fb.h
+===================================================================
+--- /dev/null
++++ linux/include/asm-arm/arch-mxc/imx_fb.h
+@@ -0,0 +1,81 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, ke...@pe...
++ *
++ * 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.
++ */
++
++#ifndef __ASM_ARCH_MXCFB_H__
++#define __ASM_ARCH_MXCFB_H__
++
++#include <linux/fb.h>
++#include <linux/platform_device.h>
++
++struct mxc_fb_platform_data {
++ char *mode;
++
++ int (*init)(struct platform_device *pdev);
++ int (*exit)(struct platform_device *pdev);
++
++ int (*power_lcd)(struct platform_device *pdev, int on);
++};
++
++
++int mxc_init_fb(struct mxc_fb_platform_data *pdata);
++
++#define FB_SYNC_OE_ACT_HIGH 0x80000000
++#define FB_SYNC_CLK_INVERT 0x40000000
++#define FB_SYNC_DATA_INVERT 0x20000000
++#define FB_SYNC_CLK_IDLE_EN 0x10000000
++#define FB_SYNC_SHARP_MODE 0x08000000
++#define FB_SYNC_SWAP_RGB 0x04000000
++
++struct mxcfb_gbl_alpha {
++ int enable;
++ int alpha;
++};
++
++struct mxcfb_color_key {
++ int enable;
++ __u32 color_key;
++};
++
++#define MXCFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
++#define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha)
++#define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key)
++#define MXCFB_SET_BRIGHTNESS _IOW('F', 0x23, __u8)
++
++#ifdef __KERNEL__
++
++extern const struct fb_videomode mxcfb_modedb[];
++extern int mxcfb_modedb_sz;
++
++enum {
++ MXCFB_REFRESH_OFF,
++ MXCFB_REFRESH_AUTO,
++ MXCFB_REFRESH_PARTIAL,
++};
++
++struct mxcfb_rect {
++ u32 top;
++ u32 left;
++ u32 width;
++ u32 height;
++};
++
++int mxcfb_set_refresh_mode(struct fb_info *fbi, int mode,
++ struct mxcfb_rect *update_region);
++
++#endif /* __KERNEL__ */
++#endif
Added: branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/231-apf27-pengu-mxc_i2c_driver.diff
===================================================================
--- branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/231-apf27-pengu-mxc_i2c_driver.diff (rev 0)
+++ branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/231-apf27-pengu-mxc_i2c_driver.diff 2008-04-03 06:43:24 UTC (rev 788)
@@ -0,0 +1,712 @@
+Subject: [@num@/@total@] i.MXC family: I2C master driver
+From: Juergen Beisert <j.b...@pe...>
+
+This patch adds I2C master driver for i.MX family.
+
+Signed-off-by: Juergen Beisert <j.b...@pe...>
+Signed-off-by: N.N. (FIXME: get a sign from freescale)
+
+---
+
+ drivers/i2c/busses/Kconfig | 10
+ drivers/i2c/busses/Makefile | 1
+ drivers/i2c/busses/imx_i2c.c | 659 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 670 insertions(+)
+
+Index: drivers/i2c/busses/Kconfig
+===================================================================
+--- linux/drivers/i2c/busses/Kconfig.orig
++++ linux/drivers/i2c/busses/Kconfig
+@@ -302,6 +302,16 @@ config I2C_MPC
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mpc.
+
++config I2C_MXC
++ tristate "MXC I2C support"
++ depends on I2C && ARCH_MXC
++ help
++ If you say yes to this option, support will be included for Freescale
++ i.MX2 family of processors (like i.MX21 and i.MX27).
++
++ This driver can also be built as a module. If so, the module
++ will be called imx_i2c.
++
+ config I2C_NFORCE2
+ tristate "Nvidia nForce2, nForce3 and nForce4"
+ depends on PCI
+Index: drivers/i2c/busses/Makefile
+===================================================================
+--- linux/drivers/i2c/busses/Makefile.orig
++++ linux/drivers/i2c/busses/Makefile
+@@ -52,6 +52,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
+ obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+ obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+ obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
++obj-$(CONFIG_I2C_MXC) += imx_i2c.o
+
+ ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
+ EXTRA_CFLAGS += -DDEBUG
+Index: drivers/i2c/busses/imx_i2c.c
+===================================================================
+--- /dev/null
++++ linux/drivers/i2c/busses/imx_i2c.c
+@@ -0,0 +1,659 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, ke...@pe...
++ *
++ * 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.
++ */
++
++/*
++ * Driver for the Freescale Semiconductor MXC I2C buses.
++ * Based on i2c driver algorithm for PCF8584 adapters
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/arch/clock.h>
++#include <asm/arch/imx_i2c.h>
++
++#define DRV_NAME "imx_i2c"
++
++typedef struct {
++ struct i2c_adapter adap;
++ wait_queue_head_t wq;
++ unsigned long membase; /* FIXME iomem? */
++ int irq;
++ unsigned int clkdiv;
++ struct clk *clk;
++ bool low_power;
++ struct imx_i2c_platform_data *pdata;
++} imx_i2c_device;
++
++/*
++ * HACK: Why is it not channel specific?
++ * Boolean to indicate if data was transferred
++ */
++static bool transfer_done = false;
++
++/*
++ * HACK: Why is it not channel specific?
++ * Boolean to indicate if we received an ACK for the data transmitted
++ */
++static bool tx_success = false;
++
++struct clk_div_table {
++ int reg_value;
++ int div;
++};
++
++static const struct clk_div_table i2c_clk_table[] = {
++ {0x20, 22}, {0x21, 24}, {0x22, 26}, {0x23, 28},
++ {0, 30}, {1, 32}, {0x24, 32}, {2, 36},
++ {0x25, 36}, {0x26, 40}, {3, 42}, {0x27, 44},
++ {4, 48}, {0x28, 48}, {5, 52}, {0x29, 56},
++ {6, 60}, {0x2A, 64}, {7, 72}, {0x2B, 72},
++ {8, 80}, {0x2C, 80}, {9, 88}, {0x2D, 96},
++ {0xA, 104}, {0x2E, 112}, {0xB, 128}, {0x2F, 128},
++ {0xC, 144}, {0xD, 160}, {0x30, 160}, {0xE, 192},
++ {0x31, 192}, {0x32, 224}, {0xF, 240}, {0x33, 256},
++ {0x10, 288}, {0x11, 320}, {0x34, 320}, {0x12, 384},
++ {0x35, 384}, {0x36, 448}, {0x13, 480}, {0x37, 512},
++ {0x14, 576}, {0x15, 640}, {0x38, 640}, {0x16, 768},
++ {0x39, 768}, {0x3A, 896}, {0x17, 960}, {0x3B, 1024},
++ {0x18, 1152}, {0x19, 1280}, {0x3C, 1280}, {0x1A, 1536},
++ {0x3D, 1536}, {0x3E, 1792}, {0x1B, 1920}, {0x3F, 2048},
++ {0x1C, 2304}, {0x1D, 2560}, {0x1E, 3072}, {0x1F, 3840},
++ {0, 0}
++};
++
++/* Transmit a STOP signal to the slave device */
++static void imx_i2c_stop(imx_i2c_device * dev)
++{
++ unsigned int cr;
++ int retry = 16;
++
++ cr = readw(dev->membase + MXC_I2CR);
++ cr &= ~(MXC_I2CR_MSTA | MXC_I2CR_MTX);
++ writew(cr, dev->membase + MXC_I2CR);
++
++ /*
++ * Make sure STOP meets setup requirement.
++ */
++ for (;;) {
++ unsigned int sr = readw(dev->membase + MXC_I2SR);
++ if ((sr & MXC_I2SR_IBB) == 0) break;
++ if (retry-- <= 0) {
++ printk(KERN_DEBUG "Bus busy\n");
++ break;
++ }
++ udelay(3);
++ }
++}
++
++/*
++ * Wait for the transmission of the data byte to complete. This function waits
++ * till we get a signal from the interrupt service routine indicating completion
++ * of the address cycle or we time out.
++ * The function returns 0 on success or -1 if an ack was not received
++ */
++static int imx_i2c_wait_for_tc(imx_i2c_device * dev, int trans_flag)
++{
++ int retry = 16;
++
++ while (retry-- && !transfer_done) {
++ wait_event_interruptible_timeout(dev->wq,
++ transfer_done,
++ dev->adap.timeout);
++ }
++ transfer_done = false;
++
++ if (retry <= 0) {
++ /* Unable to send data */
++ printk(KERN_DEBUG "Data not transmitted\n");
++ return -1;
++ } else if (!(trans_flag & I2C_M_RD)) {
++ if (!tx_success) {
++ /* An ACK was not received for transmitted byte */
++ printk(KERN_DEBUG "ACK not received \n");
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++/* Transmit a START signal to the slave device */
++static void imx_i2c_start(imx_i2c_device * dev, struct i2c_msg *msg)
++{
++ unsigned int cr, sr;
++ unsigned int addr_trans;
++ int retry = 16;
++
++ /*
++ * Set the slave address and the requested transfer mode
++ * in the data register
++ */
++ addr_trans = msg->addr << 1;
++ if (msg->flags & I2C_M_RD) {
++ addr_trans |= 0x01;
++ }
++
++ /* Set the Master bit */
++ cr = readw(dev->membase + MXC_I2CR);
++ cr |= MXC_I2CR_MSTA;
++ writew(cr, dev->membase + MXC_I2CR);
++
++ /* Wait till the Bus Busy bit is set */
++ sr = readw(dev->membase + MXC_I2SR);
++ while (retry-- && (!(sr & MXC_I2SR_IBB))) {
++ udelay(3);
++ sr = readw(dev->membase + MXC_I2SR);
++ }
++ if (retry <= 0) {
++ printk(KERN_DEBUG "Could not grab Bus ownership\n");
++ }
++
++ /* Set the Transmit bit */
++ cr = readw(dev->membase + MXC_I2CR);
++ cr |= MXC_I2CR_MTX;
++ writew(cr, dev->membase + MXC_I2CR);
++
++ writew(addr_trans, dev->membase + MXC_I2DR);
++}
++
++/* Transmit a REPEAT START to the slave device */
++static void imx_i2c_repstart(imx_i2c_device * dev, struct i2c_msg *msg)
++{
++ unsigned int cr;
++ unsigned int addr_trans;
++
++ /*
++ * Set the slave address and the requested transfer mode
++ * in the data register
++ */
++ addr_trans = msg->addr << 1;
++ if (msg->flags & I2C_M_RD) {
++ addr_trans |= 0x01;
++ }
++ cr = readw(dev->membase + MXC_I2CR);
++ cr |= MXC_I2CR_RSTA;
++ writew(cr, dev->membase + MXC_I2CR);
++ udelay(3);
++ writew(addr_trans, dev->membase + MXC_I2DR);
++}
++
++/*
++ * Read the received data. The function waits till data is available or times
++ * out. Generates a stop signal if this is the last message to be received.
++ * Sends an ack for all the bytes received except the last byte.
++ * The function returns the number of bytes read or -1 on time out.
++ */
++static int imx_i2c_readbytes(imx_i2c_device * dev, struct i2c_msg *msg,
++ int last, int addr_comp)
++{
++ int i;
++ char *buf = msg->buf;
++ int len = msg->len;
++ unsigned int cr;
++
++ cr = readw(dev->membase + MXC_I2CR);
++
++ /* switch to receive mode */
++ cr &= ~MXC_I2CR_MTX;
++ /*
++ * Clear the TXAK bit to gen an ack when receiving only one byte.
++ */
++ if (len == 1)
++ cr |= MXC_I2CR_TXAK;
++ else
++ cr &= ~MXC_I2CR_TXAK;
++
++ writew(cr, dev->membase + MXC_I2CR);
++ /*
++ * Dummy read only at the end of an address cycle
++ */
++ if (addr_comp > 0)
++ readw(dev->membase + MXC_I2DR);
++
++ for (i = 0; i < len; i++) {
++ /* Wait for data transmission to complete */
++ if (imx_i2c_wait_for_tc(dev, msg->flags)) {
++ imx_i2c_stop(dev);
++ return -1;
++ }
++ /* Do not generate an ACK for the last byte */
++ if (i == (len - 2)) {
++ cr = readw(dev->membase + MXC_I2CR);
++ cr |= MXC_I2CR_TXAK;
++ writew(cr, dev->membase + MXC_I2CR);
++ } else if (i == (len - 1)) {
++ if (last)
++ imx_i2c_stop(dev);
++ }
++ /* Read the data */
++ *buf++ = readw(dev->membase + MXC_I2DR);
++ }
++
++ return i;
++}
++
++/*
++ * Write the data to the data register. Generates a stop signal if this is
++ * the last message to be sent or if no ack was received for the data sent.
++ * The function returns the number of bytes written or -1 on time out
++ * or if no ack was received for the data that was sent.
++ */
++static int imx_i2c_writebytes(imx_i2c_device * dev, struct i2c_msg *msg,
++ int last)
++{
++ int i;
++ char *buf = msg->buf;
++ int len = msg->len;
++ unsigned int cr;
++
++ cr = readw(dev->membase + MXC_I2CR);
++ /* switch to transmit mode */
++ cr |= MXC_I2CR_MTX;
++ writew(cr, dev->membase + MXC_I2CR);
++
++ for (i = 0; i < len; i++) {
++ /* Write the data */
++ writew(*buf++, dev->membase + MXC_I2DR);
++ if (imx_i2c_wait_for_tc(dev, msg->flags)) {
++ imx_i2c_stop(dev);
++ return -1;
++ }
++ }
++ if (last > 0) {
++ imx_i2c_stop(dev);
++ }
++
++ return i;
++}
++
++/* Function enables the I2C module and initializes the registers */
++static void imx_i2c_module_en(imx_i2c_device * dev, int trans_flag)
++{
++ clk_enable(dev->clk);
++ /* Set the frequency divider */
++ writew(dev->clkdiv, dev->membase + MXC_IFDR);
++ /* Clear the status register */
++ writew(0x0, dev->membase + MXC_I2SR);
++ /* Enable I2C and its interrupts */
++ writew(MXC_I2CR_IEN, dev->membase + MXC_I2CR);
++ writew(MXC_I2CR_IEN | MXC_I2CR_IIEN, dev->membase + MXC_I2CR);
++}
++
++/* Disables the I2C module */
++static void imx_i2c_module_dis(imx_i2c_device * dev)
++{
++ writew(0x0, dev->membase + MXC_I2CR);
++ clk_disable(dev->clk);
++}
++
++/*
++ * The function is registered in the adapter structure. It is called when an MXC
++ * driver wishes to transfer data to a device connected to the I2C device.
++ * The function returns the number of messages transferred, -EREMOTEIO on I2C
++ * failure and a 0 if the num argument is less than 0.
++ */
++static int imx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
++ int num)
++{
++ imx_i2c_device *dev = (imx_i2c_device *) (i2c_get_adapdata(adap));
++ int i, ret = 0, addr_comp = 0;
++ unsigned int sr;
++
++ if (dev->low_power) {
++ printk(KERN_ERR "I2C Device in low power mode\n");
++ return -EREMOTEIO;
++ }
++
++ if (num < 1)
++ return 0;
++
++ imx_i2c_module_en(dev, msgs[0].flags);
++ sr = readw(dev->membase + MXC_I2SR);
++
++ /* Check bus state */
++ if (sr & MXC_I2SR_IBB) {
++ imx_i2c_module_dis(dev);
++ printk(KERN_DEBUG "Bus busy\n");
++ return -EREMOTEIO;
++ }
++
++ transfer_done = false;
++ tx_success = false;
++ for (i = 0; i < num && ret >= 0; i++) {
++ addr_comp = 0;
++ /*
++ * Send the slave address and transfer direction in the
++ * address cycle
++ */
++ if (i == 0) {
++ /* Send a start or repeat start signal */
++ imx_i2c_start(dev, &msgs[0]);
++ /* Wait for the address cycle to complete */
++ if (imx_i2c_wait_for_tc(dev, msgs[0].flags)) {
++ imx_i2c_stop(dev);
++ imx_i2c_module_dis(dev);
++ return -EREMOTEIO;
++ }
++ addr_comp = 1;
++ } else {
++ /*
++ * Generate repeat start only if required i.e the address
++ * changed or the transfer direction changed
++ */
++ if ((msgs[i].addr != msgs[i - 1].addr) ||
++ ((msgs[i].flags & I2C_M_RD) !=
++ (msgs[i - 1].flags & I2C_M_RD))) {
++ imx_i2c_repstart(dev, &msgs[i]);
++ /* Wait for the address cycle to complete */
++ if (imx_i2c_wait_for_tc(dev, msgs[i].flags)) {
++ imx_i2c_stop(dev);
++ imx_i2c_module_dis(dev);
++ return -EREMOTEIO;
++ }
++ addr_comp = 1;
++ }
++ }
++
++ /* Transfer the data */
++ if (msgs[i].flags & I2C_M_RD) {
++ /* Read the data */
++ ret = imx_i2c_readbytes(dev, &msgs[i], (i + 1 == num),
++ addr_comp);
++ if (ret < 0) {
++ printk(KERN_ERR "imx_i2c_readbytes: fail.\n");
++ break;
++ }
++ } else {
++ /* Write the data */
++ ret = imx_i2c_writebytes(dev, &msgs[i], (i + 1 == num));
++ if (ret < 0) {
++ printk(KERN_ERR "imx_i2c_writebytes: fail.\n");
++ break;
++ }
++ }
++ }
++
++ imx_i2c_module_dis(dev);
++ return i;
++}
++
++/*
++ * Returns the i2c functionality supported by this driver.
++ * Returns the functionality that is supported.
++ */
++static u32 imx_i2c_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++/*
++ * Stores the pointers for the i2c algorithm functions. The algorithm functions
++ * is used by the i2c bus driver to talk to the i2c bus
++ */
++static struct i2c_algorithm imx_i2c_algorithm = {
++ .master_xfer = imx_i2c_xfer,
++ .functionality = imx_i2c_func
++};
++
++/*
++ * Interrupt Service Routine. It signals to the process about the data transfer
++ * completion. Also sets a flag if bus arbitration is lost.
++ * The function returns IRQ_HANDLED.
++ */
++static irqreturn_t imx_i2c_handler(int irq, void *dev_id)
++{
++ imx_i2c_device *dev = dev_id;
++ unsigned int sr, cr;
++
++ sr = readw(dev->membase + MXC_I2SR);
++ cr = readw(dev->membase + MXC_I2CR);
++
++ /*
++ * Clear the interrupt bit
++ */
++ writew(0x0, dev->membase + MXC_I2SR);
++
++ if (sr & MXC_I2SR_IAL) {
++ printk(KERN_DEBUG "Bus Arbitration lost\n");
++ } else {
++ /* Interrupt due byte transfer completion */
++ tx_success = false;
++ /* Check if RXAK is received in Transmit mode */
++ if ((cr & MXC_I2CR_MTX) && (!(sr & MXC_I2SR_RXAK))) {
++ tx_success = true;
++ }
++ transfer_done = true;
++ wake_up_interruptible(&dev->wq);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * This function is called to put the I2C adapter in a low power state. Refer to the
++ * document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ * The function returns 0 on success and -1 on failure.
++ */
++static int mxci2c_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ imx_i2c_device *mxcdev = platform_get_drvdata(pdev);
++ unsigned int sr;
++
++ if (mxcdev == NULL)
++ return -1;
++
++ /* Prevent further calls to be processed */
++ mxcdev->low_power = true;
++ /* Wait till we finish the current transfer */
++ sr = readw(mxcdev->membase + MXC_I2SR);
++ while (sr & MXC_I2SR_IBB) {
++ msleep(10);
++ sr = readw(mxcdev->membase + MXC_I2SR);
++ }
++
++ mxcdev->pdata->exit(pdev);
++
++ return 0;
++}
++
++/*
++ * This function is called to bring the I2C adapter back from a low power state. Refer
++ * to the document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ * The function returns 0 on success and -1 on failure
++ */
++static int mxci2c_resume(struct platform_device *pdev)
++{
++ imx_i2c_device *mxcdev = platform_get_drvdata(pdev);
++
++ if (mxcdev == NULL)
++ return -1;
++
++ mxcdev->low_power = false;
++ mxcdev->pdata->init(pdev);
++
++ return 0;
++}
++
++/*
++ * This function is called during the driver binding process.
++ * The function always returns 0.
++ */
++static int mxci2c_probe(struct platform_device *pdev)
++{
++ imx_i2c_device *imx_i2c;
++ struct imx_i2c_platform_data *i2c_plat_data = pdev->dev.platform_data;
++ struct resource *res;
++ int id = pdev->id;
++ u32 clk_freq;
++ int ret = 0;
++ int i=0;
++
++ imx_i2c = kzalloc(sizeof(imx_i2c_device), GFP_KERNEL);
++ if (!imx_i2c) {
++ return -ENOMEM;
++ }
++
++ imx_i2c->pdata = i2c_plat_data;
++ /* claim the region we will work on */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ ret = -ENODEV;
++ goto err1;
++ }
++ if (!request_mem_region(res->start, res->end - res->start + 1, DRV_NAME)) {
++ dev_err(&pdev->dev, "request_mem_region failed for IMX I2C %d\n", id);
++ ret = -EBUSY;
++ goto err1;
++ }
++
++ /* TODO: use iomap() */
++ imx_i2c->membase = IO_ADDRESS(res->start);
++
++ /* Claim the I2C irq line */
++ imx_i2c->irq = platform_get_irq(pdev, 0);
++ if (imx_i2c->irq < 0) {
++ dev_err(&pdev->dev, "No interrupt defined for IMX I2C %d\n", id);
++ ret = imx_i2c->irq;
++ goto err2;
++ }
++ ret = request_irq(imx_i2c->irq, imx_i2c_handler,
++ 0, DRV_NAME, imx_i2c);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Cannot claim interrupt %d for IMX I2C %d\n",
++ imx_i2c->irq, id);
++ goto err2;
++ }
++
++ init_waitqueue_head(&imx_i2c->wq);
++
++ imx_i2c->low_power = false;
++
++ imx_i2c->pdata->init(pdev);
++
++ imx_i2c->clk = clk_get(&pdev->dev, "i2c_clk");
++ if (imx_i2c == NULL) {
++ dev_err(&pdev->dev, "Cannot get clock for for IMX I2C %d\n", id);
++ goto err3;
++ }
++
++ clk_freq = clk_get_rate(imx_i2c->clk);
++ imx_i2c->clkdiv = -1;
++ if (i2c_plat_data->i2c_clk) {
++ /* Calculate divider and round up any fractional part */
++ int div = (clk_freq + i2c_plat_data->i2c_clk - 1) /
++ i2c_plat_data->i2c_clk;
++ for (i = 0; i2c_clk_table[i].div != 0; i++) {
++ if (i2c_clk_table[i].div >= div) {
++ imx_i2c->clkdiv = i2c_clk_table[i].reg_value;
++ break;
++ }
++ }
++ }
++ if (imx_i2c->clkdiv == -1) {
++ i--;
++ imx_i2c->clkdiv = 0x1F; /* Use max divider */
++ }
++ dev_dbg(&pdev->dev, "i2c speed is %d/%d = %d bps, reg val = 0x%02X\n",
++ clk_freq, i2c_clk_table[i].div,
++ clk_freq / i2c_clk_table[i].div, imx_i2c->clkdiv);
++
++ /*
++ * Set the adapter information
++ */
++ strcpy(imx_i2c->adap.name, MXC_ADAPTER_NAME);
++ imx_i2c->adap.id = id;
++ imx_i2c->adap.nr = id;
++ imx_i2c->adap.algo = &imx_i2c_algorithm;
++ imx_i2c->adap.timeout = 1;
++ platform_set_drvdata(pdev, imx_i2c);
++ i2c_set_adapdata(&imx_i2c->adap, imx_i2c);
++ if ((ret = i2c_add_numbered_adapter(&imx_i2c->adap)) < 0) {
++ dev_err(&pdev->dev, "Cannot register the IMX I2C %d master\n", id);
++ goto err3;
++ }
++
++ return 0;
++
++err3:
++ imx_i2c->pdata->exit(pdev);
++ free_irq(imx_i2c->irq, imx_i2c);
++err2:
++ release_mem_region(res->start, res->end - res->start + 1);
++err1:
++ dev_err(&pdev->dev, "failed to probe i2c adapter\n");
++ kfree(imx_i2c);
++ return ret;
++}
++
++/*
++ * Dissociates the driver from the I2C device.
++ */
++static int mxci2c_remove(struct platform_device *pdev)
++{
++ imx_i2c_device *imx_i2c = platform_get_drvdata(pdev);
++ struct resource *res;
++
++ free_irq(imx_i2c->irq, imx_i2c);
++ i2c_del_adapter(&imx_i2c->adap);
++ imx_i2c->pdata->exit(pdev);
++ clk_put(imx_i2c->clk);
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(res->start, res->end - res->start + 1);
++ platform_set_drvdata(pdev, NULL);
++ return 0;
++}
++
++/*
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxci2c_driver = {
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = mxci2c_probe,
++ .remove = mxci2c_remove,
++ .suspend = mxci2c_suspend,
++ .resume = mxci2c_resume,
++};
++
++static int __init imx_i2c_init(void)
++{
++ return platform_driver_register(&mxci2c_driver);
++}
++
++static void __exit imx_i2c_exit(void)
++{
++ platform_driver_unregister(&mxci2c_driver);
++}
++
++subsys_initcall(imx_i2c_init);
++module_exit(imx_i2c_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC I2C driver");
++MODULE_LICENSE("GPL");
Added: branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/232-apf27-pengu-imx27_spi_driver.diff
===================================================================
--- branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/232-apf27-pengu-imx27_spi_driver.diff (rev 0)
+++ branches/apf2/buildroot/target/device/armadeus/linux/kernel-patches/2.6.25-rc7/232-apf27-pengu-imx27_spi_driver.diff 2008-04-03 06:43:24 UTC (rev 788)
@@ -0,0 +1,821 @@
+Subject: [@num@/@total@] i.MX27: SPI driver
+From: Juergen Beisert <j.b...@pe...>
+
+This patch adds basic SPI master driver support for the i.MX family
+
+TODO: Discover what the mxc_spi_unique_def structures mean. Do they rely on
+internal silicon revisions or different family members (i.MX1, i.MX21, i.MX27)
+
+At least the i.MX21 and i.MX27 are using the same SPI device. iMX1 uses nearly
+the same, but with less register bits and data registers are only 16 bit
+instead of 32 bit.
+
+Signed-off-by: Juergen Beisert <j.b...@pe...>
+Signed-off-by: N.N. (FIXME: get a sign from freescale)
+
+---
+
+ drivers/spi/Kconfig | 27 +
+ drivers/spi/Makefile | 1
+ drivers/spi/mxc_spi.c | 744 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 772 insertions(+)
+
+Index: drivers/spi/mxc_spi.c
+===================================================================
+--- /dev/null
++++ linux/drivers/spi/mxc_spi.c
+@@ -0,0 +1,744 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2008 Juergen Beisert
++ *
++ * 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.
++ */
++
++#undef DEBUG
++
++#include <linux/completion.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/types.h>
++#include <linux/clk.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/imx_spi.h>
++
++#ifdef CONFIG_SPI_MXC_TEST_LOOPBACK
++struct spi_chip_info {
++ int lb_enable;
++};
++
++static struct spi_chip_info lb_chip_info = {
++ .lb_enable = 1,
++};
++
++static struct spi_board_info loopback_info[] = {
++#ifdef CONFIG_SPI_MXC_SELECT1
++ {
++ .modalias = "loopback_spi",
++ .controller_data = &lb_chip_info,
++ .irq = 0,
++ .max_speed_hz = 4000000,
++ .bus_num = 0,
++ .chip_select = 4,
++ },
++#endif
++#ifdef CONFIG_SPI_MXC_SELECT2
++ {
++ .modalias = "loopback_spi",
++ .controller_data = &lb_chip_info,
++ .irq = 0,
++ .max_speed_hz = 4000000,
++ .bus_num = 1,
++ .chip_select = 4,
++ },
++#endif
++#ifdef CONFIG_SPI_MXC_SELECT3
++ {
++ .modalias = "loopback_spi",
++ .controller_data = &lb_chip_info,
++ .irq = 0,
++ .max_speed_hz = 4000000,
++ .bus_num = 2,
++ .chip_select = 4,
++ },
++#endif
++};
++#endif
++
++static struct mxc_spi_unique_def spi_ver_0_7 = {
++ .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_7,
++ .cs_shift = MXC_CSPICTRL_CSSHIFT_0_7,
++ .bc_shift = MXC_CSPICTRL_BCSHIFT_0_7,
++ .bc_mask = MXC_CSPICTRL_BCMASK_0_7,
++ .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_7,
++ .xfer_complete = MXC_CSPISTAT_TC_0_7,
++ .bc_overflow = MXC_CSPISTAT_BO_0_7,
++};
++
++static struct mxc_spi_unique_def spi_ver_0_5 = {
++ .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_5,
++ .cs_shift = MXC_CSPICTRL_CSSHIFT_0_5,
++ .bc_shift = MXC_CSPICTRL_BCSHIFT_0_5,
++ .bc_mask = MXC_CSPICTRL_BCMASK_0_5,
++ .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_5,
++ .xfer_complete = MXC_CSPISTAT_TC_0_5,
++ .bc_overflow = MXC_CSPISTAT_BO_0_5,
++};
++
++static struct mxc_spi_unique_def spi_ver_0_4 = {
++ .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_4,
++ .cs_shift = MXC_CSPICTRL_CSSHIFT_0_4,
++ .bc_shift = MXC_CSPICTRL_BCSHIFT_0_4,
++ .bc_mask = MXC_CSPICTRL_BCMASK_0_4,
++ .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_4,
++ .xfer_complete = MXC_CSPISTAT_TC_0_4,
++ .bc_overflow = MXC_CSPISTAT_BO_0_4,
++};
++
++static struct mxc_spi_unique_def spi_ver_0_0 = {
++ .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_0,
++ .cs_shift = MXC_CSPICTRL_CSSHIFT_0_0,
++ .bc_shift = MXC_CSPICTRL_BCSHIFT_0_0,
++ .bc_mask = MXC_CSPICTRL_BCMASK_0_0,
++ .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_0,
++ .xfer_complete = MXC_CSPISTAT_TC_0_0,
++ .bc_overflow = MXC_CSPISTAT_BO_0_0,
++};
++
++struct mxc_spi;
++/*
++ * Structure to group together all the data buffers and functions
++ * used in data transfers.
++ */
++struct mxc_spi_xfer {
++ const void *tx_buf; /* Transmit buffer. */
++ void *rx_buf; /* Receive buffer. */
++ unsigned int count; /* Data transfered count. */
++ void (*rx_get) (struct mxc_spi *, u32 val); /* Function to read the FIFO data to rx_buf. */
++ u32(*tx_get) (struct mxc_spi *); /* Function to get the data to be written to FIFO. */
++};
++
++/*
++ * This structure is a way for the low level driver to define their own
++ * spi_master structure. This structure includes the core spi_master
++ * structure that is provided by Linux SPI Framework/driver as an
++ * element and has other elements that are specifically required by this
++ * low-level driver.
++ */
++struct mxc_spi {
++ struct spi_bitbang mxc_bitbang; /* SPI Master and a simple I/O queue runner. */
++ struct completion xfer_done; /* Completion flags used in data transfers. */
++ struct mxc_spi_xfer transfer; /* Data transfer structure. */
++ struct resource *res; /* Resource structure, which will maintain base addresses and IRQs. */
++ void *base; /* Base address of CSPI, used in readl and writel. */
++ int irq; /* CSPI IRQ number. */
++ struct clk *clk; /* CSPI Clock id. */
++ /*!
++ * CSPI input clock SCLK.
++ */
++ unsigned long spi_ipg_clk;
++ /*!
++ * CSPI registers' bit pattern.
++ */
++ struct mxc_spi_unique_def *spi_ver_def;
++};
++
++#define MXC_SPI_BUF_RX(type) \
++void mxc_spi_buf_rx_##type(struct mxc_spi *master_drv_data, u32 val)\
++{\
++ type *rx = master_drv_data->transfer.rx_buf;\
++ *rx++ = (type)val;\
++ master_drv_data->transfer.rx_buf = rx;\
++}
++
++#define MXC_SPI_BUF_TX(type) \
++u32 mxc_spi_buf_tx_##type(struct mxc_spi *master_drv_data)\
++{\
++ u32 val;\
++ const type *tx = master_drv_data->transfer.tx_buf;\
++ val = *tx++;\
++ master_drv_data->transfer.tx_buf = tx;\
++ return val;\
++}
++MXC_SPI_BUF_RX(u8)
++ MXC_SPI_BUF_TX(u8)
++ MXC_SPI_BUF_RX(u16)
++ MXC_SPI_BUF_TX(u16)
++ MXC_SPI_BUF_RX(u32)
++ MXC_SPI_BUF_TX(u32)
++
++static int spi_enable_interrupt(struct mxc_spi *master_data, unsigned int irqs)
++{
++ if (irqs & ~((1 << master_data->spi_ver_def->intr_bit_shift) - 1)) {
++ return -1;
++ }
++
++ writel((irqs | readl(master_data->base + MXC_CSPIINT)),
++ master_data->base + MXC_CSPIINT);
++
++ return 0;
++}
++
++static int spi_disable_interrupt(struct mxc_spi *master_data, unsigned int irqs)
++{
++ if (irqs & ~((1 << master_data->spi_ver_def->intr_bit_shift) - 1)) {
++ return -1;
++ }
++
++ writel((~irqs & readl(master_data->base + MXC_CSPIINT)),
++ master_data->base + MXC_CSPIINT);
++ return 0;
++}
++
++static unsigned int spi_find_baudrate(struct mxc_spi *master_data,
++ unsigned int baud)
++{
++ unsigned int divisor;
++ unsigned int shift = 0;
++
++ /* Calculate required divisor (rounded) */
++ divisor = (master_data->spi_ipg_clk + baud / 2) / baud;
++ while (divisor >>= 1)
++ shift++;
++ MXC_CSPICTRL_ADJUST_SHIFT(shift);
++ if (shift > MXC_CSPICTRL_MAXDATRATE)
++ shift = MXC_CSPICTRL_MAXDATRATE;
++
++ return (shift << MXC_CSPICTRL_DATASHIFT);
++}
++
++static unsigned int spi_get_rx_data(void *base)
++{
++ return readl(base + MXC_CSPIRXDATA);
++}
++
++static void spi_put_tx_data(void *base, unsigned int val)
++{
++ unsigned int ctrl_reg;
++
++ writel(val, base + MXC_CSPITXDATA);
++
++ ctrl_reg = readl(base + MXC_CSPICTRL);
++
++ ctrl_reg |= MXC_CSPICTRL_XCH;
++
++ writel(ctrl_reg, base + MXC_CSPICTRL);
++
++ return;
++}
++
++void mxc_spi_chipselect(struct spi_device *spi, int is_active)
++{
++ struct mxc_spi *master_drv_data;
++ struct mxc_spi_xfer *ptransfer;
++ struct mxc_spi_unique_def *spi_ver_def;
++ unsigned int ctrl_reg;
++ unsigned int ctrl_mask;
++ unsigned int xfer_len;
++
++ if (is_active == BITBANG_CS_INACTIVE) {
++ /*Need to deselect the slave */
++ return;
++ }
++
++ /* Get the master controller driver data from spi device's master */
++
++ master_drv_data = spi_master_get_devdata(spi->master);
++ spi_ver_def = master_drv_data->spi_ver_def;
++
++ xfer_len = spi->bits_per_word;
++
++ /* Control Register Settings for transfer to this slave */
++
++ ctrl_reg = readl(master_drv_data->base + MXC_CSPICTRL);
++
++ ctrl_mask =
++ (MXC_CSPICTRL_LOWPOL | MXC_CSPICTRL_PHA | MXC_CSPICTRL_HIGHSSPOL |
++ MXC_CSPICTRL_CSMASK << spi_ver_def->cs_shift |
++ MXC_CSPICTRL_DATAMASK << MXC_CSPICTRL_DATASHIFT |
++ spi_ver_def->bc_mask << spi_ver_def->bc_shift);
++ ctrl_reg &= ~ctrl_mask;
++
++ ctrl_reg |=
++ ((spi->chip_select & MXC_CSPICTRL_CSMASK) << spi_ver_def->cs_shift);
++ ctrl_reg |= spi_find_baudrate(master_drv_data, spi->max_speed_hz);
++ ctrl_reg |=
++ (((xfer_len - 1) & spi_ver_def->bc_mask) << spi_ver_def->bc_shift);
++ if (spi->mode & SPI_CPHA)
++ ctrl_reg |= MXC_CSPICTRL_PHA;
++ if (!(spi->mode & SPI_CPOL))
++ ctrl_reg |= MXC_CSPICTRL_LOWPOL;
++ if (spi->mode & SPI_CS_HIGH)
++ ctrl_reg |= MXC_CSPICTRL_HIGHSSPOL;
++
++ writel(ctrl_reg, master_drv_data->base + MXC_CSPICTRL);
++
++ /* Initialize the functions for transfer */
++ ptransfer = &master_drv_data->transfer;
++ if (xfer_len <= 8) {
++ ptransfer->rx_get = mxc_spi_buf_rx_u8;
++ ptransfer->tx_get = mxc_spi_buf_tx_u8;
++ } else if (xfer_len <= 16) {
++ ptransfer->rx_get = mxc_spi_buf_rx_u16;
++ ptransfer->tx_get = mxc_spi_buf_tx_u16;
++ } else if (xfer_len <= 32) {
++ ptransfer->rx_get = mxc_spi_buf_rx_u32;
++ ptransfer->tx_get = mxc_spi_buf_tx_u32;
++ }
++#ifdef CONFIG_SPI_MXC_TEST_LOOPBACK
++ {
++ struct...
[truncated message content] |